diff --git a/pyomo/core/base/enums.py b/pyomo/core/base/enums.py index 35cca4e2ac4..972d6b09117 100644 --- a/pyomo/core/base/enums.py +++ b/pyomo/core/base/enums.py @@ -59,7 +59,7 @@ class SortComponents(enum.Flag, **strictEnum): alphabeticalOrder = alphaOrder alphabetical = alphaOrder # both alpha and decl orders are deterministic, so only must sort indices - deterministic = indices + deterministic = ORDERED_INDICES sortBoth = indices | alphabeticalOrder # Same as True alphabetizeComponentAndIndex = sortBoth diff --git a/pyomo/gdp/tests/jobshop_large_hull.lp b/pyomo/gdp/tests/jobshop_large_hull.lp index 983770880b7..df3833bdee3 100644 --- a/pyomo/gdp/tests/jobshop_large_hull.lp +++ b/pyomo/gdp/tests/jobshop_large_hull.lp @@ -461,89 +461,89 @@ c_e__pyomo_gdp_hull_reformulation_disaggregationConstraints(69)_: -1 _pyomo_gdp_hull_reformulation_relaxedDisjuncts(69)_disaggregatedVars__t(A)_ = 0 -c_e__pyomo_gdp_hull_reformulation_disj_xor(F_G_4)_: -+1 NoClash(F_G_4_0)_binary_indicator_var -+1 NoClash(F_G_4_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_B_3)_: ++1 NoClash(A_B_3_0)_binary_indicator_var ++1 NoClash(A_B_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(E_G_5)_: -+1 NoClash(E_G_5_0)_binary_indicator_var -+1 NoClash(E_G_5_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_B_5)_: ++1 NoClash(A_B_5_0)_binary_indicator_var ++1 NoClash(A_B_5_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(E_G_2)_: -+1 NoClash(E_G_2_0)_binary_indicator_var -+1 NoClash(E_G_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_C_1)_: ++1 NoClash(A_C_1_0)_binary_indicator_var ++1 NoClash(A_C_1_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(E_F_3)_: -+1 NoClash(E_F_3_0)_binary_indicator_var -+1 NoClash(E_F_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_D_3)_: ++1 NoClash(A_D_3_0)_binary_indicator_var ++1 NoClash(A_D_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(D_G_4)_: -+1 NoClash(D_G_4_0)_binary_indicator_var -+1 NoClash(D_G_4_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_E_3)_: ++1 NoClash(A_E_3_0)_binary_indicator_var ++1 NoClash(A_E_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(D_G_2)_: -+1 NoClash(D_G_2_0)_binary_indicator_var -+1 NoClash(D_G_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_E_5)_: ++1 NoClash(A_E_5_0)_binary_indicator_var ++1 NoClash(A_E_5_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(D_F_4)_: -+1 NoClash(D_F_4_0)_binary_indicator_var -+1 NoClash(D_F_4_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_F_1)_: ++1 NoClash(A_F_1_0)_binary_indicator_var ++1 NoClash(A_F_1_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(D_F_3)_: -+1 NoClash(D_F_3_0)_binary_indicator_var -+1 NoClash(D_F_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_F_3)_: ++1 NoClash(A_F_3_0)_binary_indicator_var ++1 NoClash(A_F_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(D_E_3)_: -+1 NoClash(D_E_3_0)_binary_indicator_var -+1 NoClash(D_E_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_G_5)_: ++1 NoClash(A_G_5_0)_binary_indicator_var ++1 NoClash(A_G_5_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(D_E_2)_: -+1 NoClash(D_E_2_0)_binary_indicator_var -+1 NoClash(D_E_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_C_2)_: ++1 NoClash(B_C_2_0)_binary_indicator_var ++1 NoClash(B_C_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(C_G_4)_: -+1 NoClash(C_G_4_0)_binary_indicator_var -+1 NoClash(C_G_4_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_D_2)_: ++1 NoClash(B_D_2_0)_binary_indicator_var ++1 NoClash(B_D_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(C_G_2)_: -+1 NoClash(C_G_2_0)_binary_indicator_var -+1 NoClash(C_G_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_D_3)_: ++1 NoClash(B_D_3_0)_binary_indicator_var ++1 NoClash(B_D_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(C_F_4)_: -+1 NoClash(C_F_4_0)_binary_indicator_var -+1 NoClash(C_F_4_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_E_2)_: ++1 NoClash(B_E_2_0)_binary_indicator_var ++1 NoClash(B_E_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(C_F_1)_: -+1 NoClash(C_F_1_0)_binary_indicator_var -+1 NoClash(C_F_1_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_E_3)_: ++1 NoClash(B_E_3_0)_binary_indicator_var ++1 NoClash(B_E_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(C_E_2)_: -+1 NoClash(C_E_2_0)_binary_indicator_var -+1 NoClash(C_E_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_E_5)_: ++1 NoClash(B_E_5_0)_binary_indicator_var ++1 NoClash(B_E_5_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(C_D_4)_: -+1 NoClash(C_D_4_0)_binary_indicator_var -+1 NoClash(C_D_4_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_F_3)_: ++1 NoClash(B_F_3_0)_binary_indicator_var ++1 NoClash(B_F_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(C_D_2)_: -+1 NoClash(C_D_2_0)_binary_indicator_var -+1 NoClash(C_D_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_G_2)_: ++1 NoClash(B_G_2_0)_binary_indicator_var ++1 NoClash(B_G_2_1)_binary_indicator_var = 1 c_e__pyomo_gdp_hull_reformulation_disj_xor(B_G_5)_: @@ -551,89 +551,89 @@ c_e__pyomo_gdp_hull_reformulation_disj_xor(B_G_5)_: +1 NoClash(B_G_5_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_G_2)_: -+1 NoClash(B_G_2_0)_binary_indicator_var -+1 NoClash(B_G_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(C_D_2)_: ++1 NoClash(C_D_2_0)_binary_indicator_var ++1 NoClash(C_D_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_F_3)_: -+1 NoClash(B_F_3_0)_binary_indicator_var -+1 NoClash(B_F_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(C_D_4)_: ++1 NoClash(C_D_4_0)_binary_indicator_var ++1 NoClash(C_D_4_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_E_5)_: -+1 NoClash(B_E_5_0)_binary_indicator_var -+1 NoClash(B_E_5_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(C_E_2)_: ++1 NoClash(C_E_2_0)_binary_indicator_var ++1 NoClash(C_E_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_E_3)_: -+1 NoClash(B_E_3_0)_binary_indicator_var -+1 NoClash(B_E_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(C_F_1)_: ++1 NoClash(C_F_1_0)_binary_indicator_var ++1 NoClash(C_F_1_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_E_2)_: -+1 NoClash(B_E_2_0)_binary_indicator_var -+1 NoClash(B_E_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(C_F_4)_: ++1 NoClash(C_F_4_0)_binary_indicator_var ++1 NoClash(C_F_4_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_D_3)_: -+1 NoClash(B_D_3_0)_binary_indicator_var -+1 NoClash(B_D_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(C_G_2)_: ++1 NoClash(C_G_2_0)_binary_indicator_var ++1 NoClash(C_G_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_D_2)_: -+1 NoClash(B_D_2_0)_binary_indicator_var -+1 NoClash(B_D_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(C_G_4)_: ++1 NoClash(C_G_4_0)_binary_indicator_var ++1 NoClash(C_G_4_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_C_2)_: -+1 NoClash(B_C_2_0)_binary_indicator_var -+1 NoClash(B_C_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(D_E_2)_: ++1 NoClash(D_E_2_0)_binary_indicator_var ++1 NoClash(D_E_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_G_5)_: -+1 NoClash(A_G_5_0)_binary_indicator_var -+1 NoClash(A_G_5_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(D_E_3)_: ++1 NoClash(D_E_3_0)_binary_indicator_var ++1 NoClash(D_E_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_F_3)_: -+1 NoClash(A_F_3_0)_binary_indicator_var -+1 NoClash(A_F_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(D_F_3)_: ++1 NoClash(D_F_3_0)_binary_indicator_var ++1 NoClash(D_F_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_F_1)_: -+1 NoClash(A_F_1_0)_binary_indicator_var -+1 NoClash(A_F_1_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(D_F_4)_: ++1 NoClash(D_F_4_0)_binary_indicator_var ++1 NoClash(D_F_4_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_E_5)_: -+1 NoClash(A_E_5_0)_binary_indicator_var -+1 NoClash(A_E_5_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(D_G_2)_: ++1 NoClash(D_G_2_0)_binary_indicator_var ++1 NoClash(D_G_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_E_3)_: -+1 NoClash(A_E_3_0)_binary_indicator_var -+1 NoClash(A_E_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(D_G_4)_: ++1 NoClash(D_G_4_0)_binary_indicator_var ++1 NoClash(D_G_4_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_D_3)_: -+1 NoClash(A_D_3_0)_binary_indicator_var -+1 NoClash(A_D_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(E_F_3)_: ++1 NoClash(E_F_3_0)_binary_indicator_var ++1 NoClash(E_F_3_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_C_1)_: -+1 NoClash(A_C_1_0)_binary_indicator_var -+1 NoClash(A_C_1_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(E_G_2)_: ++1 NoClash(E_G_2_0)_binary_indicator_var ++1 NoClash(E_G_2_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_B_5)_: -+1 NoClash(A_B_5_0)_binary_indicator_var -+1 NoClash(A_B_5_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(E_G_5)_: ++1 NoClash(E_G_5_0)_binary_indicator_var ++1 NoClash(E_G_5_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_B_3)_: -+1 NoClash(A_B_3_0)_binary_indicator_var -+1 NoClash(A_B_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(F_G_4)_: ++1 NoClash(F_G_4_0)_binary_indicator_var ++1 NoClash(F_G_4_1)_binary_indicator_var = 1 c_u__pyomo_gdp_hull_reformulation_relaxedDisjuncts(0)_transformedConstraints(c_0_ub)_: @@ -1901,145 +1901,145 @@ bounds 0 <= _pyomo_gdp_hull_reformulation_relaxedDisjuncts(69)_disaggregatedVars__t(B)_ <= 92 0 <= _pyomo_gdp_hull_reformulation_relaxedDisjuncts(68)_disaggregatedVars__t(A)_ <= 92 0 <= _pyomo_gdp_hull_reformulation_relaxedDisjuncts(69)_disaggregatedVars__t(A)_ <= 92 - 0 <= NoClash(F_G_4_0)_binary_indicator_var <= 1 - 0 <= NoClash(F_G_4_1)_binary_indicator_var <= 1 - 0 <= NoClash(E_G_5_0)_binary_indicator_var <= 1 - 0 <= NoClash(E_G_5_1)_binary_indicator_var <= 1 - 0 <= NoClash(E_G_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(E_G_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(E_F_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(E_F_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(D_G_4_0)_binary_indicator_var <= 1 - 0 <= NoClash(D_G_4_1)_binary_indicator_var <= 1 - 0 <= NoClash(D_G_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(D_G_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(D_F_4_0)_binary_indicator_var <= 1 - 0 <= NoClash(D_F_4_1)_binary_indicator_var <= 1 - 0 <= NoClash(D_F_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(D_F_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(D_E_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(D_E_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(D_E_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(D_E_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(C_G_4_0)_binary_indicator_var <= 1 - 0 <= NoClash(C_G_4_1)_binary_indicator_var <= 1 - 0 <= NoClash(C_G_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(C_G_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(C_F_4_0)_binary_indicator_var <= 1 - 0 <= NoClash(C_F_4_1)_binary_indicator_var <= 1 - 0 <= NoClash(C_F_1_0)_binary_indicator_var <= 1 - 0 <= NoClash(C_F_1_1)_binary_indicator_var <= 1 - 0 <= NoClash(C_E_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(C_E_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(C_D_4_0)_binary_indicator_var <= 1 - 0 <= NoClash(C_D_4_1)_binary_indicator_var <= 1 - 0 <= NoClash(C_D_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(C_D_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_G_5_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_G_5_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_G_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_G_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_F_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_F_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_E_5_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_E_5_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_E_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_E_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_E_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_E_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_D_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_D_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_D_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_D_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(B_C_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_C_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_G_5_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_G_5_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_F_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_F_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_F_1_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_F_1_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_E_5_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_E_5_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_E_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_E_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_D_3_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_D_3_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_C_1_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_C_1_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_B_5_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_B_5_1)_binary_indicator_var <= 1 0 <= NoClash(A_B_3_0)_binary_indicator_var <= 1 0 <= NoClash(A_B_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_B_5_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_B_5_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_C_1_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_C_1_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_D_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_D_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_E_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_E_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_E_5_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_E_5_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_F_1_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_F_1_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_F_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_F_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_G_5_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_G_5_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_C_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_C_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_D_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_D_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_D_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_D_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_E_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_E_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_E_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_E_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_E_5_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_E_5_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_F_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_F_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_G_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_G_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_G_5_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_G_5_1)_binary_indicator_var <= 1 + 0 <= NoClash(C_D_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(C_D_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(C_D_4_0)_binary_indicator_var <= 1 + 0 <= NoClash(C_D_4_1)_binary_indicator_var <= 1 + 0 <= NoClash(C_E_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(C_E_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(C_F_1_0)_binary_indicator_var <= 1 + 0 <= NoClash(C_F_1_1)_binary_indicator_var <= 1 + 0 <= NoClash(C_F_4_0)_binary_indicator_var <= 1 + 0 <= NoClash(C_F_4_1)_binary_indicator_var <= 1 + 0 <= NoClash(C_G_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(C_G_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(C_G_4_0)_binary_indicator_var <= 1 + 0 <= NoClash(C_G_4_1)_binary_indicator_var <= 1 + 0 <= NoClash(D_E_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(D_E_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(D_E_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(D_E_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(D_F_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(D_F_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(D_F_4_0)_binary_indicator_var <= 1 + 0 <= NoClash(D_F_4_1)_binary_indicator_var <= 1 + 0 <= NoClash(D_G_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(D_G_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(D_G_4_0)_binary_indicator_var <= 1 + 0 <= NoClash(D_G_4_1)_binary_indicator_var <= 1 + 0 <= NoClash(E_F_3_0)_binary_indicator_var <= 1 + 0 <= NoClash(E_F_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(E_G_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(E_G_2_1)_binary_indicator_var <= 1 + 0 <= NoClash(E_G_5_0)_binary_indicator_var <= 1 + 0 <= NoClash(E_G_5_1)_binary_indicator_var <= 1 + 0 <= NoClash(F_G_4_0)_binary_indicator_var <= 1 + 0 <= NoClash(F_G_4_1)_binary_indicator_var <= 1 binary - NoClash(F_G_4_0)_binary_indicator_var - NoClash(F_G_4_1)_binary_indicator_var - NoClash(E_G_5_0)_binary_indicator_var - NoClash(E_G_5_1)_binary_indicator_var - NoClash(E_G_2_0)_binary_indicator_var - NoClash(E_G_2_1)_binary_indicator_var - NoClash(E_F_3_0)_binary_indicator_var - NoClash(E_F_3_1)_binary_indicator_var - NoClash(D_G_4_0)_binary_indicator_var - NoClash(D_G_4_1)_binary_indicator_var - NoClash(D_G_2_0)_binary_indicator_var - NoClash(D_G_2_1)_binary_indicator_var - NoClash(D_F_4_0)_binary_indicator_var - NoClash(D_F_4_1)_binary_indicator_var - NoClash(D_F_3_0)_binary_indicator_var - NoClash(D_F_3_1)_binary_indicator_var - NoClash(D_E_3_0)_binary_indicator_var - NoClash(D_E_3_1)_binary_indicator_var - NoClash(D_E_2_0)_binary_indicator_var - NoClash(D_E_2_1)_binary_indicator_var - NoClash(C_G_4_0)_binary_indicator_var - NoClash(C_G_4_1)_binary_indicator_var - NoClash(C_G_2_0)_binary_indicator_var - NoClash(C_G_2_1)_binary_indicator_var - NoClash(C_F_4_0)_binary_indicator_var - NoClash(C_F_4_1)_binary_indicator_var - NoClash(C_F_1_0)_binary_indicator_var - NoClash(C_F_1_1)_binary_indicator_var - NoClash(C_E_2_0)_binary_indicator_var - NoClash(C_E_2_1)_binary_indicator_var - NoClash(C_D_4_0)_binary_indicator_var - NoClash(C_D_4_1)_binary_indicator_var - NoClash(C_D_2_0)_binary_indicator_var - NoClash(C_D_2_1)_binary_indicator_var - NoClash(B_G_5_0)_binary_indicator_var - NoClash(B_G_5_1)_binary_indicator_var - NoClash(B_G_2_0)_binary_indicator_var - NoClash(B_G_2_1)_binary_indicator_var - NoClash(B_F_3_0)_binary_indicator_var - NoClash(B_F_3_1)_binary_indicator_var - NoClash(B_E_5_0)_binary_indicator_var - NoClash(B_E_5_1)_binary_indicator_var - NoClash(B_E_3_0)_binary_indicator_var - NoClash(B_E_3_1)_binary_indicator_var - NoClash(B_E_2_0)_binary_indicator_var - NoClash(B_E_2_1)_binary_indicator_var - NoClash(B_D_3_0)_binary_indicator_var - NoClash(B_D_3_1)_binary_indicator_var - NoClash(B_D_2_0)_binary_indicator_var - NoClash(B_D_2_1)_binary_indicator_var - NoClash(B_C_2_0)_binary_indicator_var - NoClash(B_C_2_1)_binary_indicator_var - NoClash(A_G_5_0)_binary_indicator_var - NoClash(A_G_5_1)_binary_indicator_var - NoClash(A_F_3_0)_binary_indicator_var - NoClash(A_F_3_1)_binary_indicator_var - NoClash(A_F_1_0)_binary_indicator_var - NoClash(A_F_1_1)_binary_indicator_var - NoClash(A_E_5_0)_binary_indicator_var - NoClash(A_E_5_1)_binary_indicator_var - NoClash(A_E_3_0)_binary_indicator_var - NoClash(A_E_3_1)_binary_indicator_var - NoClash(A_D_3_0)_binary_indicator_var - NoClash(A_D_3_1)_binary_indicator_var - NoClash(A_C_1_0)_binary_indicator_var - NoClash(A_C_1_1)_binary_indicator_var - NoClash(A_B_5_0)_binary_indicator_var - NoClash(A_B_5_1)_binary_indicator_var NoClash(A_B_3_0)_binary_indicator_var NoClash(A_B_3_1)_binary_indicator_var + NoClash(A_B_5_0)_binary_indicator_var + NoClash(A_B_5_1)_binary_indicator_var + NoClash(A_C_1_0)_binary_indicator_var + NoClash(A_C_1_1)_binary_indicator_var + NoClash(A_D_3_0)_binary_indicator_var + NoClash(A_D_3_1)_binary_indicator_var + NoClash(A_E_3_0)_binary_indicator_var + NoClash(A_E_3_1)_binary_indicator_var + NoClash(A_E_5_0)_binary_indicator_var + NoClash(A_E_5_1)_binary_indicator_var + NoClash(A_F_1_0)_binary_indicator_var + NoClash(A_F_1_1)_binary_indicator_var + NoClash(A_F_3_0)_binary_indicator_var + NoClash(A_F_3_1)_binary_indicator_var + NoClash(A_G_5_0)_binary_indicator_var + NoClash(A_G_5_1)_binary_indicator_var + NoClash(B_C_2_0)_binary_indicator_var + NoClash(B_C_2_1)_binary_indicator_var + NoClash(B_D_2_0)_binary_indicator_var + NoClash(B_D_2_1)_binary_indicator_var + NoClash(B_D_3_0)_binary_indicator_var + NoClash(B_D_3_1)_binary_indicator_var + NoClash(B_E_2_0)_binary_indicator_var + NoClash(B_E_2_1)_binary_indicator_var + NoClash(B_E_3_0)_binary_indicator_var + NoClash(B_E_3_1)_binary_indicator_var + NoClash(B_E_5_0)_binary_indicator_var + NoClash(B_E_5_1)_binary_indicator_var + NoClash(B_F_3_0)_binary_indicator_var + NoClash(B_F_3_1)_binary_indicator_var + NoClash(B_G_2_0)_binary_indicator_var + NoClash(B_G_2_1)_binary_indicator_var + NoClash(B_G_5_0)_binary_indicator_var + NoClash(B_G_5_1)_binary_indicator_var + NoClash(C_D_2_0)_binary_indicator_var + NoClash(C_D_2_1)_binary_indicator_var + NoClash(C_D_4_0)_binary_indicator_var + NoClash(C_D_4_1)_binary_indicator_var + NoClash(C_E_2_0)_binary_indicator_var + NoClash(C_E_2_1)_binary_indicator_var + NoClash(C_F_1_0)_binary_indicator_var + NoClash(C_F_1_1)_binary_indicator_var + NoClash(C_F_4_0)_binary_indicator_var + NoClash(C_F_4_1)_binary_indicator_var + NoClash(C_G_2_0)_binary_indicator_var + NoClash(C_G_2_1)_binary_indicator_var + NoClash(C_G_4_0)_binary_indicator_var + NoClash(C_G_4_1)_binary_indicator_var + NoClash(D_E_2_0)_binary_indicator_var + NoClash(D_E_2_1)_binary_indicator_var + NoClash(D_E_3_0)_binary_indicator_var + NoClash(D_E_3_1)_binary_indicator_var + NoClash(D_F_3_0)_binary_indicator_var + NoClash(D_F_3_1)_binary_indicator_var + NoClash(D_F_4_0)_binary_indicator_var + NoClash(D_F_4_1)_binary_indicator_var + NoClash(D_G_2_0)_binary_indicator_var + NoClash(D_G_2_1)_binary_indicator_var + NoClash(D_G_4_0)_binary_indicator_var + NoClash(D_G_4_1)_binary_indicator_var + NoClash(E_F_3_0)_binary_indicator_var + NoClash(E_F_3_1)_binary_indicator_var + NoClash(E_G_2_0)_binary_indicator_var + NoClash(E_G_2_1)_binary_indicator_var + NoClash(E_G_5_0)_binary_indicator_var + NoClash(E_G_5_1)_binary_indicator_var + NoClash(F_G_4_0)_binary_indicator_var + NoClash(F_G_4_1)_binary_indicator_var end diff --git a/pyomo/gdp/tests/jobshop_small_hull.lp b/pyomo/gdp/tests/jobshop_small_hull.lp index 95434e3122f..c07b9cd048e 100644 --- a/pyomo/gdp/tests/jobshop_small_hull.lp +++ b/pyomo/gdp/tests/jobshop_small_hull.lp @@ -57,9 +57,9 @@ c_e__pyomo_gdp_hull_reformulation_disaggregationConstraints(5)_: -1 _pyomo_gdp_hull_reformulation_relaxedDisjuncts(5)_disaggregatedVars__t(A)_ = 0 -c_e__pyomo_gdp_hull_reformulation_disj_xor(B_C_2)_: -+1 NoClash(B_C_2_0)_binary_indicator_var -+1 NoClash(B_C_2_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(A_B_3)_: ++1 NoClash(A_B_3_0)_binary_indicator_var ++1 NoClash(A_B_3_1)_binary_indicator_var = 1 c_e__pyomo_gdp_hull_reformulation_disj_xor(A_C_1)_: @@ -67,9 +67,9 @@ c_e__pyomo_gdp_hull_reformulation_disj_xor(A_C_1)_: +1 NoClash(A_C_1_1)_binary_indicator_var = 1 -c_e__pyomo_gdp_hull_reformulation_disj_xor(A_B_3)_: -+1 NoClash(A_B_3_0)_binary_indicator_var -+1 NoClash(A_B_3_1)_binary_indicator_var +c_e__pyomo_gdp_hull_reformulation_disj_xor(B_C_2)_: ++1 NoClash(B_C_2_0)_binary_indicator_var ++1 NoClash(B_C_2_1)_binary_indicator_var = 1 c_u__pyomo_gdp_hull_reformulation_relaxedDisjuncts(0)_transformedConstraints(c_0_ub)_: @@ -184,17 +184,17 @@ bounds 0 <= _pyomo_gdp_hull_reformulation_relaxedDisjuncts(5)_disaggregatedVars__t(B)_ <= 19 0 <= _pyomo_gdp_hull_reformulation_relaxedDisjuncts(4)_disaggregatedVars__t(A)_ <= 19 0 <= _pyomo_gdp_hull_reformulation_relaxedDisjuncts(5)_disaggregatedVars__t(A)_ <= 19 - 0 <= NoClash(B_C_2_0)_binary_indicator_var <= 1 - 0 <= NoClash(B_C_2_1)_binary_indicator_var <= 1 - 0 <= NoClash(A_C_1_0)_binary_indicator_var <= 1 - 0 <= NoClash(A_C_1_1)_binary_indicator_var <= 1 0 <= NoClash(A_B_3_0)_binary_indicator_var <= 1 0 <= NoClash(A_B_3_1)_binary_indicator_var <= 1 + 0 <= NoClash(A_C_1_0)_binary_indicator_var <= 1 + 0 <= NoClash(A_C_1_1)_binary_indicator_var <= 1 + 0 <= NoClash(B_C_2_0)_binary_indicator_var <= 1 + 0 <= NoClash(B_C_2_1)_binary_indicator_var <= 1 binary - NoClash(B_C_2_0)_binary_indicator_var - NoClash(B_C_2_1)_binary_indicator_var - NoClash(A_C_1_0)_binary_indicator_var - NoClash(A_C_1_1)_binary_indicator_var NoClash(A_B_3_0)_binary_indicator_var NoClash(A_B_3_1)_binary_indicator_var + NoClash(A_C_1_0)_binary_indicator_var + NoClash(A_C_1_1)_binary_indicator_var + NoClash(B_C_2_0)_binary_indicator_var + NoClash(B_C_2_1)_binary_indicator_var end diff --git a/pyomo/repn/linear.py b/pyomo/repn/linear.py index f8f87795e7c..59bc0b58d99 100644 --- a/pyomo/repn/linear.py +++ b/pyomo/repn/linear.py @@ -582,14 +582,37 @@ def __init__(self): self[LinearExpression] = self._before_linear self[SumExpression] = self._before_general_expression + @staticmethod + def _record_var(visitor, var): + # We always add all indices to the var_map at once so that + # we can honor deterministic ordering of unordered sets + # (because the user could have iterated over an unordered + # set when constructing an expression, thereby altering the + # order in which we would see the variables) + vm = visitor.var_map + vo = visitor.var_order + l = len(vo) + try: + _iter = var.parent_component().values(visitor.sorter) + except AttributeError: + # Note that this only works for the AML, as kernel does not + # provide a parent_component() + _iter = (var,) + for v in _iter: + if v.fixed: + continue + vid = id(v) + vm[vid] = v + vo[vid] = l + l += 1 + @staticmethod def _before_var(visitor, child): _id = id(child) if _id not in visitor.var_map: if child.fixed: return False, (_CONSTANT, visitor.check_constant(child.value, child)) - visitor.var_map[_id] = child - visitor.var_order[_id] = len(visitor.var_order) + LinearBeforeChildDispatcher._record_var(visitor, child) ans = visitor.Result() ans.linear[_id] = 1 return False, (_LINEAR, ans) @@ -618,8 +641,7 @@ def _before_monomial(visitor, child): _CONSTANT, arg1 * visitor.check_constant(arg2.value, arg2), ) - visitor.var_map[_id] = arg2 - visitor.var_order[_id] = len(visitor.var_order) + LinearBeforeChildDispatcher._record_var(visitor, arg2) # Trap multiplication by 0 and nan. if not arg1: @@ -643,7 +665,6 @@ def _before_monomial(visitor, child): def _before_linear(visitor, child): var_map = visitor.var_map var_order = visitor.var_order - next_i = len(var_order) ans = visitor.Result() const = 0 linear = ans.linear @@ -675,9 +696,7 @@ def _before_linear(visitor, child): if arg2.fixed: const += arg1 * visitor.check_constant(arg2.value, arg2) continue - var_map[_id] = arg2 - var_order[_id] = next_i - next_i += 1 + LinearBeforeChildDispatcher._record_var(visitor, arg2) linear[_id] = arg1 elif _id in linear: linear[_id] += arg1 @@ -744,11 +763,12 @@ class LinearRepnVisitor(StreamBasedExpressionVisitor): expand_nonlinear_products = False max_exponential_expansion = 1 - def __init__(self, subexpression_cache, var_map, var_order): + def __init__(self, subexpression_cache, var_map, var_order, sorter): super().__init__() self.subexpression_cache = subexpression_cache self.var_map = var_map self.var_order = var_order + self.sorter = sorter self._eval_expr_visitor = _EvaluationVisitor(True) self.evaluate = self._eval_expr_visitor.dfs_postorder_stack diff --git a/pyomo/repn/plugins/lp_writer.py b/pyomo/repn/plugins/lp_writer.py index 23f5c82280a..be718ee696e 100644 --- a/pyomo/repn/plugins/lp_writer.py +++ b/pyomo/repn/plugins/lp_writer.py @@ -310,12 +310,13 @@ def write(self, model): _qp = self.config.allow_quadratic_objective _qc = self.config.allow_quadratic_constraint objective_visitor = (QuadraticRepnVisitor if _qp else LinearRepnVisitor)( - {}, var_map, self.var_order + {}, var_map, self.var_order, sorter ) constraint_visitor = (QuadraticRepnVisitor if _qc else LinearRepnVisitor)( objective_visitor.subexpression_cache if _qp == _qc else {}, var_map, self.var_order, + sorter, ) timer.toc('Initialized column order', level=logging.DEBUG) diff --git a/pyomo/repn/plugins/nl_writer.py b/pyomo/repn/plugins/nl_writer.py index 1941e1e0c64..59a83e61730 100644 --- a/pyomo/repn/plugins/nl_writer.py +++ b/pyomo/repn/plugins/nl_writer.py @@ -529,6 +529,7 @@ def __init__(self, ostream, rowstream, colstream, config): self.external_functions = {} self.used_named_expressions = set() self.var_map = {} + self.sorter = FileDeterminism_to_SortComponents(config.file_determinism) self.visitor = AMPLRepnVisitor( self.template, self.subexpression_cache, @@ -538,6 +539,7 @@ def __init__(self, ostream, rowstream, colstream, config): self.used_named_expressions, self.symbolic_solver_labels, self.config.export_defined_variables, + self.sorter, ) self.next_V_line_id = 0 self.pause_gc = None @@ -815,8 +817,12 @@ def write(self, model): if self.config.export_nonlinear_variables: for v in self.config.export_nonlinear_variables: + # Note that because we have already walked all the + # expressions, we have already "seen" all the variables + # we will see, so we don't need to fill in any VarData + # from IndexedVar containers here. if v.is_indexed(): - _iter = v.values() + _iter = v.values(sorter) else: _iter = (v,) for _v in _iter: @@ -2596,6 +2602,25 @@ def __init__(self): self[LinearExpression] = self._before_linear self[SumExpression] = self._before_general_expression + @staticmethod + def _record_var(visitor, var): + # We always add all indices to the var_map at once so that + # we can honor deterministic ordering of unordered sets + # (because the user could have iterated over an unordered + # set when constructing an expression, thereby altering the + # order in which we would see the variables) + vm = visitor.var_map + try: + _iter = var.parent_component().values(visitor.sorter) + except AttributeError: + # Note that this only works for the AML, as kernel does not + # provide a parent_component() + _iter = (var,) + for v in _iter: + if v.fixed: + continue + vm[id(v)] = v + @staticmethod def _before_string(visitor, child): visitor.encountered_string_arguments = True @@ -2611,7 +2636,7 @@ def _before_var(visitor, child): if _id not in visitor.fixed_vars: visitor.cache_fixed_var(_id, child) return False, (_CONSTANT, visitor.fixed_vars[_id]) - visitor.var_map[_id] = child + _before_child_handlers._record_var(visitor, child) return False, (_MONOMIAL, _id, 1) @staticmethod @@ -2650,7 +2675,7 @@ def _before_monomial(visitor, child): if _id not in visitor.fixed_vars: visitor.cache_fixed_var(_id, arg2) return False, (_CONSTANT, arg1 * visitor.fixed_vars[_id]) - visitor.var_map[_id] = arg2 + _before_child_handlers._record_var(visitor, arg2) return False, (_MONOMIAL, _id, arg1) @staticmethod @@ -2691,7 +2716,7 @@ def _before_linear(visitor, child): visitor.cache_fixed_var(_id, arg2) const += arg1 * visitor.fixed_vars[_id] continue - var_map[_id] = arg2 + _before_child_handlers._record_var(visitor, arg2) linear[_id] = arg1 elif _id in linear: linear[_id] += arg1 @@ -2739,6 +2764,7 @@ def __init__( used_named_expressions, symbolic_solver_labels, use_named_exprs, + sorter, ): super().__init__() self.template = template @@ -2754,6 +2780,7 @@ def __init__( self.fixed_vars = {} self._eval_expr_visitor = _EvaluationVisitor(True) self.evaluate = self._eval_expr_visitor.dfs_postorder_stack + self.sorter = sorter def check_constant(self, ans, obj): if ans.__class__ not in native_numeric_types: diff --git a/pyomo/repn/plugins/standard_form.py b/pyomo/repn/plugins/standard_form.py index 8440c1ab92d..c72661daaf0 100644 --- a/pyomo/repn/plugins/standard_form.py +++ b/pyomo/repn/plugins/standard_form.py @@ -265,7 +265,7 @@ def write(self, model): initialize_var_map_from_column_order(model, self.config, var_map) var_order = {_id: i for i, _id in enumerate(var_map)} - visitor = LinearRepnVisitor({}, var_map, var_order) + visitor = LinearRepnVisitor({}, var_map, var_order, sorter) timer.toc('Initialized column order', level=logging.DEBUG) diff --git a/pyomo/repn/tests/ampl/test_nlv2.py b/pyomo/repn/tests/ampl/test_nlv2.py index 7e47de24f29..f0bc5262183 100644 --- a/pyomo/repn/tests/ampl/test_nlv2.py +++ b/pyomo/repn/tests/ampl/test_nlv2.py @@ -69,6 +69,7 @@ def __init__(self, symbolic=False): self.used_named_expressions, self.symbolic_solver_labels, True, + None, ) def __enter__(self): diff --git a/pyomo/repn/tests/cpxlp/test_lpv2.py b/pyomo/repn/tests/cpxlp/test_lpv2.py index fbe4f15fbe9..336939a4d7d 100644 --- a/pyomo/repn/tests/cpxlp/test_lpv2.py +++ b/pyomo/repn/tests/cpxlp/test_lpv2.py @@ -14,22 +14,23 @@ import pyomo.common.unittest as unittest from pyomo.common.log import LoggingIntercept -from pyomo.environ import ConcreteModel, Block, Constraint, Var, Objective, Suffix + +import pyomo.environ as pyo from pyomo.repn.plugins.lp_writer import LPWriter class TestLPv2(unittest.TestCase): def test_warn_export_suffixes(self): - m = ConcreteModel() - m.x = Var() - m.obj = Objective(expr=m.x) - m.con = Constraint(expr=m.x >= 2) - m.b = Block() - m.ignored = Suffix(direction=Suffix.IMPORT) - m.duals = Suffix(direction=Suffix.IMPORT_EXPORT) - m.b.duals = Suffix(direction=Suffix.IMPORT_EXPORT) - m.b.scaling = Suffix(direction=Suffix.EXPORT) + m = pyo.ConcreteModel() + m.x = pyo.Var() + m.obj = pyo.Objective(expr=m.x) + m.con = pyo.Constraint(expr=m.x >= 2) + m.b = pyo.Block() + m.ignored = pyo.Suffix(direction=pyo.Suffix.IMPORT) + m.duals = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT) + m.b.duals = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT) + m.b.scaling = pyo.Suffix(direction=pyo.Suffix.EXPORT) # Empty suffixes are ignored writer = LPWriter() @@ -73,3 +74,68 @@ def test_warn_export_suffixes(self): LP writer cannot export suffixes to LP files. Skipping. """, ) + + def test_deterministic_unordered_sets(self): + ref = """\\* Source Pyomo model name=unknown *\\ + +min +o: ++1 x(a) ++1 x(aaaaa) ++1 x(ooo) ++1 x(z) + +s.t. + +c_l_c(a)_: ++1 x(a) +>= 1 + +c_l_c(aaaaa)_: ++1 x(aaaaa) +>= 5 + +c_l_c(ooo)_: ++1 x(ooo) +>= 3 + +c_l_c(z)_: ++1 x(z) +>= 1 + +bounds + -inf <= x(a) <= +inf + -inf <= x(aaaaa) <= +inf + -inf <= x(ooo) <= +inf + -inf <= x(z) <= +inf +end +""" + set_init = ['a', 'z', 'ooo', 'aaaaa'] + + m = pyo.ConcreteModel() + m.I = pyo.Set(initialize=set_init, ordered=False) + m.x = pyo.Var(m.I) + m.c = pyo.Constraint(m.I, rule=lambda m, i: m.x[i] >= len(i)) + m.o = pyo.Objective(expr=sum(m.x[i] for i in m.I)) + + OUT = StringIO() + with LoggingIntercept() as LOG: + LPWriter().write(m, OUT, symbolic_solver_labels=True) + self.assertEqual(LOG.getvalue(), "") + print(OUT.getvalue()) + self.assertEqual(ref, OUT.getvalue()) + + m = pyo.ConcreteModel() + m.I = pyo.Set() + m.x = pyo.Var(pyo.Any) + m.c = pyo.Constraint(pyo.Any) + for i in set_init: + m.c[i] = m.x[i] >= len(i) + m.o = pyo.Objective(expr=sum(m.x.values())) + + OUT = StringIO() + with LoggingIntercept() as LOG: + LPWriter().write(m, OUT, symbolic_solver_labels=True) + self.assertEqual(LOG.getvalue(), "") + + self.assertEqual(ref, OUT.getvalue()) diff --git a/pyomo/repn/tests/test_linear.py b/pyomo/repn/tests/test_linear.py index faf12a7da09..0eec8a1541c 100644 --- a/pyomo/repn/tests/test_linear.py +++ b/pyomo/repn/tests/test_linear.py @@ -40,9 +40,10 @@ def __init__(self): self.subexpr = {} self.var_map = {} self.var_order = {} + self.sorter = None def __iter__(self): - return iter((self.subexpr, self.var_map, self.var_order)) + return iter((self.subexpr, self.var_map, self.var_order, self.sorter)) def sum_sq(args, fixed, fgh): @@ -576,8 +577,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 0) self.assertEqual(repn.linear, {id(m.x[0]): 1}) @@ -588,8 +591,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 0) self.assertEqual(repn.linear, {id(m.x[0]): 3}) @@ -600,8 +605,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 0) self.assertEqual(repn.linear, {id(m.x[0]): 3, id(m.x[1]): 4}) @@ -612,8 +619,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 0) self.assertEqual(repn.linear, {id(m.x[0]): 3, id(m.x[1]): 6}) @@ -624,8 +633,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 10) self.assertEqual(repn.linear, {id(m.x[0]): 3, id(m.x[1]): 6}) @@ -636,8 +647,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 50) self.assertEqual(repn.linear, {id(m.x[0]): 3, id(m.x[1]): 6}) @@ -648,8 +661,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 0) self.assertStructuredAlmostEqual( @@ -663,8 +678,10 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1]}) - self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1}) + self.assertEqual( + cfg.var_map, {id(m.x[0]): m.x[0], id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]} + ) + self.assertEqual(cfg.var_order, {id(m.x[0]): 0, id(m.x[1]): 1, id(m.x[2]): 2}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 10) self.assertStructuredAlmostEqual( @@ -677,8 +694,8 @@ def test_linear(self): cfg = VisitorConfig() repn = LinearRepnVisitor(*cfg).walk_expression(e) self.assertEqual(cfg.subexpr, {}) - self.assertEqual(cfg.var_map, {id(m.x[1]): m.x[1]}) - self.assertEqual(cfg.var_order, {id(m.x[1]): 0}) + self.assertEqual(cfg.var_map, {id(m.x[1]): m.x[1], id(m.x[2]): m.x[2]}) + self.assertEqual(cfg.var_order, {id(m.x[1]): 0, id(m.x[2]): 1}) self.assertEqual(repn.multiplier, 1) self.assertEqual(repn.constant, 40) self.assertStructuredAlmostEqual(repn.linear, {id(m.x[1]): InvalidNumber(nan)}) diff --git a/pyomo/repn/tests/test_quadratic.py b/pyomo/repn/tests/test_quadratic.py index b034099de98..605c859464a 100644 --- a/pyomo/repn/tests/test_quadratic.py +++ b/pyomo/repn/tests/test_quadratic.py @@ -29,9 +29,10 @@ def __init__(self): self.subexpr = {} self.var_map = {} self.var_order = {} + self.sorter = None def __iter__(self): - return iter((self.subexpr, self.var_map, self.var_order)) + return iter((self.subexpr, self.var_map, self.var_order, self.sorter)) class TestQuadratic(unittest.TestCase): diff --git a/pyomo/repn/tests/test_util.py b/pyomo/repn/tests/test_util.py index 4d9b0ac8811..47cc6b1a63a 100644 --- a/pyomo/repn/tests/test_util.py +++ b/pyomo/repn/tests/test_util.py @@ -379,7 +379,7 @@ def test_FileDeterminism_to_SortComponents(self): ) self.assertEqual( FileDeterminism_to_SortComponents(FileDeterminism.ORDERED), - SortComponents.unsorted, + SortComponents.deterministic, ) self.assertEqual( FileDeterminism_to_SortComponents(FileDeterminism.SORT_INDICES), @@ -480,7 +480,7 @@ class MockConfig(object): MockConfig.file_determinism = FileDeterminism.ORDERED self.assertEqual( list(initialize_var_map_from_column_order(m, MockConfig, {}).values()), - [m.b.y[7], m.b.y[6], m.y[3], m.y[2], m.c.y[4], m.x], + [m.b.y[7], m.b.y[6], m.y[3], m.y[2], m.c.y[4], m.x, m.c.y[5]], ) MockConfig.file_determinism = FileDeterminism.SORT_INDICES self.assertEqual( @@ -499,7 +499,7 @@ class MockConfig(object): MockConfig.file_determinism = FileDeterminism.ORDERED self.assertEqual( list(initialize_var_map_from_column_order(m, MockConfig, {}).values()), - [m.b.y[7], m.b.y[6], m.y[3], m.y[2], m.c.y[4], m.x], + [m.b.y[7], m.b.y[6], m.y[3], m.y[2], m.c.y[4], m.x, m.c.y[5]], ) # verify no side effects self.assertEqual(MockConfig.column_order, ref) diff --git a/pyomo/repn/util.py b/pyomo/repn/util.py index ecb8ed998d9..b65aa9427d5 100644 --- a/pyomo/repn/util.py +++ b/pyomo/repn/util.py @@ -17,7 +17,7 @@ import operator import sys -from pyomo.common.collections import Sequence, ComponentMap +from pyomo.common.collections import Sequence, ComponentMap, ComponentSet from pyomo.common.deprecation import deprecation_warning from pyomo.common.errors import DeveloperError, InvalidValueError from pyomo.common.numeric_types import ( @@ -544,12 +544,13 @@ def categorize_valid_components( def FileDeterminism_to_SortComponents(file_determinism): - sorter = SortComponents.unsorted + if file_determinism >= FileDeterminism.SORT_SYMBOLS: + return SortComponents.ALPHABETICAL | SortComponents.SORTED_INDICES if file_determinism >= FileDeterminism.SORT_INDICES: - sorter = sorter | SortComponents.indices - if file_determinism >= FileDeterminism.SORT_SYMBOLS: - sorter = sorter | SortComponents.alphabetical - return sorter + return SortComponents.SORTED_INDICES + if file_determinism >= FileDeterminism.ORDERED: + return SortComponents.ORDERED_INDICES + return SortComponents.UNSORTED def initialize_var_map_from_column_order(model, config, var_map): @@ -581,13 +582,33 @@ def initialize_var_map_from_column_order(model, config, var_map): if column_order is not None: # Note that Vars that appear twice (e.g., through a # Reference) will be sorted with the FIRST occurrence. + fill_in = ComponentSet() for var in column_order: if var.is_indexed(): for _v in var.values(sorter): if not _v.fixed: var_map[id(_v)] = _v elif not var.fixed: + pc = var.parent_component() + if pc is not var and pc not in fill_in: + # For any VarData in an IndexedVar, remember the + # IndexedVar so that after all the VarData that the + # user has specified in the column ordering have + # been processed (and added to the var_map) we can + # go back and fill in any missing VarData from that + # IndexedVar. This is needed because later when + # walking expressions we assume that any VarData + # that is not in the var_map will be the first + # VarData from its Var container (indexed or scalar). + fill_in.add(pc) var_map[id(var)] = var + # Note that ComponentSet iteration is deterministic, and + # re-inserting _v into the var_map will not change the ordering + # for any pre-existing variables + for pc in fill_in: + for _v in pc.values(sorter): + if not _v.fixed: + var_map[id(_v)] = _v return var_map diff --git a/pyomo/solvers/tests/piecewise_linear/indexed.lp b/pyomo/solvers/tests/piecewise_linear/indexed.lp index 32e9a0161fc..e73fb8331bd 100644 --- a/pyomo/solvers/tests/piecewise_linear/indexed.lp +++ b/pyomo/solvers/tests/piecewise_linear/indexed.lp @@ -25,11 +25,11 @@ c_e_linearized_constraint(0_1)_LOG_constraint2_: +0.49663531783502585 linearized_constraint(0_1)_LOG_lambda(2) +0.3836621854632263 linearized_constraint(0_1)_LOG_lambda(3) -0.7511436155469337 linearized_constraint(0_1)_LOG_lambda(4) ++1.0 linearized_constraint(0_1)_LOG_lambda(5) -0.8511436155469337 linearized_constraint(0_1)_LOG_lambda(6) +0.18366218546322624 linearized_constraint(0_1)_LOG_lambda(7) +0.1966353178350258 linearized_constraint(0_1)_LOG_lambda(8) -1.0390715290764525 linearized_constraint(0_1)_LOG_lambda(9) -+1.0 linearized_constraint(0_1)_LOG_lambda(5) = 0 c_e_linearized_constraint(0_1)_LOG_constraint3_: @@ -37,11 +37,11 @@ c_e_linearized_constraint(0_1)_LOG_constraint3_: +1 linearized_constraint(0_1)_LOG_lambda(2) +1 linearized_constraint(0_1)_LOG_lambda(3) +1 linearized_constraint(0_1)_LOG_lambda(4) ++1 linearized_constraint(0_1)_LOG_lambda(5) +1 linearized_constraint(0_1)_LOG_lambda(6) +1 linearized_constraint(0_1)_LOG_lambda(7) +1 linearized_constraint(0_1)_LOG_lambda(8) +1 linearized_constraint(0_1)_LOG_lambda(9) -+1 linearized_constraint(0_1)_LOG_lambda(5) = 1 c_u_linearized_constraint(0_1)_LOG_constraint4(1)_: @@ -54,8 +54,8 @@ c_u_linearized_constraint(0_1)_LOG_constraint4(1)_: c_u_linearized_constraint(0_1)_LOG_constraint4(2)_: +1 linearized_constraint(0_1)_LOG_lambda(4) -+1 linearized_constraint(0_1)_LOG_lambda(6) +1 linearized_constraint(0_1)_LOG_lambda(5) ++1 linearized_constraint(0_1)_LOG_lambda(6) -1 linearized_constraint(0_1)_LOG_bin_y(2) <= 0 @@ -83,8 +83,8 @@ c_u_linearized_constraint(0_1)_LOG_constraint5(2)_: c_u_linearized_constraint(0_1)_LOG_constraint5(3)_: +1 linearized_constraint(0_1)_LOG_lambda(1) -+1 linearized_constraint(0_1)_LOG_lambda(9) +1 linearized_constraint(0_1)_LOG_lambda(5) ++1 linearized_constraint(0_1)_LOG_lambda(9) +1 linearized_constraint(0_1)_LOG_bin_y(3) <= 1 @@ -106,11 +106,11 @@ c_e_linearized_constraint(8_3)_LOG_constraint2_: +0.49663531783502585 linearized_constraint(8_3)_LOG_lambda(2) +0.3836621854632263 linearized_constraint(8_3)_LOG_lambda(3) -0.7511436155469337 linearized_constraint(8_3)_LOG_lambda(4) ++1.0 linearized_constraint(8_3)_LOG_lambda(5) -0.8511436155469337 linearized_constraint(8_3)_LOG_lambda(6) +0.18366218546322624 linearized_constraint(8_3)_LOG_lambda(7) +0.1966353178350258 linearized_constraint(8_3)_LOG_lambda(8) -1.0390715290764525 linearized_constraint(8_3)_LOG_lambda(9) -+1.0 linearized_constraint(8_3)_LOG_lambda(5) = 0 c_e_linearized_constraint(8_3)_LOG_constraint3_: @@ -118,11 +118,11 @@ c_e_linearized_constraint(8_3)_LOG_constraint3_: +1 linearized_constraint(8_3)_LOG_lambda(2) +1 linearized_constraint(8_3)_LOG_lambda(3) +1 linearized_constraint(8_3)_LOG_lambda(4) ++1 linearized_constraint(8_3)_LOG_lambda(5) +1 linearized_constraint(8_3)_LOG_lambda(6) +1 linearized_constraint(8_3)_LOG_lambda(7) +1 linearized_constraint(8_3)_LOG_lambda(8) +1 linearized_constraint(8_3)_LOG_lambda(9) -+1 linearized_constraint(8_3)_LOG_lambda(5) = 1 c_u_linearized_constraint(8_3)_LOG_constraint4(1)_: @@ -135,8 +135,8 @@ c_u_linearized_constraint(8_3)_LOG_constraint4(1)_: c_u_linearized_constraint(8_3)_LOG_constraint4(2)_: +1 linearized_constraint(8_3)_LOG_lambda(4) -+1 linearized_constraint(8_3)_LOG_lambda(6) +1 linearized_constraint(8_3)_LOG_lambda(5) ++1 linearized_constraint(8_3)_LOG_lambda(6) -1 linearized_constraint(8_3)_LOG_bin_y(2) <= 0 @@ -164,8 +164,8 @@ c_u_linearized_constraint(8_3)_LOG_constraint5(2)_: c_u_linearized_constraint(8_3)_LOG_constraint5(3)_: +1 linearized_constraint(8_3)_LOG_lambda(1) -+1 linearized_constraint(8_3)_LOG_lambda(9) +1 linearized_constraint(8_3)_LOG_lambda(5) ++1 linearized_constraint(8_3)_LOG_lambda(9) +1 linearized_constraint(8_3)_LOG_bin_y(3) <= 1 @@ -173,28 +173,28 @@ bounds -inf <= Z(0_1) <= +inf -inf <= Z(8_3) <= +inf -2 <= X(0_1) <= 2 + -2 <= X(8_3) <= 2 0 <= linearized_constraint(0_1)_LOG_lambda(1) <= +inf 0 <= linearized_constraint(0_1)_LOG_lambda(2) <= +inf 0 <= linearized_constraint(0_1)_LOG_lambda(3) <= +inf 0 <= linearized_constraint(0_1)_LOG_lambda(4) <= +inf + 0 <= linearized_constraint(0_1)_LOG_lambda(5) <= +inf 0 <= linearized_constraint(0_1)_LOG_lambda(6) <= +inf 0 <= linearized_constraint(0_1)_LOG_lambda(7) <= +inf 0 <= linearized_constraint(0_1)_LOG_lambda(8) <= +inf 0 <= linearized_constraint(0_1)_LOG_lambda(9) <= +inf - 0 <= linearized_constraint(0_1)_LOG_lambda(5) <= +inf 0 <= linearized_constraint(0_1)_LOG_bin_y(1) <= 1 0 <= linearized_constraint(0_1)_LOG_bin_y(2) <= 1 0 <= linearized_constraint(0_1)_LOG_bin_y(3) <= 1 - -2 <= X(8_3) <= 2 0 <= linearized_constraint(8_3)_LOG_lambda(1) <= +inf 0 <= linearized_constraint(8_3)_LOG_lambda(2) <= +inf 0 <= linearized_constraint(8_3)_LOG_lambda(3) <= +inf 0 <= linearized_constraint(8_3)_LOG_lambda(4) <= +inf + 0 <= linearized_constraint(8_3)_LOG_lambda(5) <= +inf 0 <= linearized_constraint(8_3)_LOG_lambda(6) <= +inf 0 <= linearized_constraint(8_3)_LOG_lambda(7) <= +inf 0 <= linearized_constraint(8_3)_LOG_lambda(8) <= +inf 0 <= linearized_constraint(8_3)_LOG_lambda(9) <= +inf - 0 <= linearized_constraint(8_3)_LOG_lambda(5) <= +inf 0 <= linearized_constraint(8_3)_LOG_bin_y(1) <= 1 0 <= linearized_constraint(8_3)_LOG_bin_y(2) <= 1 0 <= linearized_constraint(8_3)_LOG_bin_y(3) <= 1 diff --git a/pyomo/solvers/tests/piecewise_linear/step.lp b/pyomo/solvers/tests/piecewise_linear/step.lp index 7ecd9e7e34e..68574f9658e 100644 --- a/pyomo/solvers/tests/piecewise_linear/step.lp +++ b/pyomo/solvers/tests/piecewise_linear/step.lp @@ -64,10 +64,10 @@ bounds -inf <= Z <= +inf 0 <= X <= 3 -inf <= con_INC_delta(1) <= 1 - -inf <= con_INC_delta(3) <= +inf - 0 <= con_INC_delta(5) <= +inf -inf <= con_INC_delta(2) <= +inf + -inf <= con_INC_delta(3) <= +inf -inf <= con_INC_delta(4) <= +inf + 0 <= con_INC_delta(5) <= +inf 0 <= con_INC_bin_y(1) <= 1 0 <= con_INC_bin_y(2) <= 1 0 <= con_INC_bin_y(3) <= 1