Skip to content

Disable named expressions for MB+LD2 - #71

Merged
Robbybp merged 9 commits into
mainfrom
named-expr-workaround
Jul 18, 2026
Merged

Disable named expressions for MB+LD2#71
Robbybp merged 9 commits into
mainfrom
named-expr-workaround

Conversation

@Robbybp

@Robbybp Robbybp commented Jun 29, 2026

Copy link
Copy Markdown
Owner

There is some odd behavior for the MB+LD2 model-method combination. Here are a few lines of output from analyze_solvetime.py:

EXIT: Optimal Solution Found.
[+   0.08] Solve model
WARNING: Constraints in the reduced-space model are violated
WARNING: Result is not valid!
[+   0.05] Validate result

The first line above is the last line of output from IPOPT: We converge to an optimal solution, but our post-solve constraint evaluation identifies an infeasible solution. What's unusual is that, on further inspection, the constraint violation magnitude is 0.17. This is much too large to be a difference due to scaled/unscaled models, IPOPT's bound relaxation, or any other solver-specific idiosyncrasy. I've found that this behavior only occurs when we use named expressions, so I'm patching our scripts to avoid using named expressions for this model-method combination.

I've looked into this discrepancy a bit and I think this is most likely an NL writer bug. I will open a Pyomo issue once I'm happy with this workaround.

This needs:

  • Comparison of runtime results
  • Comparison of convergence results
  • Controls in place so this doesn't come up again (and we're sure it isn't happening for other model-method combinations)

@Robbybp

Robbybp commented Jun 29, 2026

Copy link
Copy Markdown
Owner Author

Runtime results

These are MB+LD2

With named expressions

Identifier                                                          ncalls   cumtime   percall      %
-----------------------------------------------------------------------------------------------------
root                                                                     1     1.288     1.288  100.0
     ------------------------------------------------------------------------------------------------
     mb-steady-linear-d2                                                 1     1.288     1.288  100.0
                        -----------------------------------------------------------------------------
                        elimination                                      1     1.155     1.155   89.7
                                   ------------------------------------------------------------------
                                   eliminate                            13     0.182     0.014   15.7
                                   eliminate-nodes                      13     0.133     0.010   11.5
                                   get-d1                               14     0.492     0.035   42.6
                                   get-d2                                2     0.107     0.053    9.2
                                   igraph                                1     0.098     0.098    8.5
                                   linear-igraph                         1     0.103     0.103    8.9
                                   subgraph                              1     0.040     0.040    3.4
                                   other                               n/a     0.002       n/a    0.1
                                   ==================================================================
                        solver                                           1     0.084     0.084    6.5
                                   ------------------------------------------------------------------
                                   solve                                 1     0.012     0.012   14.2
                                                  ---------------------------------------------------
                                                  constraint-jac        10     0.000     0.000    3.9
                                                  constraints            9     0.001     0.000    6.5
                                                  intermediate-cb        9     0.000     0.000    0.1
                                                  lagrangian-hess        8     0.002     0.000   14.7
                                                  objective              9     0.000     0.000    0.6
                                                  objective-grad        10     0.000     0.000    1.1
                                                  other                n/a     0.009       n/a   73.1
                                                  ===================================================
                                   other                               n/a     0.072       n/a   85.8
                                   ==================================================================
                        other                                          n/a     0.049       n/a    3.8
                        =============================================================================
     other                                                             n/a     0.000       n/a    0.0
     ================================================================================================
=====================================================================================================

Without named expressions

