Here is an AI translation based on Oscar's approach that only takes a few seconds. Does it do what you need?
```python
from __future__ import annotations
from typing import Dict, List, Tuple as _T, Iterable
from dataclasses import dataclass
from sympy import *
eqs=S('''[Eq(v0, v39), Eq(v1, v21), Eq(v2, v160), Eq(v3, 125*v136/1296 + 143*v157/648 + 13*v158/162 + 35*v196/324 + 125*v230/1296 + 7*v67/162 + 5*v96/81 + 155/648), Eq(v4, v46), Eq(v5, v21), Eq(v6, 7*v103/162 + 13*v13/162 + 143*v138/648 + 5*v165/81 + 125*v188/1296 + 35*v56/324 + 145/432), Eq(v7, v21), Eq(v8, 125*v136/1296 + 143*v157/648 + 13*v158/162 + 125*v238/1296 + 35*v64/324 + 7*v67/162 + 13*v70/162 + 5*v96/81 + 103/648), Eq(v9, 125*v107/1296 + 5*v114/81 + 35*v169/324 + 125*v176/1296 + 143*v234/648 + 13*v77/162 + 155/648), Eq(v10, v152), Eq(v11, 5*v150/81 + 35*v182/324 + 125*v23/1296 + 143*v48/648 + 13*v69/162 + 145/432), Eq(v12, Max(11973429987871294032791/15614510052024077690880, v44)), Eq(v13, v9), Eq(v14, 143*v131/648 + 35*v164/324 + 125*v174/1296 + 13*v179/162 + 125*v224/1296 + 155/648), Eq(v15, v97), Eq(v16, Max(22153944431869014019426428453312493667994869174799325454923686985538985161903624297370947248977440887249367238742791250601673384171676607719/32454635176053367993998877873873950990459011341470372284598283919422255066489869933707729610512961907754883836467874521812063002516520960000, v232)), Eq(v17, v87), Eq(v18, v236), Eq(v19, Max(8153526396622056593187661712693/9765476659969457979924424224000, v153)), Eq(v20, v97), Eq(v21, 35*v104/324 + 7*v115/162 + 125*v163/1296 + 125*v190/1296 + 5*v65/81 + 13*v66/162 + 143*v89/648 + 155/648), Eq(v22, Max(7275710867969158635412531309174807/8437371834213611694654702529536000, v180)), Eq(v23, v9), Eq(v24, Max(2614555075632615128064129937148739196765976986107121040972735374362471663685097832269563604123454373834497709933777759023191743438472863355594852611/3252479130413442679612535606086476366411081822411880393493248150349958821111651172916031511388192323765980310338178294488167832084589834141696000000, v229)), Eq(v25, 5*v168/81 + 7*v202/162 + 13*v36/162 + 35*v43/324 + 35*v68/1296 + 143*v7/648 + 125*v78/1296 + 145/432), Eq(v26, Max(3854097996225308316203175283663385/5973659258623237079815529390911488, v231)), Eq(v27, v35), Eq(v28, Max(7082014151066409483273977986654807/8437371834213611694654702529536000, v218)), Eq(v29, v3), Eq(v30, v156), Eq(v31, v32), Eq(v32, 5*v100/81 + 143*v162/648 + 35*v186/324 + 125*v40/1296 + 125*v49/1296 + 13*v52/162 + 13*v59/162 + 103/648), Eq(v33, v9), Eq(v34, v145), Eq(v35, 125*v126/1296 + 13*v173/162 + 125*v181/1296 + 13*v206/162 + 35*v211/324 + 143*v98/648 + 103/648), Eq(v36, v97), Eq(v37, v39), Eq(v38, Max(435458653906733290600307/519997654931407615526400, v106)), Eq(v39, 125*v159/1296 + 13*v19/162 + 125*v74/1296 + 35*v82/324 + 143*v91/648 + 13*v94/162 + 103/648), Eq(v40, Max(226542105817153888727102225905133917442673378023193639810034013/282361652451162721818510415100150396932752441247124690042880000, v25)), Eq(v41, v9), Eq(v42, Max(2394733571844680723947486046892229995824719990932886027/3293635682949831743806860531669548694292913046945792000, v213)), Eq(v43, Max(7275710867969158635412531309174807/8437371834213611694654702529536000, v180)), Eq(v44, 5*v150/81 + 125*v23/1296 + 143*v48/648 + 13*v69/162 + 575/1296), Eq(v45, v147), Eq(v46, 143*v134/648 + 125*v204/1296 + 35*v63/324 + 125*v75/1296 + 13*v86/162 + 103/648), Eq(v47, Max(17774053714151175033989655690633134825729039/24642541563136281050949853769599826662195200, v184)), Eq(v48, v97), Eq(v49, v39), Eq(v50, v46), Eq(v51, v147), Eq(v52, v35), Eq(v53, v151), Eq(v54, Max(279093664883899921882792279729481055727296597875364409018874143/330075542795919385459138332466610996414444404698606408499200000, v201)), Eq(v55, Max(279093664883899921882792279729481055727296597875364409018874143/330075542795919385459138332466610996414444404698606408499200000, v201)), Eq(v56, Max(17162041845107476095157951754621/19530953319938915959848848448000, v84)), Eq(v57, Max(134845448633481464957323497536579332465563743749277/172297325954688833637102978220838496248844582912000, v6)), Eq(v58, v147), Eq(v59, Max(7275710867969158635412531309174807/8437371834213611694654702529536000, v180)), Eq(v60, v183), Eq(v61, v229), Eq(v62, 35*v104/324 + 143*v118/648 + 7*v123/162 + 13*v125/162 + 35*v144/1296 + 125*v163/1296 + 125*v18/1296 + 5*v93/81 + 155/648), Eq(v63, Max(175636969241485433817388790704239855296988799222569480849525214868889482808102263013043142576463500794632154622270708701/294314475806011059781427635267647592615090539835558997573966535841876742686892500252978044232249079792621628328850227200, v160)), Eq(v64, Max(5061423529750895019224713210229530919488626594511426252665941900089074860550587856332801957246398173667897955595061549032234894743025570361086403/6440552733491965702203040804131636369130855093884911670283659703663284794280497372110953487897410542110852099679560979184490756603148186419200000, v183)), Eq(v65, v156), Eq(v66, v152), Eq(v67, v46), Eq(v68, v147), Eq(v69, v87), Eq(v70, Max(17162041845107476095157951754621/19530953319938915959848848448000, v84)), Eq(v71, 125*v141/1296 + 143*v178/648 + 13*v45/162 + 575/1296), Eq(v72, Max(253802678761938692393280149165758641400287017359935136027687/326807468114771668771424091551099996449944955147135057920000, v111)), Eq(v73, v236), Eq(v74, v156), Eq(v75, Max(3854097996225308316203175283663385/5973659258623237079815529390911488, v231)), Eq(v76, Max(7275710867969158635412531309174807/8437371834213611694654702529536000, v180)), Eq(v77, v35), Eq(v78, v183), Eq(v79, Max(8850883678872758268947173651427717/9863131426569152559723668466240000, v189)), Eq(v80, Max(8153526396622056593187661712693/9765476659969457979924424224000, v153)), Eq(v81, v97), Eq(v82, Max(2358584054497148792710148400261053499897881214516493192068924801916534408118507179932080824564044765382257088703238080044388691345123909081442699/3220276366745982851101520402065818184565427546942455835141829851831642397140248686055476743948705271055426049839780489592245378301574093209600000, v21)), Eq(v83, Max(3636449405556959850095431375189982793388139699327/5173750886263588479209023698635022807381206630400, v11)), Eq(v84, 7*v112/162 + 13*v139/162 + 5*v155/81 + 35*v198/1296 + 125*v5/1296 + 143*v60/648 + 575/1296), Eq(v85, Max(11973429987871294032791/15614510052024077690880, v44)), Eq(v86, Max(16191931/22535817, v71)), Eq(v87, 125*v12/1296 + 35*v214/324 + 143*v50/648 + 155/648), Eq(v88, 7*v112/162 + 13*v139/162 + 5*v155/81 + 35*v198/1296 + 35*v205/324 + 125*v5/1296 + 143*v60/648 + 145/432), Eq(v89, v236), Eq(v90, v8), Eq(v91, v152), Eq(v92, Max(8850883678872758268947173651427717/9863131426569152559723668466240000, v189)), Eq(v93, v152), Eq(v94, v46), Eq(v95, Max(8850883678872758268947173651427717/9863131426569152559723668466240000, v189)), Eq(v96, v122), Eq(v97, 35*v108/324 + 125*v175/1296 + 125*v74/1296 + 143*v91/648 + 13*v94/162 + 155/648), Eq(v98, v35), Eq(v99, v152), Eq(v100, v46), Eq(v101, v46), Eq(v102, Max(220238025723283192366108519240454879220580984891661788157350013/282361652451162721818510415100150396932752441247124690042880000, v154)), Eq(v103, v147), Eq(v104, Max(226542105817153888727102225905133917442673378023193639810034013/282361652451162721818510415100150396932752441247124690042880000, v25)), Eq(v105, v14), Eq(v106, 7*v103/162 + 13*v13/162 + 143*v138/648 + 5*v165/81 + 125*v188/1296 + 575/1296), Eq(v107, Max(435458653906733290600307/519997654931407615526400, v106)), Eq(v108, Max(253802678761938692393280149165758641400287017359935136027687/326807468114771668771424091551099996449944955147135057920000, v111)), Eq(v109, v87), Eq(v110, v35), Eq(v111, 5*v109/81 + 143*v194/648 + 125*v20/1296 + 13*v41/162 + 35*v43/324 + 7*v58/162 + 145/432), Eq(v112, v160), Eq(v113, Max(1258342213853621367032641137686368091858037627209580572330220504142983507324061383727708018843022293004047445501873262810166895090483369/1697773340450584222326787919746492518856403606479931590531402171972287877510455635787179828965942765628524996676494796077216101826560000, v3)), Eq(v114, v46), Eq(v115, v46), Eq(v116, Max(8153526396622056593187661712693/9765476659969457979924424224000, v153)), Eq(v117, v152), Eq(v118, v151), Eq(v119, v46), Eq(v120, 125*v105/1296 + 143*v133/648 + 5*v187/81 + 13*v209/162 + 575/1296), Eq(v121, 13*v191/162 + 125*v33/1296 + 143*v34/648 + 5*v51/81 + 575/1296), Eq(v122, 143*v110/648 + 35*v142/324 + 125*v195/1296 + 125*v227/1296 + 13*v80/162 + 103/648), Eq(v123, v156), Eq(v124, Max(2394733571844680723947486046892229995824719990932886027/3293635682949831743806860531669548694292913046945792000, v213)), Eq(v125, v39), Eq(v126, v223), Eq(v127, v151), Eq(v128, v46), Eq(v129, Max(16191931/22535817, v71)), Eq(v130, v35), Eq(v131, v152), Eq(v132, v151), Eq(v133, v9), Eq(v134, v46), Eq(v135, Max(11269204546127/14346413781285, v120)), Eq(v136, v32), Eq(v137, Max(7275710867969158635412531309174807/8437371834213611694654702529536000, v180)), Eq(v138, v3), Eq(v139, v3), Eq(v140, v207), Eq(v141, v221), Eq(v142, Max(2358584054497148792710148400261053499897881214516493192068924801916534408118507179932080824564044765382257088703238080044388691345123909081442699/3220276366745982851101520402065818184565427546942455835141829851831642397140248686055476743948705271055426049839780489592245378301574093209600000, v21)), Eq(v143, Max(226542105817153888727102225905133917442673378023193639810034013/282361652451162721818510415100150396932752441247124690042880000, v25)), Eq(v144, v46), Eq(v145, 5*v100/81 + 125*v137/1296 + 35*v143/324 + 143*v162/648 + 125*v49/1296 + 13*v52/162 + 155/648), Eq(v146, 125*v102/1296 + 143*v131/648 + 125*v174/1296 + 13*v179/162 + 35*v192/324 + 13*v212/162 + 103/648), Eq(v147, 125*v129/1296 + 143*v134/648 + 125*v204/1296 + 35*v26/324 + 155/648), Eq(v148, v156), Eq(v149, Max(279093664883899921882792279729481055727296597875364409018874143/330075542795919385459138332466610996414444404698606408499200000, v201)), Eq(v150, v147), Eq(v151, 7*v115/162 + 125*v167/1296 + 35*v171/324 + 125*v190/1296 + 5*v65/81 + 13*v66/162 + 13*v76/162 + 143*v89/648 + 103/648), Eq(v152, 35*v113/324 + 5*v114/81 + 125*v176/1296 + 13*v200/162 + 143*v234/648 + 125*v57/1296 + 13*v77/162 + 103/648), Eq(v153, 5*v109/81 + 143*v194/648 + 125*v20/1296 + 13*v41/162 + 7*v58/162 + 575/1296), Eq(v154, 143*v1/648 + 7*v161/162 + 5*v2/81 + 35*v22/324 + 125*v29/1296 + 13*v81/162 + 145/432), Eq(v155, v97), Eq(v156, 35*v203/324 + 143*v50/648 + 125*v83/1296 + 13*v85/162 + 103/648), Eq(v157, v8), Eq(v158, v152), Eq(v159, Max(253802678761938692393280149165758641400287017359935136027687/326807468114771668771424091551099996449944955147135057920000, v111)), Eq(v160, 125*v126/1296 + 125*v135/1296 + 13*v206/162 + 35*v47/324 + 143*v98/648 + 155/648), Eq(v161, v147), Eq(v162, v8), Eq(v163, Max(7275710867969158635412531309174807/8437371834213611694654702529536000, v180)), Eq(v164, Max(220238025723283192366108519240454879220580984891661788157350013/282361652451162721818510415100150396932752441247124690042880000, v154)), Eq(v165, v193), Eq(v166, v39), Eq(v167, Max(226542105817153888727102225905133917442673378023193639810034013/282361652451162721818510415100150396932752441247124690042880000, v25)), Eq(v168, v9), Eq(v169, Max(134845448633481464957323497536579332465563743749277/172297325954688833637102978220838496248844582912000, v6)), Eq(v170, v8), Eq(v171, Max(2105200769737816505172382620601987033203554288183000146797721880918236299783478163617023469627750000504871656527720958235556227417449073238133508201/2782318780868529183351713627384866911464529400558281841562540991982539031129174864751931906771681354191888107061570343007700006852560016533094400000, v62)), Eq(v172, v9), Eq(v173, Max(11269204546127/14346413781285, v120)), Eq(v174, v122), Eq(v175, Max(8153526396622056593187661712693/9765476659969457979924424224000, v153)), Eq(v176, v146), Eq(v177, Max(279093664883899921882792279729481055727296597875364409018874143/330075542795919385459138332466610996414444404698606408499200000, v201)), Eq(v178, v160), Eq(v179, v46), Eq(v180, 5*v168/81 + 7*v202/162 + 13*v36/162 + 35*v68/1296 + 143*v7/648 + 125*v78/1296 + 575/1296), Eq(v181, Max(17774053714151175033989655690633134825729039/24642541563136281050949853769599826662195200, v184)), Eq(v182, Max(8153526396622056593187661712693/9765476659969457979924424224000, v153)), Eq(v183, 13*v170/162 + 35*v177/324 + 125*v215/1296 + 7*v217/162 + 5*v237/81 + 35*v4/1296 + 125*v53/1296 + 143*v73/648 + 155/648), Eq(v184, 125*v105/1296 + 143*v133/648 + 5*v187/81 + 13*v209/162 + 35*v38/324 + 145/432), Eq(v185, Max(7839007286424827564645117347/9940275171668787978402662400, v121)), Eq(v186, Max(2105200769737816505172382620601987033203554288183000146797721880918236299783478163617023469627750000504871656527720958235556227417449073238133508201/2782318780868529183351713627384866911464529400558281841562540991982539031129174864751931906771681354191888107061570343007700006852560016533094400000, v62)), Eq(v187, v147), Eq(v188, v145), Eq(v189, 5*v15/81 + 35*v17/1296 + 7*v172/162 + 5*v220/324 + 13*v225/162 + 125*v235/1296 + 143*v61/648 + 575/1296), Eq(v190, v39), Eq(v191, v193), Eq(v192, Max(2045078160365334499396949348874892561929655603986003104366740054193468546098285839528846751540950480006451342487403164371269925361888435218161080201/2782318780868529183351713627384866911464529400558281841562540991982539031129174864751931906771681354191888107061570343007700006852560016533094400000, v216)), Eq(v193, 143*v110/648 + 125*v116/1296 + 125*v227/1296 + 35*v72/324 + 155/648), Eq(v194, v183), Eq(v195, Max(253802678761938692393280149165758641400287017359935136027687/326807468114771668771424091551099996449944955147135057920000, v111)), Eq(v196, Max(540603656426932533425269180020889323149790647994708176949439/653614936229543337542848183102199992899889910294270115840000, v88)), Eq(v197, Max(7839007286424827564645117347/9940275171668787978402662400, v121)), Eq(v198, v147), Eq(v199, Max(8850883678872758268947173651427717/9863131426569152559723668466240000, v189)), Eq(v200, Max(435458653906733290600307/519997654931407615526400, v106)), Eq(v201, 5*v15/81 + 35*v17/1296 + 7*v172/162 + 5*v220/324 + 13*v225/162 + 125*v235/1296 + 143*v61/648 + 35*v79/324 + 145/432), Eq(v202, v87), Eq(v203, Max(33555258956212545159265306236629059868117420803200021272171253837071413093415619201625551702480684238035240126327735818814535013747339/50980804700015500968416644345982125478843256558573011969114731928624900945625419111863289811598969388796638160975604215819955863552000, v208)), Eq(v204, v46), Eq(v205, Max(8850883678872758268947173651427717/9863131426569152559723668466240000, v189)), Eq(v206, v46), Eq(v207, 7*v10/162 + 5*v128/324 + 125*v132/1296 + 143*v140/648 + 35*v148/1296 + 35*v226/324 + 13*v228/162 + 5*v37/81 + 125*v54/1296 + 13*v92/162 + 103/648), Eq(v208, 143*v0/648 + 5*v101/81 + 35*v108/324 + 125*v117/1296 + 125*v175/1296 + 13*v30/162 + 155/648), Eq(v209, v160), Eq(v210, v122), Eq(v211, Max(164303259789428574676434357424189686228606168309404001224495213032351595510640234280468301450122934132127132665995958212872858503/242821238664149429242953838715430791222961708193172782203145156648304855136533203360117025851618319372030931646164857757106176000, v9)), Eq(v212, Max(7082014151066409483273977986654807/8437371834213611694654702529536000, v218)), Eq(v213, 13*v191/162 + 35*v28/324 + 125*v33/1296 + 143*v34/648 + 5*v51/81 + 145/432), Eq(v214, Max(3636449405556959850095431375189982793388139699327/5173750886263588479209023698635022807381206630400, v11)), Eq(v215, Max(8850883678872758268947173651427717/9863131426569152559723668466240000, v189)), Eq(v216, 143*v127/648 + 5*v130/81 + 125*v137/1296 + 35*v143/324 + 13*v166/162 + 7*v219/162 + 125*v90/1296 + 155/648), Eq(v217, v35), Eq(v218, 143*v1/648 + 7*v161/162 + 5*v2/81 + 125*v29/1296 + 13*v81/162 + 575/1296), Eq(v219, v46), Eq(v220, v147), Eq(v221, 35*v124/324 + 125*v197/1296 + 125*v233/1296 + 143*v27/648 + 155/648), Eq(v222, Max(11269204546127/14346413781285, v120)), Eq(v223, 35*v16/324 + 13*v185/162 + 125*v233/1296 + 143*v27/648 + 125*v42/1296 + 103/648), Eq(v224, Max(7082014151066409483273977986654807/8437371834213611694654702529536000, v218)), Eq(v225, v183), Eq(v226, Max(2614555075632615128064129937148739196765976986107121040972735374362471663685097832269563604123454373834497709933777759023191743438472863355594852611/3252479130413442679612535606086476366411081822411880393493248150349958821111651172916031511388192323765980310338178294488167832084589834141696000000, v229)), Eq(v227, v46), Eq(v228, v236), Eq(v229, 7*v10/162 + 5*v128/324 + 125*v132/1296 + 143*v140/648 + 35*v148/1296 + 35*v149/324 + 125*v199/1296 + 13*v228/162 + 5*v37/81 + 155/648), Eq(v230, Max(17162041845107476095157951754621/19530953319938915959848848448000, v84)), Eq(v231, 125*v141/1296 + 143*v178/648 + 35*v222/324 + 13*v45/162 + 145/432), Eq(v232, 5*v119/81 + 35*v164/324 + 13*v210/162 + 125*v224/1296 + 143*v31/648 + 125*v99/1296 + 155/648), Eq(v233, v46), Eq(v234, v152), Eq(v235, v21), Eq(v236, 13*v170/162 + 7*v217/162 + 5*v237/81 + 35*v24/324 + 35*v4/1296 + 125*v53/1296 + 125*v55/1296 + 143*v73/648 + 13*v95/162 + 103/648), Eq(v237, v39), Eq(v238, Max(540603656426932533425269180020889323149790647994708176949439/653614936229543337542848183102199992899889910294270115840000, v88))]''')
import sympy as sp
from sympy import Eq, Expr, Max, Tuple, symbols, linsolve, Matrix, S, Symbol
@dataclass(frozen=True)
class MaxSpec:
m: Symbol # the new epigraph variable (m_i)
args: _T[Expr, ...] # the Max arguments (already xreplaced in eqs2)
raw: Max # original Max expression (before replace)
def build_max_epigraph(eqs: Iterable[Eq]):
eqs = list(eqs)
maxes = Tuple(*eqs).atoms(Max)
syms_max = symbols(f'm0:{len(maxes)}', real=True)
rep_m = dict(zip(maxes, syms_max))
eqs2 = [e.xreplace(rep_m) for e in eqs] # linear (affine) now
# Record each Max’s argument list after replacement
max_specs: List[MaxSpec] = []
for raw, m in zip(maxes, syms_max):
args = Tuple(*[a.xreplace(rep_m) for a in raw.args])
max_specs.append(MaxSpec(m=m, args=args, raw=raw))
# Symbols present
syms_all = Tuple(*eqs2).free_symbols
return eqs2, max_specs, syms_max, syms_all, rep_m
def lower_bound_propagation(eqs2: List[Eq], max_specs: List[MaxSpec]) -> Dict[Symbol, sRational]:
# Start with bounds from Max(const, x, …) where a pure numeric const is present
L: Dict[Symbol, Rational] = {}
def upd(v, val):
if v not in L or val > L[v]:
L[v] = val
for ms in max_specs:
consts = [a for a in ms.args if a.is_Number]
if consts:
c = max(consts) # “epigraph” lower bound
upd(ms.m, nsimplify(c))
# Push through obvious affine equalities v = sum(a_i * w_i) + b with a_i >= 0
# (Very conservative: only pick up clearly nonnegative coefficients.)
# Repeat to a fixpoint (few iterations usually suffice)
unknowns = list(Tuple(*eqs2).free_symbols)
for _ in range(3): # small, safe number of passes; increase if you like
pushed = False
for e in eqs2:
lhs, rhs = e.lhs, e.rhs
if lhs.is_Symbol:
# collect nonnegative linear part and constant
rhs_lin = expand(rhs)
b = rhs_lin.as_independent(*unknowns, as_Add=True)[0]
rest = rhs_lin - b
lb = nsimplify(b) if b.is_Number else 0
ok = True
contrib = 0
for term in rest.as_ordered_terms():
coeff, sym = term.as_independent(*unknowns, as_Add=False)
if not sym.is_Symbol:
ok = False; break
coeff = nsimplify(coeff)
if coeff.is_Number and coeff >= 0 and sym in L:
contrib += coeff * L[sym]
elif coeff == 0:
continue
else:
ok = False; break
if ok:
newL = lb + contrib
if lhs not in L or newL > L[lhs]:
L[lhs] = newL; pushed = True
if not pushed:
break
return L
def solve_linear(eqs: List[Eq], unknowns: List[Symbol]) -> Dict[Symbol, Expr]:
# SymPy returns a FiniteSet with a Tuple solution (possibly parametric).
solset = linsolve(eqs, unknowns)
if not solset: # no solution
return {}
(sol_tuple,) = tuple(solset)
return {u: s for u, s in zip(unknowns, sol_tuple)}
def initial_policy(max_specs: List[MaxSpec], L: Dict[Symbol, Expr] | None = None):
policy = []
for ms in max_specs:
# Prefer a numeric const if present (freezes many Maxes immediately)
const_ix = None
best_val = None
for j, a in enumerate(ms.args):
if a.is_Number:
if best_val is None or a > best_val:
best_val, const_ix = a, j
if const_ix is not None:
policy.append(const_ix)
else:
policy.append(0)
return policy
def policy_iteration(eqs2: List[Eq], max_specs: List[MaxSpec],
syms_max: List[Symbol],
syms_all: Iterable[Symbol],
seed_numeric: Dict[Symbol, float] | None = None,
max_iters: int = 20,
verbose: bool = True):
# Unknown ordering: m’s first, then “don’t care”, then “specials”
# (Your earlier ordering works well; we’ll keep it simple: all symbols.)
unknowns = list(syms_max) + [s for s in syms_all if s not in syms_max]
# Precompute bound-based initial policy
L = lower_bound_propagation(eqs2, max_specs)
policy = initial_policy(max_specs, L)
for it in range(max_iters):
# Enforce chosen branches: add equalities m_i = args[policy[i]]
eqs_pol = list(eqs2)
for ms, j in zip(max_specs, policy):
eqs_pol.append(Eq(ms.m, ms.args[j]))
sol = solve_linear(eqs_pol, unknowns)
if not sol:
if verbose: print(f"[policy {it}] infeasible under current branch choices")
return None # infeasible policy (should be rare if system is well-posed)
# Evaluate to decide if any Max branch is violated
changed = False
for i, ms in enumerate(max_specs):
# Compute numeric-ish value of each arg under current solution
# Substitute symbolic solution first; then optionally a numeric seed
def val(expr):
v = expr.xreplace(sol)
if seed_numeric:
v = v.xreplace({k: nsimplify(vv) for k, vv in seed_numeric.items()})
try:
return N(v, 40)
except Exception:
return v
vals = [val(a) for a in ms.args]
mval = val(ms.m.xreplace(sol))
# pick the arg with the (numerically) largest value
# if ties, keep the current policy choice (stable)
try:
best_ix = max(range(len(vals)), key=lambda j: vals[j])
violated = (vals[best_ix] > mval + 1e-30) # tiny slack to avoid noise
except TypeError:
# Non-numeric comparison; fall back to symbolic max check
violated = False
best_ix = policy[i]
for j, a in enumerate(ms.args):
if simplify((a - ms.args[policy[i]]).xreplace(sol)) > 0:
best_ix = j; violated = True; break
if violated and best_ix != policy[i]:
policy[i] = best_ix
changed = True
if verbose:
print(f"[policy {it}] {'switch' if changed else 'fixed'}")
if not changed:
# Fixed point: return the full solved map (you can also project)
return sol
if verbose:
print("[policy] exceeded iteration cap.")
return None
# eqs = [...] # your big list of Eq(...) from the prompt
eqs2, max_specs, syms_max, syms_all, rep_m = build_max_epigraph(eqs)
# Optional: seed a few core symbols with plausible numerics to break ties consistently.
seed = {} # e.g., {Symbol('v21'): 0.73, Symbol('v111'): 0.78}
solution = policy_iteration(eqs2, max_specs, list(syms_max), syms_all, seed_numeric=seed, verbose=True)
if solution is None:
print("No fixed policy found (under current setup).")
else:
# You now have values/affine forms for ALL vars (including m_i).
# If you want only the original v-variables:
sol_orig = {s: e for s, e in solution.items() if s.name.startswith('v')}
print("Solved entries:", len(sol_orig))
```
/c