1- //! Direct quadratic encoding of OptimalLinearArrangement<SimpleGraph> .
1+ //! Tournament comparisons encode the vertices between each edge's endpoints .
22use crate :: models:: algebraic:: QUBO ;
33use crate :: models:: graph:: OptimalLinearArrangement ;
4- use crate :: rules:: qubo_helpers:: { decode_rows , ObjectiveEncoding , QuboBuilder } ;
4+ use crate :: rules:: qubo_helpers:: { pair_index , tournament_ranks , ObjectiveEncoding , QuboBuilder } ;
55use crate :: rules:: { ExtractionResult , ReduceTo , ReductionError , ReductionResult } ;
66use crate :: topology:: { Graph , SimpleGraph } ;
77use crate :: types:: Min ;
@@ -20,10 +20,7 @@ impl ReductionResult for ReductionOptimalLinearArrangementToQUBO {
2020 }
2121 fn extract_solution ( & self , bits : & Vec < bool > ) -> ExtractionResult < Vec < usize > > {
2222 self . encoding . validate ( bits) ?;
23- decode_rows (
24- bits,
25- std:: iter:: repeat_n ( self . num_vertices , self . num_vertices ) ,
26- )
23+ tournament_ranks ( self . num_vertices , bits)
2724 }
2825}
2926
@@ -40,26 +37,45 @@ impl crate::rules::AggregateReductionResult for ReductionOptimalLinearArrangemen
4037}
4138
4239#[ crate :: reduction( transform = {
43- exact { num_vars = "num_vertices^ 2" } ,
44- upper_bound { num_quadratic_terms = "num_vertices^2 * (num_vertices^2 - 1) / 2" } ,
40+ exact { num_vars = "num_vertices * (num_vertices - 1) / 2" } ,
41+ upper_bound { num_quadratic_terms = "num_vertices * (num_vertices - 1) * (num_vertices - 2 ) / 2" } ,
4542} ) ]
4643impl ReduceTo < QUBO < i64 > > for OptimalLinearArrangement < SimpleGraph > {
4744 type Result = ReductionOptimalLinearArrangementToQUBO ;
4845 fn reduce_to ( & self ) -> Result < Self :: Result , ReductionError > {
4946 type Builder = QuboBuilder < OptimalLinearArrangement < SimpleGraph > , QUBO < i64 > > ;
5047 let n = self . num_vertices ( ) ;
51- let mut q = Builder :: new ( Builder :: dimension ( n, n) ?) ;
48+ let mut q = Builder :: new ( Builder :: dimension ( n, n. saturating_sub ( 1 ) ) ? / 2 ) ;
49+ let edges =
50+ <Self as ReduceTo < QUBO < i64 > > >:: exact_i64 ( self . num_edges ( ) , "counting graph edges" ) ?;
51+ let span = <Self as ReduceTo < QUBO < i64 > > >:: exact_i64 (
52+ n. saturating_sub ( 1 ) ,
53+ "bounding rank distance" ,
54+ ) ?;
55+ let high = edges. checked_mul ( span) . ok_or_else ( Builder :: overflow) ?;
56+ let penalty = high. checked_add ( 1 ) . ok_or_else ( Builder :: overflow) ?;
57+ q. add_constant ( i128:: from ( edges) ) ?;
5258 for ( u, v) in self . graph ( ) . edges ( ) {
53- for p in 0 ..n {
54- for s in 0 ..n {
55- q . add ( u * n + p , v * n + s , p . abs_diff ( s ) as i128 ) ? ;
59+ for w in 0 ..n {
60+ if w == u || w == v {
61+ continue ;
5662 }
63+ let a = pair_index ( n, u. min ( w) , u. max ( w) ) ;
64+ let b = pair_index ( n, v. min ( w) , v. max ( w) ) ;
65+ let ca = i128:: from ( u > w) ;
66+ let cb = i128:: from ( v > w) ;
67+ let sa = 1 - 2 * ca;
68+ let sb = 1 - 2 * cb;
69+ // XOR of the two comparisons identifies a vertex strictly between u and v.
70+ q. add_constant ( ca + cb - 2 * ca * cb) ?;
71+ q. add ( a, a, sa * ( 1 - 2 * cb) ) ?;
72+ q. add ( b, b, sb * ( 1 - 2 * ca) ) ?;
73+ q. add ( a, b, -2 * sa * sb) ?;
5774 }
5875 }
59- let ( penalty, low, high) = q. penalty ( ) ?;
60- q. assignment ( n, n, true , penalty) ?;
76+ q. tournament ( n, & [ ] , penalty) ?;
6177 Ok ( ReductionOptimalLinearArrangementToQUBO {
62- encoding : q. optimization ( low , high) ?,
78+ encoding : q. optimization ( 0 , high) ?,
6379 num_vertices : n,
6480 } )
6581 }
@@ -74,9 +90,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::Ru
7490 OptimalLinearArrangement :: new( SimpleGraph :: new( 3 , vec![ ( 0 , 1 ) , ( 1 , 2 ) ] ) ) ,
7591 crate :: export:: SolutionPair {
7692 source_config: serde_json:: json!( [ 0 , 1 , 2 ] ) ,
77- target_config: serde_json:: json!( [
78- true , false , false , false , true , false , false , false , true
79- ] ) ,
93+ target_config: serde_json:: json!( [ true , true , true ] ) ,
8094 } ,
8195 )
8296 } ,
0 commit comments