From 7079a36203feca4b06a8fac46bbe1c3f857d0060 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Fri, 27 Oct 2023 08:53:38 -0500 Subject: [PATCH] Lazy: Rename fields --- miplearn/collectors/basic.py | 8 +++--- miplearn/components/lazy/mem.py | 38 ++++++++++++++-------------- miplearn/problems/tsp.py | 8 +++--- miplearn/solvers/gurobi.py | 26 +++++++++---------- tests/components/lazy/test_mem.py | 4 +-- tests/fixtures/tsp-n20-00000.h5 | Bin 107009 -> 37243 bytes tests/fixtures/tsp-n20-00000.mps.gz | Bin 6238 -> 6238 bytes tests/fixtures/tsp-n20-00000.pkl.gz | Bin 1145 -> 1145 bytes tests/fixtures/tsp-n20-00001.h5 | Bin 29948 -> 30392 bytes tests/fixtures/tsp-n20-00001.mps.gz | Bin 5371 -> 5371 bytes tests/fixtures/tsp-n20-00001.pkl.gz | Bin 1134 -> 1134 bytes tests/fixtures/tsp-n20-00002.h5 | Bin 30868 -> 31312 bytes tests/fixtures/tsp-n20-00002.mps.gz | Bin 5653 -> 5653 bytes tests/fixtures/tsp-n20-00002.pkl.gz | Bin 1134 -> 1134 bytes 14 files changed, 42 insertions(+), 42 deletions(-) diff --git a/miplearn/collectors/basic.py b/miplearn/collectors/basic.py index d3d7f77..0bec085 100644 --- a/miplearn/collectors/basic.py +++ b/miplearn/collectors/basic.py @@ -58,11 +58,11 @@ class BasicCollector: # Add lazy constraints to model if ( - hasattr(model, "fix_violations") - and model.fix_violations is not None + hasattr(model, "lazy_enforce") + and model.lazy_enforce is not None ): - model.fix_violations(model, model.violations_, "aot") - h5.put_scalar("mip_constr_violations", repr(model.violations_)) + model.lazy_enforce(model, model.lazy_constrs_, "aot") + h5.put_scalar("mip_lazy", repr(model.lazy_constrs_)) # Save MPS file model.write(mps_filename) diff --git a/miplearn/components/lazy/mem.py b/miplearn/components/lazy/mem.py index 7f25b4d..eb3fc63 100644 --- a/miplearn/components/lazy/mem.py +++ b/miplearn/components/lazy/mem.py @@ -24,30 +24,30 @@ class MemorizingLazyConstrComponent: def __init__(self, clf: Any, extractor: FeaturesExtractor) -> None: self.clf = clf self.extractor = extractor - self.violations_: List[Hashable] = [] + self.constrs_: List[Hashable] = [] self.n_features_: int = 0 self.n_targets_: int = 0 def fit(self, train_h5: List[str]) -> None: logger.info("Reading training data...") n_samples = len(train_h5) - x, y, violations, n_features = [], [], [], None - violation_to_idx: Dict[Hashable, int] = {} + x, y, constrs, n_features = [], [], [], None + constr_to_idx: Dict[Hashable, int] = {} for h5_filename in train_h5: with H5File(h5_filename, "r") as h5: # Store lazy constraints - sample_violations_str = h5.get_scalar("mip_constr_violations") - assert sample_violations_str is not None - assert isinstance(sample_violations_str, str) - sample_violations = eval(sample_violations_str) - assert isinstance(sample_violations, list) + sample_constrs_str = h5.get_scalar("mip_lazy") + assert sample_constrs_str is not None + assert isinstance(sample_constrs_str, str) + sample_constrs = eval(sample_constrs_str) + assert isinstance(sample_constrs, list) y_sample = [] - for v in sample_violations: - if v not in violation_to_idx: - violation_to_idx[v] = len(violation_to_idx) - violations.append(v) - y_sample.append(violation_to_idx[v]) + for c in sample_constrs: + if c not in constr_to_idx: + constr_to_idx[c] = len(constr_to_idx) + constrs.append(c) + y_sample.append(constr_to_idx[c]) y.append(y_sample) # Extract features @@ -62,8 +62,8 @@ class MemorizingLazyConstrComponent: logger.info("Constructing matrices...") assert n_features is not None self.n_features_ = n_features - self.violations_ = violations - self.n_targets_ = len(violation_to_idx) + self.constrs_ = constrs + self.n_targets_ = len(constr_to_idx) x_np = np.vstack(x) assert x_np.shape == (n_samples, n_features) y_np = MultiLabelBinarizer().fit_transform(y) @@ -82,8 +82,8 @@ class MemorizingLazyConstrComponent: model: GurobiModel, stats: Dict[str, Any], ) -> None: - assert self.violations_ is not None - if model.fix_violations is None: + assert self.constrs_ is not None + if model.lazy_enforce is None: return # Read features @@ -99,7 +99,7 @@ class MemorizingLazyConstrComponent: y = y.reshape(-1) # Enforce constraints - violations = [self.violations_[i] for (i, yi) in enumerate(y) if yi > 0.5] + violations = [self.constrs_[i] for (i, yi) in enumerate(y) if yi > 0.5] logger.info(f"Enforcing {len(violations)} constraints ahead-of-time...") - model.fix_violations(model, violations, "aot") + model.lazy_enforce(model, violations, "aot") stats["Lazy Constraints: AOT"] = len(violations) diff --git a/miplearn/problems/tsp.py b/miplearn/problems/tsp.py index a23b9bc..c11b057 100644 --- a/miplearn/problems/tsp.py +++ b/miplearn/problems/tsp.py @@ -142,7 +142,7 @@ def build_tsp_model(data: Union[str, TravelingSalesmanData]) -> GurobiModel: name="eq_degree", ) - def find_violations(model: GurobiModel) -> List[Any]: + def lazy_separate(model: GurobiModel) -> List[Any]: violations = [] x = model.inner.cbGetSolution(model.inner._x) selected_edges = [e for e in model.inner._edges if x[e] > 0.5] @@ -159,7 +159,7 @@ def build_tsp_model(data: Union[str, TravelingSalesmanData]) -> GurobiModel: violations.append(cut_edges) return violations - def fix_violations(model: GurobiModel, violations: List[Any], where: str) -> None: + def lazy_enforce(model: GurobiModel, violations: List[Any], where: str) -> None: for violation in violations: constr = quicksum(model.inner._x[e[0], e[1]] for e in violation) >= 2 if where == "cb": @@ -172,6 +172,6 @@ def build_tsp_model(data: Union[str, TravelingSalesmanData]) -> GurobiModel: return GurobiModel( model, - find_violations=find_violations, - fix_violations=fix_violations, + lazy_separate=lazy_separate, + lazy_enforce=lazy_enforce, ) diff --git a/miplearn/solvers/gurobi.py b/miplearn/solvers/gurobi.py index 9d7cf5c..90e1a20 100644 --- a/miplearn/solvers/gurobi.py +++ b/miplearn/solvers/gurobi.py @@ -21,13 +21,13 @@ class GurobiModel(AbstractModel): def __init__( self, inner: gp.Model, - find_violations: Optional[Callable] = None, - fix_violations: Optional[Callable] = None, + lazy_separate: Optional[Callable] = None, + lazy_enforce: Optional[Callable] = None, ) -> None: - self.fix_violations = fix_violations - self.find_violations = find_violations + self.lazy_separate = lazy_separate + self.lazy_enforce = lazy_enforce self.inner = inner - self.violations_: Optional[List[Any]] = None + self.lazy_constrs_: Optional[List[Any]] = None def add_constrs( self, @@ -125,18 +125,18 @@ class GurobiModel(AbstractModel): stats["Fixed variables"] = n_fixed def optimize(self) -> None: - self.violations_ = [] + self.lazy_constrs_ = [] def callback(m: gp.Model, where: int) -> None: - assert self.find_violations is not None - assert self.violations_ is not None - assert self.fix_violations is not None + assert self.lazy_separate is not None + assert self.lazy_constrs_ is not None + assert self.lazy_enforce is not None if where == GRB.Callback.MIPSOL: - violations = self.find_violations(self) - self.violations_.extend(violations) - self.fix_violations(self, violations, "cb") + violations = self.lazy_separate(self) + self.lazy_constrs_.extend(violations) + self.lazy_enforce(self, violations, "cb") - if self.fix_violations is not None: + if self.lazy_enforce is not None: self.inner.Params.lazyConstraints = 1 self.inner.optimize(callback) else: diff --git a/tests/components/lazy/test_mem.py b/tests/components/lazy/test_mem.py index 9f7618c..54147a4 100644 --- a/tests/components/lazy/test_mem.py +++ b/tests/components/lazy/test_mem.py @@ -33,10 +33,10 @@ def test_mem_component( ] # Should store violations - assert comp.violations_ is not None + assert comp.constrs_ is not None assert comp.n_features_ == 190 assert comp.n_targets_ == 22 - assert len(comp.violations_) == 22 + assert len(comp.constrs_) == 22 # Call before-mip stats: Dict[str, Any] = {} diff --git a/tests/fixtures/tsp-n20-00000.h5 b/tests/fixtures/tsp-n20-00000.h5 index 57d49901ae2367668f6e7e08485479d7f8b015cb..d6bf57ab7a095d3ac12551f8effc97d8c2848d21 100644 GIT binary patch delta 2934 zcmchZeN0nV6u|Ghwjfx6^4Y!?e2Cc)qyiNvh$2v+48;zbg&?l9r3hGgZC^o=w#;k` zk*K5IOcGrd(9O)vbuKlUnBYfrPMwQWjBfJ_5);VO4P&C28r}QoLrmKKxtrW~-n-{_ z&OPV6ckg}M&V{|$4+rI|dOd(`*_;4*w=SJut5MfM!hL$Vxr^?++!6@^1^|p@$PM8f zZ}l{p@MFg@BWsiDqWRe!O+Xo%#=<=h#&MfR8y%9G#Gkh|?Fx+eCLqK#d#``Hqq4rf z0_=(BrpM+3@PrNuU`7mlDWGo#K8jFrI`$ga8y%JokpizkcB)a0QiavxK#}XvDWO-O zk^R|?#L|QBR@P~>fJqyIm^U-L_P544+}Iv;F>ZYn$mO0e@Vo-W`2Gza3!5X^27Fhd z^05GOX~hfCt*~)?r!{UONW@yP3}uxRqQ)36{@teN?SV0$Rtzy5J-YiiupXUElA&J{ zmFTb7qd8N$q_br@jT#8)l)yYX;+FI&e__)>xLAB?;*0NtR6evCs05`Gqh=MNn4*jA$777GK^fQxJrFF*g} zYT)2~CzI&pMkik03!=XyftcWvU0r8~u-#aC1f3My@(_k^j8+oHu69cc(Vdg6$W|!P zL^7UMx<*aZ^=vhF5`{!TVP19vk&~ZQPTI|c)=rwt6h+$6C{AQLOFwAH%gJ3IscW;F z4K0L;?CNwB(J*0c>!I3B1`9o8H&aUpkkW3^IEk62{NwZlj?0h2Ck`p0cW9%%oBKDN4p{@ri*&UEJS}R z&PCcK!?>;e=EuP;P;HhM-#2nGF9g!45JBZK)>%!#qJ|J;>ryYi?tF7`a3o5@het~+ zpK)3!@Bgf?Qd3lq7F2C&MB)`~=vZ{}L7jwQ6#@*JIFe-=cCsqP5T{850 zGe)301^Cdg2Q!Gad}zv^atHzT0K7&k$JZowEC#@$g6n!I@6AZuy}8lMM?o(k`d`X5Y)|Bz{AjAqt69z$2WqBgfhP%r&5QurpCn`ly z;$bTmQ8e%{2x+fsh7Y+?to!BQp&%5UBNVBSTYU|G)%*a3pyD~IwOu+Ef|7I8(?iCD zAk_XETjV1CC^qFClLelH?>>!q_IQaZLoBi&sB5Z z{j6~#y{Wg1`_}^oqOBxpprIdyR`52_7Are5WzcsS^=J`>T4k?aVMp98aA0J{#OkHVn6GT%ic!G#WW{}s#vt%odR`n$mLGK zrqCB|B2OUUa}oK?D03%eCZzl@?~R$2q~|m{iZjq-+FL^=itbB>jwMLZCxwGq9$TER NsSm~st)LHs{{RRV#cTio delta 2801 zcmcgtYgAKL8ol=>BzO&vAYdR8QgqRX5CXLjg%$#c5ha5dr^TWWLQo`uT77J(M0g%Oah86RVXX)7Zt3Ugn9u-44qxohQ|+`adA zzVGbwxKqawb0_1#l34gS4B?N6Xd$Tm{4UquNfS~LzNmY(%K74ImAx-P5eU;F9=P)O zB2vH7lCDH6)$(2<1_o>z7q}x#%hV`ZdSf(s9(oTA3QK!RLN+!HfyK33o{lAM+O!7R z;zMq=b(FWV~JleiB`l&*`Lofw`i zy`0RPzMJYx$$o}qgZV64TiEzIp4&|r3sJ|gh0?j49*rbQPv0`0V#tPM+MLmH(@F$3)Fgs zBKK&Z$J3j>u=VT}aNje|{V?X62eh|6Ef6Zj{_;VnS3MZ@>Z0f81dUsCuTy2&ro9mu z9hy0Ein40jn+uBRLJ+gq1!y@<=!L+)J)ve5;e*Y}AG5bZ01L%}ZJJhw1@R#C1x zn_nCz5{iUjAcf~ESeIX@QVUX-^W!xIDuFzCIX^ctL>&35NXm~-+02jShYQ0+Yo%r2 zeI9@5R#d*DK&8m$D>X&=g{%1yeC>`>eXdfW#*hM)KA0Z{G~56<3{3ITZR6Zc$p0~? zZHm`Ha}EpV3p6=c9i0K=$RUPpqq&M}sk7>E@eL*u&6lSho)w9i7UXoznA(mAnf4|yhu_5S)5BB*i0LYFxO2p3t= z-7b@Vb%11HETsBXTuisNu0IFNK25gh@LDJ16Il#CQtXa0qKBYgVoJ6tMfVGxAoyo! zhQ*9sx&MP@Opkqv>{W6IiWe~BR2t43w>4=se%FEzw&tY%lqR+1mk+HUc%vnK`q$0e zblJN{Lk-YG@#M&XoaE4{n$}ge3Q57gE!=`1)5nOi1JA@#J>ZHLitu!*f#%+7$;&-1 zkT-+&2UW_UpROM}bHxi{x6;_>TaJxoGR<3ehIDri@dCaBK)lhXT}BLn-#Sp}0to8! zA>R>O$I=+sz7E*IcU6%D(GC+HpikoWOwGCDs&!DrMG%&vh=Dz)03*>XI^8MGC_13|FbcaL>sgX4Am;q{225gPp9t$`{9HBQlYMNFu4cvc75- zm4lseR&->iYJ!5WJq2e1MSMT%dwas>0PY~b!J7A*96&7rR+d&79KaF+{HPK9i2^Zy z+>{RGMpO!I+TR!=R z1L{Sh#a&(D6e>*Cp+_y$Zhi+y;C(1#ME8thlVq8QiL~WV^oI!)8sQ^^3xTAppWc78 zz-UvaR4>OaY8-tVM^}t;17Z@T2@Y2^cF7Gkq9_cx?8?<w#`JXJz9CyTA*NS8DS0g_tB)qgE8=VlU^C?K~6b)tc=o zCD;yp3tlt74D8D8D)ZeBLmp}^kwvc{ipka(@*$yp47WM5C@Z5#%K}@=xnd6W{l$u$ zg?F8Gwc(Oe8T02LWzFna`kVGQ$O~y((X?N@4>a6A$^=1FSOf;3n{G=zP!Ram>}+%utm4X#xW!A#ySg( zUgfjmFAZAnez$hm^I+ZQKU|?5`AqRVBkA)y9rbN~59%gsg`XMD^!#~HeAs+rs;a=h zZ9!i1w)z*%hl@*Rm|-ZMK(*u=-kJzcfOcjW87CgBPk6&@!R$H zGB0d+FD3H&qwto~B}d2EcdAc+#cC)Y6ihwzJ7K6T?wR~zeJT6l$GPkWiKW{ZhPw*J zWToKro;#{*lf!$>%Wh&{b%8C`Jm7YMV|I7^SxioVE%x%SI{>5YBInNMgO~62e_ixn zZtLXanY6=2hMJ6bhm}zc<9^+L-{V~-Zup`+>1nqz>L%#E_le;LgXPkrljY2Z?N43g z4Zpove`LG3jrMcuzpnb|Dz3Ioa%zPKhoAeOdenRMe^z9#jxZRENAh6&TOonR=0#wv L(j9Ot%31V3&gFz* diff --git a/tests/fixtures/tsp-n20-00000.mps.gz b/tests/fixtures/tsp-n20-00000.mps.gz index a0debe527d7cdc107df65b910311c39c3f3956cb..4699bf6cedfec2e218135c4ec4d8651ab6748dbb 100644 GIT binary patch delta 16 Xcmca-aL<5UzMF%i^nmq7_HYRRGi(KQ delta 16 Xcmca-aL<5UzMF%CW4F~t_HYRRFir&m diff --git a/tests/fixtures/tsp-n20-00000.pkl.gz b/tests/fixtures/tsp-n20-00000.pkl.gz index d0273ff4d3853813c3ad17a37d40ed2071dba901..f0baeca80039967d0d22d68e94be3472e8e63949 100644 GIT binary patch delta 16 Xcmey#@sopHzMF%i^nmq7_97MlGFSy- delta 16 Xcmey#@sopHzMF%CW4F~t_97MlFFFM8 diff --git a/tests/fixtures/tsp-n20-00001.h5 b/tests/fixtures/tsp-n20-00001.h5 index 469a6ce5bc91fa139f4ea5ad18c270ef85f62bbb..f54f99efb8491d944f390ee446341164ec4bd7c8 100644 GIT binary patch delta 2895 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 Kd$M~wqW=R+)zb$6 delta 2277 zcmcgtiBD5^9DncexSplba<&LOak^5a2UB2xD@Vn`phKvcx|-7Cft|J2D{axlp>ghr znbsefyPRVt%a)NEsWa-9#cdv2@aU8*EE zK@fB!ihPN~j|}3$EXT3Wd50!&0*~VA3(*N+O>IS)$R@BjEsEQ3ozq2pO=-N+C@lju z*;BZ#2knda8b>p(rD1VdEG}MyLZeBY3GA0d4bnmCZi}I{X}&Hd*ieuQJQU#He(wD* zKMpUQ-ozpB$(Lo6VklmWuU1BU4MGZY`9^Ri=M;WLr)~j#=_Q#RDV*6B@J{;HI+28% zp@?m;_opV4L64*&7=kQYgcJzBN zo!gZCK5Uy5*?)fX3SPfgr8| zx`Hg=EgT_c?ms-vQ*E>gIAr7a*yS(8pkA&)?}Huk<%_kXt>5W#kU_0RrBP|Yuw1Ta zbq6SyqN|*2_V_7DWAM0+XvmSX>JlG@lSn zm%b7wF;6O@M9Du>GYLq1kvR?gxcnSz)cxU&#Bno$N==lwV`#mRFak!c2s^Nb5#u+% zNk0ts$VOuIm2agIo2qn-ufgrx!S(8gvhzmHGZW)JtS&C&<`^u{f(rW=o-DD2BiQFn z)-%x)9NmzJDW;MXl~rt_>B^k96ACt~BOKH8vgr+;F-lF~$=WE9`(DL355ZF@hTD67 zOmaqcYxowYh)wF?-hKT}l|EqsjEy3!teOqHw(fW%&wOj>!5TPp#mreHj~ewVv>jNR zZxR`E%C02P#DYI8`~6N5XlB7H?FAQ-KnDx%*yZ|_2bngR=W|977Z-KX{L2Ttg30Aa z4vl_X{4~kgIP2{0=x_2Q@HPa;Gxt^O&@VYU)l)ktp=IXp!2Jb?6$TJ9Zs*sV|&#Sw7UAKuz_=$gxlbWcI;~f2Lpx1k6sk$#a@rcm9V2fZx@(6 z#-ZKgrUQOU(CKkm15P+O)gkcd4Da&vz3GE{^A!|y22)oEe?rV{d1J zLR;A&4o}F9fL%dZu}CdAk|ZSkHVdOD1Sf+sEdD&W5|qnt*9yWcUdUERPuCp|m148? zU}>lXMLBu4~e`M1%$r`;jB?3qTvg$TNsZ<3}7oD9ja`etx7RJ5A8znOs| zVx}^;$3emJ;Vo!dw}4=(;WFrH0ZYPiwQIe=vn}bfdJna6$ik(9*mqseP5~;cLa&3N z@KW>^I1Qh9U?N#~8*m1kC0TGqgCd?)~1`RS{p#e<+84*Z=?k diff --git a/tests/fixtures/tsp-n20-00002.mps.gz b/tests/fixtures/tsp-n20-00002.mps.gz index de15dd3bd620f1b5f0cd22dc43d333d250bfb2b9..6fb3acb06b0b09a51bf53d45237b6a31c5cb5e03 100644 GIT binary patch delta 16 XcmbQLGgXIOzMF%i^nmq7c0MrxDcS^( delta 16 XcmbQLGgXIOzMF%CW4F~tc0MrxCcFe4 diff --git a/tests/fixtures/tsp-n20-00002.pkl.gz b/tests/fixtures/tsp-n20-00002.pkl.gz index 702ebdcac262bfad05b80c4e7381eab1099e6ce2..43dc6a7fee011129bc41ae480a3606d43664a59f 100644 GIT binary patch delta 16 XcmaFI@s5LCzMF%i^nmq7_H-5iF!%*Q delta 16 XcmaFI@s5LCzMF%CW4F~t_H-5iE!qUm