@@ -20,6 +20,7 @@ pub struct Solver {
2020 // Solved and unsolved vars are separate to reduce overhead of many solved variables.
2121 solved_vars : IndexMap < Var , f64 > ,
2222 unsolved_vars : IndexSet < Var > ,
23+ back_substitute_stack : Vec < ConstraintId > ,
2324 inconsistent_constraints : IndexSet < ConstraintId > ,
2425 invalid_rounding : IndexSet < Var > ,
2526}
@@ -85,18 +86,24 @@ impl Solver {
8586 . insert ( id) ;
8687 }
8788 self . constraints . insert ( id, expr) ;
88- self . try_back_substitute ( id) ;
89+ // Use explicit stack in heap-allocated vector to avoid stack overflow.
90+ self . back_substitute_stack . push ( id) ;
91+ while !self . back_substitute_stack . is_empty ( ) {
92+ self . try_back_substitute ( ) ;
93+ }
8994 id
9095 }
9196
9297 // Tries to back substitute using the given [`ConstraintId`].
93- pub fn try_back_substitute ( & mut self , constraint_id : ConstraintId ) {
98+ pub fn try_back_substitute ( & mut self ) {
9499 // If coefficient length is not 1, do nothing.
95- if let Some ( constraint) = self . constraints . get_mut ( & constraint_id) {
100+ if let Some ( id) = self . back_substitute_stack . pop ( )
101+ && let Some ( constraint) = self . constraints . get_mut ( & id)
102+ {
96103 constraint. simplify ( & self . solved_vars ) ;
97104 if constraint. coeffs . is_empty ( ) && !relative_eq ! ( constraint. constant, 0. ) {
98- self . inconsistent_constraints . insert ( constraint_id ) ;
99- self . constraints . swap_remove ( & constraint_id ) ;
105+ self . inconsistent_constraints . insert ( id ) ;
106+ self . constraints . swap_remove ( & id ) ;
100107 return ;
101108 }
102109 if constraint. coeffs . len ( ) != 1 {
@@ -108,7 +115,7 @@ impl Solver {
108115 let val = -constraint. constant / coeff;
109116 if let Some ( old_val) = self . solved_vars . get ( & var) {
110117 if relative_ne ! ( * old_val, val, epsilon = EPSILON ) {
111- self . inconsistent_constraints . insert ( constraint_id ) ;
118+ self . inconsistent_constraints . insert ( id ) ;
112119 }
113120 } else {
114121 let rounded_val = round ( val) ;
@@ -117,7 +124,7 @@ impl Solver {
117124 }
118125 self . solve_var ( var, rounded_val) ;
119126 }
120- self . constraints . swap_remove ( & constraint_id ) ;
127+ self . constraints . swap_remove ( & id ) ;
121128 for constraint in self
122129 . var_to_constraints
123130 . get ( & var)
@@ -126,7 +133,7 @@ impl Solver {
126133 . copied ( )
127134 . collect_vec ( )
128135 {
129- self . try_back_substitute ( constraint) ;
136+ self . back_substitute_stack . push ( constraint) ;
130137 }
131138 }
132139 }
0 commit comments