Identifier                                                          ncalls   cumtime   percall      %
-----------------------------------------------------------------------------------------------------
root                                                                     1     1.296     1.296  100.0
     ------------------------------------------------------------------------------------------------
     mb-steady-linear-d2                                                 1     1.296     1.296  100.0
                        -----------------------------------------------------------------------------
                        elimination                                      1     1.161     1.161   89.6
                                   ------------------------------------------------------------------
                                   eliminate                            13     0.178     0.014   15.4
                                   eliminate-nodes                      13     0.118     0.009   10.2
                                   get-d1                               14     0.490     0.035   42.2
                                   get-d2                                2     0.125     0.062   10.7
                                   igraph                                1     0.100     0.100    8.6
                                   linear-igraph                         1     0.108     0.108    9.3
                                   subgraph                              1     0.041     0.041    3.5
                                   other                               n/a     0.002       n/a    0.1
                                   ==================================================================
                        solver                                           1     0.088     0.088    6.8
                                   ------------------------------------------------------------------
                                   solve                                 1     0.011     0.011   13.0
                                                  ---------------------------------------------------
                                                  constraint-jac        10     0.000     0.000    4.0
                                                  constraints            9     0.001     0.000    7.1
                                                  intermediate-cb        9     0.000     0.000    0.1
                                                  lagrangian-hess        8     0.002     0.000   15.4
                                                  objective              9     0.000     0.000    0.7
                                                  objective-grad        10     0.000     0.000    1.1
                                                  other                n/a     0.008       n/a   71.6
                                                  ===================================================
                                   other                               n/a     0.076       n/a   87.0
                                   ==================================================================
                        other                                          n/a     0.048       n/a    3.7
                        =============================================================================
     other                                                             n/a     0.000       n/a    0.0
     ================================================================================================
=====================================================================================================

No appreciable difference.

@Robbybp

Robbybp commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

Convergence results

All MB results, run on Darwin.

With named expressions for method (main branch)

       model     method  n-success  n-total  percent-success  ave-elim-time  ave-solve-time
0  mb-steady    no-elim         88      121        72.727273       0.000039        1.056338
1  mb-steady         d1         89      121        73.553719       4.647681        1.095656
2  mb-steady       ecd2         89      121        73.553719       4.475969        1.124023
3  mb-steady  linear-d2         88      121        72.727273       5.194716        0.998081
4  mb-steady         d2         96      121        79.338843            NaN        0.918361
5  mb-steady     greedy        105      121        86.776860       1.365976        0.845214
6  mb-steady   matching        101      121        83.471074       2.431153        1.042989

Without named expressions for LD2 (this branch)

       model     method  n-success  n-total  percent-success  ave-elim-time  ave-solve-time
0  mb-steady    no-elim         88      121        72.727273       0.000031        1.002411
1  mb-steady         d1         89      121        73.553719       4.452170        1.033757
2  mb-steady       ecd2         89      121        73.553719       4.469480        0.948522
3  mb-steady  linear-d2         90      121        74.380165       5.077071        0.925272
4  mb-steady         d2         96      121        79.338843            NaN        0.744996
5  mb-steady     greedy        105      121        86.776860       1.353755        0.876362
6  mb-steady   matching        101      121        83.471074       2.430085        0.904619

Without named expressions, we LD2 converges two extra instances.

@Robbybp

Robbybp commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

In summarize_sweep_results.py, we now print a warning when success is True but feasible is False. Other than the MB+LD2 instances, this happens for some pipeline instances with infeasibilities near 1e-5. When I change feastol to 1e-4, This only happens for three instances:

WARNING: pipeline, no-elim: success=True but feasible=False at index 79; infeasibility=0.000100078221294
WARNING: pipeline, ecd2: success=True but feasible=False at index 79; infeasibility=0.000100112039945
WARNING: pipeline, d2: success=True but feasible=False at index 79; infeasibility=0.0001000009942799

I think I'm fine with accepting these instances. These are likely just "acceptable" infeasibilities (to IPOPT) that get exacerbated by unscaling the model.

@Robbybp

Robbybp commented Jul 10, 2026

Copy link
Copy Markdown
Owner Author
WARNING: pipeline, no-elim: success=True but feasible=False at index 79; infeasibility=0.000100078221294
WARNING: pipeline, ecd2: success=True but feasible=False at index 79; infeasibility=0.000100112039945
WARNING: pipeline, d2: success=True but feasible=False at index 79; infeasibility=0.0001000009942799

These infeasibilities seem to be due to bound violations of flow rates. The variables have values around 10000 and the violations are of about 1e-4. This is consistent with IPOPT's default bound relax factor of 1e-8. The solution here is probably to just do a relative tolerance check for our self-reported bound violations.

@Robbybp

Robbybp commented Jul 10, 2026

Copy link
Copy Markdown
Owner Author

This is waiting on a re-run of the convergence results with feastol=1e-5 and the relative tolerance check I just implemented. I have manually verified that the three instances with warnings above pass with the relative tolerance check, but there were several more warnings with feastol=1e-5 that I didn't record. It would be nice if we could revert to feastol=1e-5 and get no warnings.

@Sakshi21299

Copy link
Copy Markdown
Collaborator

Thankyou Robby for debugging this and rerunning the results! The relative tolerance check sounds logical. Looking forward to seeing the results.

Comment thread var_elim/algorithms/validate.py Outdated
vars_violating_bounds.append((var, var.lb, lb_diff))
relative_lb_diff = lb_diff / abs(var.lb) if var.lb != 0 else lb_diff
if lb_diff < - tolerance and relative_lb_diff < - tolerance:
vars_violating_bounds.append((var, var.lb, min(lb_diff, relative_lb_diff)))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the warning message, maybe its worth printing that the infeasibility check failed in the absolute or relative sense.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this function, we only print the vague message "there are variables violating their bounds." I don't think we ever print a variable-specific warning message, so I don't see a good place to distinguish.

@Robbybp

Robbybp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

The other warnings with feastol=1e-5 aren't due to bounds. Here's a representative set of the warnings:

WARNING: pipeline, no-elim: success=True but feasible=False at index 103; infeasibility=6.353730395858292e-05                                                                       [681/9344]
WARNING: pipeline, ecd2: success=True but feasible=False at index 82; infeasibility=2.901628613471985e-05                  
WARNING: pipeline, linear-d2: success=True but feasible=False at index 81; infeasibility=1.3452023267745972e-05           
WARNING: pipeline, d2: success=True but feasible=False at index 112; infeasibility=2.026371657848358e-05                  
WARNING: pipeline, greedy: success=True but feasible=False at index 2; infeasibility=9.983719792217016e-05                                       
WARNING: pipeline, matching: success=True but feasible=False at index 2; infeasibility=9.98677860479802e-05

For no-elim, warnings are due to material balance constraints where we equate two terms of magnitude ~1000. For matching, violations are due to bounds on an eliminated variable (now an inequality constraint) and would likely disappear with a relative tolerance check on this constraint as well.

I'm re-running the results, but I'm leaning towards just setting feastol=1e-4.

@Robbybp

Robbybp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

We still have the following warnings after adding a relative tolerance check for inequality constraints.

WARNING: pipeline, no-elim: success=True but feasible=False at index 103; infeasibility=6.353730395858292e-05                                        
WARNING: pipeline, ecd2: success=True but feasible=False at index 82; infeasibility=2.901628613471985e-05                                                 
WARNING: pipeline, linear-d2: success=True but feasible=False at index 81; infeasibility=1.3452023267745972e-05                                                                
WARNING: pipeline, d2: success=True but feasible=False at index 112; infeasibility=2.026371657848358e-05                                    

@Robbybp

Robbybp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

For no-elim, warnings are due to material balance constraints where we equate two terms of magnitude ~1000

We could probably detect sum expressions in equality constraints with RHS=0 and do a relative tolerance check between the first two terms. I think this would catch these material balance discrepancies, at least.

I'm going to merge this PR as-is, but I may add this check in another PR.

@Robbybp
Robbybp merged commit 5dcaa4c into main Jul 18, 2026
@Robbybp
Robbybp deleted the named-expr-workaround branch July 18, 2026 15:09
@Sakshi21299

Copy link
Copy Markdown
Collaborator

So we don't have any warnings with relative tolerance implemented and setting feastol=1e-4?

@Robbybp

Robbybp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

Yes. All violations are now less than 1e-4 (relative)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants