glpmpl03.c 211 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072
  1. /* glpmpl03.c */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  6. * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  7. * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  8. * E-mail: <mao@gnu.org>.
  9. *
  10. * GLPK is free software: you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************/
  23. #define _GLPSTD_ERRNO
  24. #define _GLPSTD_STDIO
  25. #include "glpenv.h"
  26. #include "glpmpl.h"
  27. /**********************************************************************/
  28. /* * * FLOATING-POINT NUMBERS * * */
  29. /**********************************************************************/
  30. /*----------------------------------------------------------------------
  31. -- fp_add - floating-point addition.
  32. --
  33. -- This routine computes the sum x + y. */
  34. double fp_add(MPL *mpl, double x, double y)
  35. { if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y ||
  36. x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y)
  37. mpl_error(mpl, "%.*g + %.*g; floating-point overflow",
  38. DBL_DIG, x, DBL_DIG, y);
  39. return x + y;
  40. }
  41. /*----------------------------------------------------------------------
  42. -- fp_sub - floating-point subtraction.
  43. --
  44. -- This routine computes the difference x - y. */
  45. double fp_sub(MPL *mpl, double x, double y)
  46. { if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y ||
  47. x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y)
  48. mpl_error(mpl, "%.*g - %.*g; floating-point overflow",
  49. DBL_DIG, x, DBL_DIG, y);
  50. return x - y;
  51. }
  52. /*----------------------------------------------------------------------
  53. -- fp_less - floating-point non-negative subtraction.
  54. --
  55. -- This routine computes the non-negative difference max(0, x - y). */
  56. double fp_less(MPL *mpl, double x, double y)
  57. { if (x < y) return 0.0;
  58. if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y)
  59. mpl_error(mpl, "%.*g less %.*g; floating-point overflow",
  60. DBL_DIG, x, DBL_DIG, y);
  61. return x - y;
  62. }
  63. /*----------------------------------------------------------------------
  64. -- fp_mul - floating-point multiplication.
  65. --
  66. -- This routine computes the product x * y. */
  67. double fp_mul(MPL *mpl, double x, double y)
  68. { if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y))
  69. mpl_error(mpl, "%.*g * %.*g; floating-point overflow",
  70. DBL_DIG, x, DBL_DIG, y);
  71. return x * y;
  72. }
  73. /*----------------------------------------------------------------------
  74. -- fp_div - floating-point division.
  75. --
  76. -- This routine computes the quotient x / y. */
  77. double fp_div(MPL *mpl, double x, double y)
  78. { if (fabs(y) < DBL_MIN)
  79. mpl_error(mpl, "%.*g / %.*g; floating-point zero divide",
  80. DBL_DIG, x, DBL_DIG, y);
  81. if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
  82. mpl_error(mpl, "%.*g / %.*g; floating-point overflow",
  83. DBL_DIG, x, DBL_DIG, y);
  84. return x / y;
  85. }
  86. /*----------------------------------------------------------------------
  87. -- fp_idiv - floating-point quotient of exact division.
  88. --
  89. -- This routine computes the quotient of exact division x div y. */
  90. double fp_idiv(MPL *mpl, double x, double y)
  91. { if (fabs(y) < DBL_MIN)
  92. mpl_error(mpl, "%.*g div %.*g; floating-point zero divide",
  93. DBL_DIG, x, DBL_DIG, y);
  94. if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
  95. mpl_error(mpl, "%.*g div %.*g; floating-point overflow",
  96. DBL_DIG, x, DBL_DIG, y);
  97. x /= y;
  98. return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0;
  99. }
  100. /*----------------------------------------------------------------------
  101. -- fp_mod - floating-point remainder of exact division.
  102. --
  103. -- This routine computes the remainder of exact division x mod y.
  104. --
  105. -- NOTE: By definition x mod y = x - y * floor(x / y). */
  106. double fp_mod(MPL *mpl, double x, double y)
  107. { double r;
  108. xassert(mpl == mpl);
  109. if (x == 0.0)
  110. r = 0.0;
  111. else if (y == 0.0)
  112. r = x;
  113. else
  114. { r = fmod(fabs(x), fabs(y));
  115. if (r != 0.0)
  116. { if (x < 0.0) r = - r;
  117. if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y;
  118. }
  119. }
  120. return r;
  121. }
  122. /*----------------------------------------------------------------------
  123. -- fp_power - floating-point exponentiation (raise to power).
  124. --
  125. -- This routine computes the exponentiation x ** y. */
  126. double fp_power(MPL *mpl, double x, double y)
  127. { double r;
  128. if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y))
  129. mpl_error(mpl, "%.*g ** %.*g; result undefined",
  130. DBL_DIG, x, DBL_DIG, y);
  131. if (x == 0.0) goto eval;
  132. if (fabs(x) > 1.0 && y > +1.0 &&
  133. +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y ||
  134. fabs(x) < 1.0 && y < -1.0 &&
  135. +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y)
  136. mpl_error(mpl, "%.*g ** %.*g; floating-point overflow",
  137. DBL_DIG, x, DBL_DIG, y);
  138. if (fabs(x) > 1.0 && y < -1.0 &&
  139. -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y ||
  140. fabs(x) < 1.0 && y > +1.0 &&
  141. -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y)
  142. r = 0.0;
  143. else
  144. eval: r = pow(x, y);
  145. return r;
  146. }
  147. /*----------------------------------------------------------------------
  148. -- fp_exp - floating-point base-e exponential.
  149. --
  150. -- This routine computes the base-e exponential e ** x. */
  151. double fp_exp(MPL *mpl, double x)
  152. { if (x > 0.999 * log(DBL_MAX))
  153. mpl_error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x);
  154. return exp(x);
  155. }
  156. /*----------------------------------------------------------------------
  157. -- fp_log - floating-point natural logarithm.
  158. --
  159. -- This routine computes the natural logarithm log x. */
  160. double fp_log(MPL *mpl, double x)
  161. { if (x <= 0.0)
  162. mpl_error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x);
  163. return log(x);
  164. }
  165. /*----------------------------------------------------------------------
  166. -- fp_log10 - floating-point common (decimal) logarithm.
  167. --
  168. -- This routine computes the common (decimal) logarithm lg x. */
  169. double fp_log10(MPL *mpl, double x)
  170. { if (x <= 0.0)
  171. mpl_error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x);
  172. return log10(x);
  173. }
  174. /*----------------------------------------------------------------------
  175. -- fp_sqrt - floating-point square root.
  176. --
  177. -- This routine computes the square root x ** 0.5. */
  178. double fp_sqrt(MPL *mpl, double x)
  179. { if (x < 0.0)
  180. mpl_error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x);
  181. return sqrt(x);
  182. }
  183. /*----------------------------------------------------------------------
  184. -- fp_sin - floating-point trigonometric sine.
  185. --
  186. -- This routine computes the trigonometric sine sin(x). */
  187. double fp_sin(MPL *mpl, double x)
  188. { if (!(-1e6 <= x && x <= +1e6))
  189. mpl_error(mpl, "sin(%.*g); argument too large", DBL_DIG, x);
  190. return sin(x);
  191. }
  192. /*----------------------------------------------------------------------
  193. -- fp_cos - floating-point trigonometric cosine.
  194. --
  195. -- This routine computes the trigonometric cosine cos(x). */
  196. double fp_cos(MPL *mpl, double x)
  197. { if (!(-1e6 <= x && x <= +1e6))
  198. mpl_error(mpl, "cos(%.*g); argument too large", DBL_DIG, x);
  199. return cos(x);
  200. }
  201. /*----------------------------------------------------------------------
  202. -- fp_atan - floating-point trigonometric arctangent.
  203. --
  204. -- This routine computes the trigonometric arctangent atan(x). */
  205. double fp_atan(MPL *mpl, double x)
  206. { xassert(mpl == mpl);
  207. return atan(x);
  208. }
  209. /*----------------------------------------------------------------------
  210. -- fp_atan2 - floating-point trigonometric arctangent.
  211. --
  212. -- This routine computes the trigonometric arctangent atan(y / x). */
  213. double fp_atan2(MPL *mpl, double y, double x)
  214. { xassert(mpl == mpl);
  215. return atan2(y, x);
  216. }
  217. /*----------------------------------------------------------------------
  218. -- fp_round - round floating-point value to n fractional digits.
  219. --
  220. -- This routine rounds given floating-point value x to n fractional
  221. -- digits with the formula:
  222. --
  223. -- round(x, n) = floor(x * 10^n + 0.5) / 10^n.
  224. --
  225. -- The parameter n is assumed to be integer. */
  226. double fp_round(MPL *mpl, double x, double n)
  227. { double ten_to_n;
  228. if (n != floor(n))
  229. mpl_error(mpl, "round(%.*g, %.*g); non-integer second argument",
  230. DBL_DIG, x, DBL_DIG, n);
  231. if (n <= DBL_DIG + 2)
  232. { ten_to_n = pow(10.0, n);
  233. if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
  234. { x = floor(x * ten_to_n + 0.5);
  235. if (x != 0.0) x /= ten_to_n;
  236. }
  237. }
  238. return x;
  239. }
  240. /*----------------------------------------------------------------------
  241. -- fp_trunc - truncate floating-point value to n fractional digits.
  242. --
  243. -- This routine truncates given floating-point value x to n fractional
  244. -- digits with the formula:
  245. --
  246. -- ( floor(x * 10^n) / 10^n, if x >= 0
  247. -- trunc(x, n) = <
  248. -- ( ceil(x * 10^n) / 10^n, if x < 0
  249. --
  250. -- The parameter n is assumed to be integer. */
  251. double fp_trunc(MPL *mpl, double x, double n)
  252. { double ten_to_n;
  253. if (n != floor(n))
  254. mpl_error(mpl, "trunc(%.*g, %.*g); non-integer second argument",
  255. DBL_DIG, x, DBL_DIG, n);
  256. if (n <= DBL_DIG + 2)
  257. { ten_to_n = pow(10.0, n);
  258. if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
  259. { x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n));
  260. if (x != 0.0) x /= ten_to_n;
  261. }
  262. }
  263. return x;
  264. }
  265. /**********************************************************************/
  266. /* * * PSEUDO-RANDOM NUMBER GENERATORS * * */
  267. /**********************************************************************/
  268. /*----------------------------------------------------------------------
  269. -- fp_irand224 - pseudo-random integer in the range [0, 2^24).
  270. --
  271. -- This routine returns a next pseudo-random integer (converted to
  272. -- floating-point) which is uniformly distributed between 0 and 2^24-1,
  273. -- inclusive. */
  274. #define two_to_the_24 0x1000000
  275. double fp_irand224(MPL *mpl)
  276. { return
  277. (double)rng_unif_rand(mpl->rand, two_to_the_24);
  278. }
  279. /*----------------------------------------------------------------------
  280. -- fp_uniform01 - pseudo-random number in the range [0, 1).
  281. --
  282. -- This routine returns a next pseudo-random number which is uniformly
  283. -- distributed in the range [0, 1). */
  284. #define two_to_the_31 ((unsigned int)0x80000000)
  285. double fp_uniform01(MPL *mpl)
  286. { return
  287. (double)rng_next_rand(mpl->rand) / (double)two_to_the_31;
  288. }
  289. /*----------------------------------------------------------------------
  290. -- fp_uniform - pseudo-random number in the range [a, b).
  291. --
  292. -- This routine returns a next pseudo-random number which is uniformly
  293. -- distributed in the range [a, b). */
  294. double fp_uniform(MPL *mpl, double a, double b)
  295. { double x;
  296. if (a >= b)
  297. mpl_error(mpl, "Uniform(%.*g, %.*g); invalid range",
  298. DBL_DIG, a, DBL_DIG, b);
  299. x = fp_uniform01(mpl);
  300. #if 0
  301. x = a * (1.0 - x) + b * x;
  302. #else
  303. x = fp_add(mpl, a * (1.0 - x), b * x);
  304. #endif
  305. return x;
  306. }
  307. /*----------------------------------------------------------------------
  308. -- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1.
  309. --
  310. -- This routine returns a Gaussian random variate with zero mean and
  311. -- unit standard deviation. The polar (Box-Mueller) method is used.
  312. --
  313. -- This code is a modified version of the routine gsl_ran_gaussian from
  314. -- the GNU Scientific Library Version 1.0. */
  315. double fp_normal01(MPL *mpl)
  316. { double x, y, r2;
  317. do
  318. { /* choose x, y in uniform square (-1,-1) to (+1,+1) */
  319. x = -1.0 + 2.0 * fp_uniform01(mpl);
  320. y = -1.0 + 2.0 * fp_uniform01(mpl);
  321. /* see if it is in the unit circle */
  322. r2 = x * x + y * y;
  323. } while (r2 > 1.0 || r2 == 0.0);
  324. /* Box-Muller transform */
  325. return y * sqrt(-2.0 * log (r2) / r2);
  326. }
  327. /*----------------------------------------------------------------------
  328. -- fp_normal - Gaussian random variate with specified mu and sigma.
  329. --
  330. -- This routine returns a Gaussian random variate with mean mu and
  331. -- standard deviation sigma. */
  332. double fp_normal(MPL *mpl, double mu, double sigma)
  333. { double x;
  334. #if 0
  335. x = mu + sigma * fp_normal01(mpl);
  336. #else
  337. x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl)));
  338. #endif
  339. return x;
  340. }
  341. /**********************************************************************/
  342. /* * * SEGMENTED CHARACTER STRINGS * * */
  343. /**********************************************************************/
  344. /*----------------------------------------------------------------------
  345. -- create_string - create character string.
  346. --
  347. -- This routine creates a segmented character string, which is exactly
  348. -- equivalent to specified character string. */
  349. STRING *create_string
  350. ( MPL *mpl,
  351. char buf[MAX_LENGTH+1] /* not changed */
  352. )
  353. #if 0
  354. { STRING *head, *tail;
  355. int i, j;
  356. xassert(buf != NULL);
  357. xassert(strlen(buf) <= MAX_LENGTH);
  358. head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
  359. for (i = j = 0; ; i++)
  360. { if ((tail->seg[j++] = buf[i]) == '\0') break;
  361. if (j == STRSEG_SIZE)
  362. tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0;
  363. }
  364. tail->next = NULL;
  365. return head;
  366. }
  367. #else
  368. { STRING *str;
  369. xassert(strlen(buf) <= MAX_LENGTH);
  370. str = dmp_get_atom(mpl->strings, strlen(buf)+1);
  371. strcpy(str, buf);
  372. return str;
  373. }
  374. #endif
  375. /*----------------------------------------------------------------------
  376. -- copy_string - make copy of character string.
  377. --
  378. -- This routine returns an exact copy of segmented character string. */
  379. STRING *copy_string
  380. ( MPL *mpl,
  381. STRING *str /* not changed */
  382. )
  383. #if 0
  384. { STRING *head, *tail;
  385. xassert(str != NULL);
  386. head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
  387. for (; str != NULL; str = str->next)
  388. { memcpy(tail->seg, str->seg, STRSEG_SIZE);
  389. if (str->next != NULL)
  390. tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING)));
  391. }
  392. tail->next = NULL;
  393. return head;
  394. }
  395. #else
  396. { xassert(mpl == mpl);
  397. return create_string(mpl, str);
  398. }
  399. #endif
  400. /*----------------------------------------------------------------------
  401. -- compare_strings - compare one character string with another.
  402. --
  403. -- This routine compares one segmented character strings with another
  404. -- and returns the result of comparison as follows:
  405. --
  406. -- = 0 - both strings are identical;
  407. -- < 0 - the first string precedes the second one;
  408. -- > 0 - the first string follows the second one. */
  409. int compare_strings
  410. ( MPL *mpl,
  411. STRING *str1, /* not changed */
  412. STRING *str2 /* not changed */
  413. )
  414. #if 0
  415. { int j, c1, c2;
  416. xassert(mpl == mpl);
  417. for (;; str1 = str1->next, str2 = str2->next)
  418. { xassert(str1 != NULL);
  419. xassert(str2 != NULL);
  420. for (j = 0; j < STRSEG_SIZE; j++)
  421. { c1 = (unsigned char)str1->seg[j];
  422. c2 = (unsigned char)str2->seg[j];
  423. if (c1 < c2) return -1;
  424. if (c1 > c2) return +1;
  425. if (c1 == '\0') goto done;
  426. }
  427. }
  428. done: return 0;
  429. }
  430. #else
  431. { xassert(mpl == mpl);
  432. return strcmp(str1, str2);
  433. }
  434. #endif
  435. /*----------------------------------------------------------------------
  436. -- fetch_string - extract content of character string.
  437. --
  438. -- This routine returns a character string, which is exactly equivalent
  439. -- to specified segmented character string. */
  440. char *fetch_string
  441. ( MPL *mpl,
  442. STRING *str, /* not changed */
  443. char buf[MAX_LENGTH+1] /* modified */
  444. )
  445. #if 0
  446. { int i, j;
  447. xassert(mpl == mpl);
  448. xassert(buf != NULL);
  449. for (i = 0; ; str = str->next)
  450. { xassert(str != NULL);
  451. for (j = 0; j < STRSEG_SIZE; j++)
  452. if ((buf[i++] = str->seg[j]) == '\0') goto done;
  453. }
  454. done: xassert(strlen(buf) <= MAX_LENGTH);
  455. return buf;
  456. }
  457. #else
  458. { xassert(mpl == mpl);
  459. return strcpy(buf, str);
  460. }
  461. #endif
  462. /*----------------------------------------------------------------------
  463. -- delete_string - delete character string.
  464. --
  465. -- This routine deletes specified segmented character string. */
  466. void delete_string
  467. ( MPL *mpl,
  468. STRING *str /* destroyed */
  469. )
  470. #if 0
  471. { STRING *temp;
  472. xassert(str != NULL);
  473. while (str != NULL)
  474. { temp = str;
  475. str = str->next;
  476. dmp_free_atom(mpl->strings, temp, sizeof(STRING));
  477. }
  478. return;
  479. }
  480. #else
  481. { dmp_free_atom(mpl->strings, str, strlen(str)+1);
  482. return;
  483. }
  484. #endif
  485. /**********************************************************************/
  486. /* * * SYMBOLS * * */
  487. /**********************************************************************/
  488. /*----------------------------------------------------------------------
  489. -- create_symbol_num - create symbol of numeric type.
  490. --
  491. -- This routine creates a symbol, which has a numeric value specified
  492. -- as floating-point number. */
  493. SYMBOL *create_symbol_num(MPL *mpl, double num)
  494. { SYMBOL *sym;
  495. sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
  496. sym->num = num;
  497. sym->str = NULL;
  498. return sym;
  499. }
  500. /*----------------------------------------------------------------------
  501. -- create_symbol_str - create symbol of abstract type.
  502. --
  503. -- This routine creates a symbol, which has an abstract value specified
  504. -- as segmented character string. */
  505. SYMBOL *create_symbol_str
  506. ( MPL *mpl,
  507. STRING *str /* destroyed */
  508. )
  509. { SYMBOL *sym;
  510. xassert(str != NULL);
  511. sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
  512. sym->num = 0.0;
  513. sym->str = str;
  514. return sym;
  515. }
  516. /*----------------------------------------------------------------------
  517. -- copy_symbol - make copy of symbol.
  518. --
  519. -- This routine returns an exact copy of symbol. */
  520. SYMBOL *copy_symbol
  521. ( MPL *mpl,
  522. SYMBOL *sym /* not changed */
  523. )
  524. { SYMBOL *copy;
  525. xassert(sym != NULL);
  526. copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
  527. if (sym->str == NULL)
  528. { copy->num = sym->num;
  529. copy->str = NULL;
  530. }
  531. else
  532. { copy->num = 0.0;
  533. copy->str = copy_string(mpl, sym->str);
  534. }
  535. return copy;
  536. }
  537. /*----------------------------------------------------------------------
  538. -- compare_symbols - compare one symbol with another.
  539. --
  540. -- This routine compares one symbol with another and returns the result
  541. -- of comparison as follows:
  542. --
  543. -- = 0 - both symbols are identical;
  544. -- < 0 - the first symbol precedes the second one;
  545. -- > 0 - the first symbol follows the second one.
  546. --
  547. -- Note that the linear order, in which symbols follow each other, is
  548. -- implementation-dependent. It may be not an alphabetical order. */
  549. int compare_symbols
  550. ( MPL *mpl,
  551. SYMBOL *sym1, /* not changed */
  552. SYMBOL *sym2 /* not changed */
  553. )
  554. { xassert(sym1 != NULL);
  555. xassert(sym2 != NULL);
  556. /* let all numeric quantities precede all symbolic quantities */
  557. if (sym1->str == NULL && sym2->str == NULL)
  558. { if (sym1->num < sym2->num) return -1;
  559. if (sym1->num > sym2->num) return +1;
  560. return 0;
  561. }
  562. if (sym1->str == NULL) return -1;
  563. if (sym2->str == NULL) return +1;
  564. return compare_strings(mpl, sym1->str, sym2->str);
  565. }
  566. /*----------------------------------------------------------------------
  567. -- delete_symbol - delete symbol.
  568. --
  569. -- This routine deletes specified symbol. */
  570. void delete_symbol
  571. ( MPL *mpl,
  572. SYMBOL *sym /* destroyed */
  573. )
  574. { xassert(sym != NULL);
  575. if (sym->str != NULL) delete_string(mpl, sym->str);
  576. dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL));
  577. return;
  578. }
  579. /*----------------------------------------------------------------------
  580. -- format_symbol - format symbol for displaying or printing.
  581. --
  582. -- This routine converts specified symbol to a charater string, which
  583. -- is suitable for displaying or printing.
  584. --
  585. -- The resultant string is never longer than 255 characters. If it gets
  586. -- longer, it is truncated from the right and appended by dots. */
  587. char *format_symbol
  588. ( MPL *mpl,
  589. SYMBOL *sym /* not changed */
  590. )
  591. { char *buf = mpl->sym_buf;
  592. xassert(sym != NULL);
  593. if (sym->str == NULL)
  594. sprintf(buf, "%.*g", DBL_DIG, sym->num);
  595. else
  596. { char str[MAX_LENGTH+1];
  597. int quoted, j, len;
  598. fetch_string(mpl, sym->str, str);
  599. if (!(isalpha((unsigned char)str[0]) || str[0] == '_'))
  600. quoted = 1;
  601. else
  602. { quoted = 0;
  603. for (j = 1; str[j] != '\0'; j++)
  604. { if (!(isalnum((unsigned char)str[j]) ||
  605. strchr("+-._", (unsigned char)str[j]) != NULL))
  606. { quoted = 1;
  607. break;
  608. }
  609. }
  610. }
  611. # define safe_append(c) \
  612. (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
  613. buf[0] = '\0', len = 0;
  614. if (quoted) safe_append('\'');
  615. for (j = 0; str[j] != '\0'; j++)
  616. { if (quoted && str[j] == '\'') safe_append('\'');
  617. safe_append(str[j]);
  618. }
  619. if (quoted) safe_append('\'');
  620. # undef safe_append
  621. buf[len] = '\0';
  622. if (len == 255) strcpy(buf+252, "...");
  623. }
  624. xassert(strlen(buf) <= 255);
  625. return buf;
  626. }
  627. /*----------------------------------------------------------------------
  628. -- concat_symbols - concatenate one symbol with another.
  629. --
  630. -- This routine concatenates values of two given symbols and assigns
  631. -- the resultant character string to a new symbol, which is returned on
  632. -- exit. Both original symbols are destroyed. */
  633. SYMBOL *concat_symbols
  634. ( MPL *mpl,
  635. SYMBOL *sym1, /* destroyed */
  636. SYMBOL *sym2 /* destroyed */
  637. )
  638. { char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1];
  639. xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG);
  640. if (sym1->str == NULL)
  641. sprintf(str1, "%.*g", DBL_DIG, sym1->num);
  642. else
  643. fetch_string(mpl, sym1->str, str1);
  644. if (sym2->str == NULL)
  645. sprintf(str2, "%.*g", DBL_DIG, sym2->num);
  646. else
  647. fetch_string(mpl, sym2->str, str2);
  648. if (strlen(str1) + strlen(str2) > MAX_LENGTH)
  649. { char buf[255+1];
  650. strcpy(buf, format_symbol(mpl, sym1));
  651. xassert(strlen(buf) < sizeof(buf));
  652. mpl_error(mpl, "%s & %s; resultant symbol exceeds %d characters",
  653. buf, format_symbol(mpl, sym2), MAX_LENGTH);
  654. }
  655. delete_symbol(mpl, sym1);
  656. delete_symbol(mpl, sym2);
  657. return create_symbol_str(mpl, create_string(mpl, strcat(str1,
  658. str2)));
  659. }
  660. /**********************************************************************/
  661. /* * * N-TUPLES * * */
  662. /**********************************************************************/
  663. /*----------------------------------------------------------------------
  664. -- create_tuple - create n-tuple.
  665. --
  666. -- This routine creates a n-tuple, which initially has no components,
  667. -- i.e. which is 0-tuple. */
  668. TUPLE *create_tuple(MPL *mpl)
  669. { TUPLE *tuple;
  670. xassert(mpl == mpl);
  671. tuple = NULL;
  672. return tuple;
  673. }
  674. /*----------------------------------------------------------------------
  675. -- expand_tuple - append symbol to n-tuple.
  676. --
  677. -- This routine expands n-tuple appending to it a given symbol, which
  678. -- becomes its new last component. */
  679. TUPLE *expand_tuple
  680. ( MPL *mpl,
  681. TUPLE *tuple, /* destroyed */
  682. SYMBOL *sym /* destroyed */
  683. )
  684. { TUPLE *tail, *temp;
  685. xassert(sym != NULL);
  686. /* create a new component */
  687. tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
  688. tail->sym = sym;
  689. tail->next = NULL;
  690. /* and append it to the component list */
  691. if (tuple == NULL)
  692. tuple = tail;
  693. else
  694. { for (temp = tuple; temp->next != NULL; temp = temp->next);
  695. temp->next = tail;
  696. }
  697. return tuple;
  698. }
  699. /*----------------------------------------------------------------------
  700. -- tuple_dimen - determine dimension of n-tuple.
  701. --
  702. -- This routine returns dimension of n-tuple, i.e. number of components
  703. -- in the n-tuple. */
  704. int tuple_dimen
  705. ( MPL *mpl,
  706. TUPLE *tuple /* not changed */
  707. )
  708. { TUPLE *temp;
  709. int dim = 0;
  710. xassert(mpl == mpl);
  711. for (temp = tuple; temp != NULL; temp = temp->next) dim++;
  712. return dim;
  713. }
  714. /*----------------------------------------------------------------------
  715. -- copy_tuple - make copy of n-tuple.
  716. --
  717. -- This routine returns an exact copy of n-tuple. */
  718. TUPLE *copy_tuple
  719. ( MPL *mpl,
  720. TUPLE *tuple /* not changed */
  721. )
  722. { TUPLE *head, *tail;
  723. if (tuple == NULL)
  724. head = NULL;
  725. else
  726. { head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
  727. for (; tuple != NULL; tuple = tuple->next)
  728. { xassert(tuple->sym != NULL);
  729. tail->sym = copy_symbol(mpl, tuple->sym);
  730. if (tuple->next != NULL)
  731. tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
  732. }
  733. tail->next = NULL;
  734. }
  735. return head;
  736. }
  737. /*----------------------------------------------------------------------
  738. -- compare_tuples - compare one n-tuple with another.
  739. --
  740. -- This routine compares two given n-tuples, which must have the same
  741. -- dimension (not checked for the sake of efficiency), and returns one
  742. -- of the following codes:
  743. --
  744. -- = 0 - both n-tuples are identical;
  745. -- < 0 - the first n-tuple precedes the second one;
  746. -- > 0 - the first n-tuple follows the second one.
  747. --
  748. -- Note that the linear order, in which n-tuples follow each other, is
  749. -- implementation-dependent. It may be not an alphabetical order. */
  750. int compare_tuples
  751. ( MPL *mpl,
  752. TUPLE *tuple1, /* not changed */
  753. TUPLE *tuple2 /* not changed */
  754. )
  755. { TUPLE *item1, *item2;
  756. int ret;
  757. xassert(mpl == mpl);
  758. for (item1 = tuple1, item2 = tuple2; item1 != NULL;
  759. item1 = item1->next, item2 = item2->next)
  760. { xassert(item2 != NULL);
  761. xassert(item1->sym != NULL);
  762. xassert(item2->sym != NULL);
  763. ret = compare_symbols(mpl, item1->sym, item2->sym);
  764. if (ret != 0) return ret;
  765. }
  766. xassert(item2 == NULL);
  767. return 0;
  768. }
  769. /*----------------------------------------------------------------------
  770. -- build_subtuple - build subtuple of given n-tuple.
  771. --
  772. -- This routine builds subtuple, which consists of first dim components
  773. -- of given n-tuple. */
  774. TUPLE *build_subtuple
  775. ( MPL *mpl,
  776. TUPLE *tuple, /* not changed */
  777. int dim
  778. )
  779. { TUPLE *head, *temp;
  780. int j;
  781. head = create_tuple(mpl);
  782. for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next)
  783. { xassert(temp != NULL);
  784. head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym));
  785. }
  786. return head;
  787. }
  788. /*----------------------------------------------------------------------
  789. -- delete_tuple - delete n-tuple.
  790. --
  791. -- This routine deletes specified n-tuple. */
  792. void delete_tuple
  793. ( MPL *mpl,
  794. TUPLE *tuple /* destroyed */
  795. )
  796. { TUPLE *temp;
  797. while (tuple != NULL)
  798. { temp = tuple;
  799. tuple = temp->next;
  800. xassert(temp->sym != NULL);
  801. delete_symbol(mpl, temp->sym);
  802. dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
  803. }
  804. return;
  805. }
  806. /*----------------------------------------------------------------------
  807. -- format_tuple - format n-tuple for displaying or printing.
  808. --
  809. -- This routine converts specified n-tuple to a character string, which
  810. -- is suitable for displaying or printing.
  811. --
  812. -- The resultant string is never longer than 255 characters. If it gets
  813. -- longer, it is truncated from the right and appended by dots. */
  814. char *format_tuple
  815. ( MPL *mpl,
  816. int c,
  817. TUPLE *tuple /* not changed */
  818. )
  819. { TUPLE *temp;
  820. int dim, j, len;
  821. char *buf = mpl->tup_buf, str[255+1], *save;
  822. # define safe_append(c) \
  823. (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
  824. buf[0] = '\0', len = 0;
  825. dim = tuple_dimen(mpl, tuple);
  826. if (c == '[' && dim > 0) safe_append('[');
  827. if (c == '(' && dim > 1) safe_append('(');
  828. for (temp = tuple; temp != NULL; temp = temp->next)
  829. { if (temp != tuple) safe_append(',');
  830. xassert(temp->sym != NULL);
  831. save = mpl->sym_buf;
  832. mpl->sym_buf = str;
  833. format_symbol(mpl, temp->sym);
  834. mpl->sym_buf = save;
  835. xassert(strlen(str) < sizeof(str));
  836. for (j = 0; str[j] != '\0'; j++) safe_append(str[j]);
  837. }
  838. if (c == '[' && dim > 0) safe_append(']');
  839. if (c == '(' && dim > 1) safe_append(')');
  840. # undef safe_append
  841. buf[len] = '\0';
  842. if (len == 255) strcpy(buf+252, "...");
  843. xassert(strlen(buf) <= 255);
  844. return buf;
  845. }
  846. /**********************************************************************/
  847. /* * * ELEMENTAL SETS * * */
  848. /**********************************************************************/
  849. /*----------------------------------------------------------------------
  850. -- create_elemset - create elemental set.
  851. --
  852. -- This routine creates an elemental set, whose members are n-tuples of
  853. -- specified dimension. Being created the set is initially empty. */
  854. ELEMSET *create_elemset(MPL *mpl, int dim)
  855. { ELEMSET *set;
  856. xassert(dim > 0);
  857. set = create_array(mpl, A_NONE, dim);
  858. return set;
  859. }
  860. /*----------------------------------------------------------------------
  861. -- find_tuple - check if elemental set contains given n-tuple.
  862. --
  863. -- This routine finds given n-tuple in specified elemental set in order
  864. -- to check if the set contains that n-tuple. If the n-tuple is found,
  865. -- the routine returns pointer to corresponding array member. Otherwise
  866. -- null pointer is returned. */
  867. MEMBER *find_tuple
  868. ( MPL *mpl,
  869. ELEMSET *set, /* not changed */
  870. TUPLE *tuple /* not changed */
  871. )
  872. { xassert(set != NULL);
  873. xassert(set->type == A_NONE);
  874. xassert(set->dim == tuple_dimen(mpl, tuple));
  875. return find_member(mpl, set, tuple);
  876. }
  877. /*----------------------------------------------------------------------
  878. -- add_tuple - add new n-tuple to elemental set.
  879. --
  880. -- This routine adds given n-tuple to specified elemental set.
  881. --
  882. -- For the sake of efficiency this routine doesn't check whether the
  883. -- set already contains the same n-tuple or not. Therefore the calling
  884. -- program should use the routine find_tuple (if necessary) in order to
  885. -- make sure that the given n-tuple is not contained in the set, since
  886. -- duplicate n-tuples within the same set are not allowed. */
  887. MEMBER *add_tuple
  888. ( MPL *mpl,
  889. ELEMSET *set, /* modified */
  890. TUPLE *tuple /* destroyed */
  891. )
  892. { MEMBER *memb;
  893. xassert(set != NULL);
  894. xassert(set->type == A_NONE);
  895. xassert(set->dim == tuple_dimen(mpl, tuple));
  896. memb = add_member(mpl, set, tuple);
  897. memb->value.none = NULL;
  898. return memb;
  899. }
  900. /*----------------------------------------------------------------------
  901. -- check_then_add - check and add new n-tuple to elemental set.
  902. --
  903. -- This routine is equivalent to the routine add_tuple except that it
  904. -- does check for duplicate n-tuples. */
  905. MEMBER *check_then_add
  906. ( MPL *mpl,
  907. ELEMSET *set, /* modified */
  908. TUPLE *tuple /* destroyed */
  909. )
  910. { if (find_tuple(mpl, set, tuple) != NULL)
  911. mpl_error(mpl, "duplicate tuple %s detected", format_tuple(mpl,
  912. '(', tuple));
  913. return add_tuple(mpl, set, tuple);
  914. }
  915. /*----------------------------------------------------------------------
  916. -- copy_elemset - make copy of elemental set.
  917. --
  918. -- This routine makes an exact copy of elemental set. */
  919. ELEMSET *copy_elemset
  920. ( MPL *mpl,
  921. ELEMSET *set /* not changed */
  922. )
  923. { ELEMSET *copy;
  924. MEMBER *memb;
  925. xassert(set != NULL);
  926. xassert(set->type == A_NONE);
  927. xassert(set->dim > 0);
  928. copy = create_elemset(mpl, set->dim);
  929. for (memb = set->head; memb != NULL; memb = memb->next)
  930. add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple));
  931. return copy;
  932. }
  933. /*----------------------------------------------------------------------
  934. -- delete_elemset - delete elemental set.
  935. --
  936. -- This routine deletes specified elemental set. */
  937. void delete_elemset
  938. ( MPL *mpl,
  939. ELEMSET *set /* destroyed */
  940. )
  941. { xassert(set != NULL);
  942. xassert(set->type == A_NONE);
  943. delete_array(mpl, set);
  944. return;
  945. }
  946. /*----------------------------------------------------------------------
  947. -- arelset_size - compute size of "arithmetic" elemental set.
  948. --
  949. -- This routine computes the size of "arithmetic" elemental set, which
  950. -- is specified in the form of arithmetic progression:
  951. --
  952. -- { t0 .. tf by dt }.
  953. --
  954. -- The size is computed using the formula:
  955. --
  956. -- n = max(0, floor((tf - t0) / dt) + 1). */
  957. int arelset_size(MPL *mpl, double t0, double tf, double dt)
  958. { double temp;
  959. if (dt == 0.0)
  960. mpl_error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed",
  961. DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
  962. if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0)
  963. temp = +DBL_MAX;
  964. else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0)
  965. temp = -DBL_MAX;
  966. else
  967. temp = tf - t0;
  968. if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt))
  969. { if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0)
  970. temp = +DBL_MAX;
  971. else
  972. temp = 0.0;
  973. }
  974. else
  975. { temp = floor(temp / dt) + 1.0;
  976. if (temp < 0.0) temp = 0.0;
  977. }
  978. xassert(temp >= 0.0);
  979. if (temp > (double)(INT_MAX - 1))
  980. mpl_error(mpl, "%.*g .. %.*g by %.*g; set too large",
  981. DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
  982. return (int)(temp + 0.5);
  983. }
  984. /*----------------------------------------------------------------------
  985. -- arelset_member - compute member of "arithmetic" elemental set.
  986. --
  987. -- This routine returns a numeric value of symbol, which is equivalent
  988. -- to j-th member of given "arithmetic" elemental set specified in the
  989. -- form of arithmetic progression:
  990. --
  991. -- { t0 .. tf by dt }.
  992. --
  993. -- The symbol value is computed with the formula:
  994. --
  995. -- j-th member = t0 + (j - 1) * dt,
  996. --
  997. -- The number j must satisfy to the restriction 1 <= j <= n, where n is
  998. -- the set size computed by the routine arelset_size. */
  999. double arelset_member(MPL *mpl, double t0, double tf, double dt, int j)
  1000. { xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt));
  1001. return t0 + (double)(j - 1) * dt;
  1002. }
  1003. /*----------------------------------------------------------------------
  1004. -- create_arelset - create "arithmetic" elemental set.
  1005. --
  1006. -- This routine creates "arithmetic" elemental set, which is specified
  1007. -- in the form of arithmetic progression:
  1008. --
  1009. -- { t0 .. tf by dt }.
  1010. --
  1011. -- Components of this set are 1-tuples. */
  1012. ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt)
  1013. { ELEMSET *set;
  1014. int j, n;
  1015. set = create_elemset(mpl, 1);
  1016. n = arelset_size(mpl, t0, tf, dt);
  1017. for (j = 1; j <= n; j++)
  1018. { add_tuple
  1019. ( mpl,
  1020. set,
  1021. expand_tuple
  1022. ( mpl,
  1023. create_tuple(mpl),
  1024. create_symbol_num
  1025. ( mpl,
  1026. arelset_member(mpl, t0, tf, dt, j)
  1027. )
  1028. )
  1029. );
  1030. }
  1031. return set;
  1032. }
  1033. /*----------------------------------------------------------------------
  1034. -- set_union - union of two elemental sets.
  1035. --
  1036. -- This routine computes the union:
  1037. --
  1038. -- X U Y = { j | (j in X) or (j in Y) },
  1039. --
  1040. -- where X and Y are given elemental sets (destroyed on exit). */
  1041. ELEMSET *set_union
  1042. ( MPL *mpl,
  1043. ELEMSET *X, /* destroyed */
  1044. ELEMSET *Y /* destroyed */
  1045. )
  1046. { MEMBER *memb;
  1047. xassert(X != NULL);
  1048. xassert(X->type == A_NONE);
  1049. xassert(X->dim > 0);
  1050. xassert(Y != NULL);
  1051. xassert(Y->type == A_NONE);
  1052. xassert(Y->dim > 0);
  1053. xassert(X->dim == Y->dim);
  1054. for (memb = Y->head; memb != NULL; memb = memb->next)
  1055. { if (find_tuple(mpl, X, memb->tuple) == NULL)
  1056. add_tuple(mpl, X, copy_tuple(mpl, memb->tuple));
  1057. }
  1058. delete_elemset(mpl, Y);
  1059. return X;
  1060. }
  1061. /*----------------------------------------------------------------------
  1062. -- set_diff - difference between two elemental sets.
  1063. --
  1064. -- This routine computes the difference:
  1065. --
  1066. -- X \ Y = { j | (j in X) and (j not in Y) },
  1067. --
  1068. -- where X and Y are given elemental sets (destroyed on exit). */
  1069. ELEMSET *set_diff
  1070. ( MPL *mpl,
  1071. ELEMSET *X, /* destroyed */
  1072. ELEMSET *Y /* destroyed */
  1073. )
  1074. { ELEMSET *Z;
  1075. MEMBER *memb;
  1076. xassert(X != NULL);
  1077. xassert(X->type == A_NONE);
  1078. xassert(X->dim > 0);
  1079. xassert(Y != NULL);
  1080. xassert(Y->type == A_NONE);
  1081. xassert(Y->dim > 0);
  1082. xassert(X->dim == Y->dim);
  1083. Z = create_elemset(mpl, X->dim);
  1084. for (memb = X->head; memb != NULL; memb = memb->next)
  1085. { if (find_tuple(mpl, Y, memb->tuple) == NULL)
  1086. add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
  1087. }
  1088. delete_elemset(mpl, X);
  1089. delete_elemset(mpl, Y);
  1090. return Z;
  1091. }
  1092. /*----------------------------------------------------------------------
  1093. -- set_symdiff - symmetric difference between two elemental sets.
  1094. --
  1095. -- This routine computes the symmetric difference:
  1096. --
  1097. -- X (+) Y = (X \ Y) U (Y \ X),
  1098. --
  1099. -- where X and Y are given elemental sets (destroyed on exit). */
  1100. ELEMSET *set_symdiff
  1101. ( MPL *mpl,
  1102. ELEMSET *X, /* destroyed */
  1103. ELEMSET *Y /* destroyed */
  1104. )
  1105. { ELEMSET *Z;
  1106. MEMBER *memb;
  1107. xassert(X != NULL);
  1108. xassert(X->type == A_NONE);
  1109. xassert(X->dim > 0);
  1110. xassert(Y != NULL);
  1111. xassert(Y->type == A_NONE);
  1112. xassert(Y->dim > 0);
  1113. xassert(X->dim == Y->dim);
  1114. /* Z := X \ Y */
  1115. Z = create_elemset(mpl, X->dim);
  1116. for (memb = X->head; memb != NULL; memb = memb->next)
  1117. { if (find_tuple(mpl, Y, memb->tuple) == NULL)
  1118. add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
  1119. }
  1120. /* Z := Z U (Y \ X) */
  1121. for (memb = Y->head; memb != NULL; memb = memb->next)
  1122. { if (find_tuple(mpl, X, memb->tuple) == NULL)
  1123. add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
  1124. }
  1125. delete_elemset(mpl, X);
  1126. delete_elemset(mpl, Y);
  1127. return Z;
  1128. }
  1129. /*----------------------------------------------------------------------
  1130. -- set_inter - intersection of two elemental sets.
  1131. --
  1132. -- This routine computes the intersection:
  1133. --
  1134. -- X ^ Y = { j | (j in X) and (j in Y) },
  1135. --
  1136. -- where X and Y are given elemental sets (destroyed on exit). */
  1137. ELEMSET *set_inter
  1138. ( MPL *mpl,
  1139. ELEMSET *X, /* destroyed */
  1140. ELEMSET *Y /* destroyed */
  1141. )
  1142. { ELEMSET *Z;
  1143. MEMBER *memb;
  1144. xassert(X != NULL);
  1145. xassert(X->type == A_NONE);
  1146. xassert(X->dim > 0);
  1147. xassert(Y != NULL);
  1148. xassert(Y->type == A_NONE);
  1149. xassert(Y->dim > 0);
  1150. xassert(X->dim == Y->dim);
  1151. Z = create_elemset(mpl, X->dim);
  1152. for (memb = X->head; memb != NULL; memb = memb->next)
  1153. { if (find_tuple(mpl, Y, memb->tuple) != NULL)
  1154. add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
  1155. }
  1156. delete_elemset(mpl, X);
  1157. delete_elemset(mpl, Y);
  1158. return Z;
  1159. }
  1160. /*----------------------------------------------------------------------
  1161. -- set_cross - cross (Cartesian) product of two elemental sets.
  1162. --
  1163. -- This routine computes the cross (Cartesian) product:
  1164. --
  1165. -- X x Y = { (i,j) | (i in X) and (j in Y) },
  1166. --
  1167. -- where X and Y are given elemental sets (destroyed on exit). */
  1168. ELEMSET *set_cross
  1169. ( MPL *mpl,
  1170. ELEMSET *X, /* destroyed */
  1171. ELEMSET *Y /* destroyed */
  1172. )
  1173. { ELEMSET *Z;
  1174. MEMBER *memx, *memy;
  1175. TUPLE *tuple, *temp;
  1176. xassert(X != NULL);
  1177. xassert(X->type == A_NONE);
  1178. xassert(X->dim > 0);
  1179. xassert(Y != NULL);
  1180. xassert(Y->type == A_NONE);
  1181. xassert(Y->dim > 0);
  1182. Z = create_elemset(mpl, X->dim + Y->dim);
  1183. for (memx = X->head; memx != NULL; memx = memx->next)
  1184. { for (memy = Y->head; memy != NULL; memy = memy->next)
  1185. { tuple = copy_tuple(mpl, memx->tuple);
  1186. for (temp = memy->tuple; temp != NULL; temp = temp->next)
  1187. tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
  1188. temp->sym));
  1189. add_tuple(mpl, Z, tuple);
  1190. }
  1191. }
  1192. delete_elemset(mpl, X);
  1193. delete_elemset(mpl, Y);
  1194. return Z;
  1195. }
  1196. /**********************************************************************/
  1197. /* * * ELEMENTAL VARIABLES * * */
  1198. /**********************************************************************/
  1199. /* (there are no specific routines for elemental variables) */
  1200. /**********************************************************************/
  1201. /* * * LINEAR FORMS * * */
  1202. /**********************************************************************/
  1203. /*----------------------------------------------------------------------
  1204. -- constant_term - create constant term.
  1205. --
  1206. -- This routine creates the linear form, which is a constant term. */
  1207. FORMULA *constant_term(MPL *mpl, double coef)
  1208. { FORMULA *form;
  1209. if (coef == 0.0)
  1210. form = NULL;
  1211. else
  1212. { form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
  1213. form->coef = coef;
  1214. form->var = NULL;
  1215. form->next = NULL;
  1216. }
  1217. return form;
  1218. }
  1219. /*----------------------------------------------------------------------
  1220. -- single_variable - create single variable.
  1221. --
  1222. -- This routine creates the linear form, which is a single elemental
  1223. -- variable. */
  1224. FORMULA *single_variable
  1225. ( MPL *mpl,
  1226. ELEMVAR *var /* referenced */
  1227. )
  1228. { FORMULA *form;
  1229. xassert(var != NULL);
  1230. form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
  1231. form->coef = 1.0;
  1232. form->var = var;
  1233. form->next = NULL;
  1234. return form;
  1235. }
  1236. /*----------------------------------------------------------------------
  1237. -- copy_formula - make copy of linear form.
  1238. --
  1239. -- This routine returns an exact copy of linear form. */
  1240. FORMULA *copy_formula
  1241. ( MPL *mpl,
  1242. FORMULA *form /* not changed */
  1243. )
  1244. { FORMULA *head, *tail;
  1245. if (form == NULL)
  1246. head = NULL;
  1247. else
  1248. { head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
  1249. for (; form != NULL; form = form->next)
  1250. { tail->coef = form->coef;
  1251. tail->var = form->var;
  1252. if (form->next != NULL)
  1253. tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA)));
  1254. }
  1255. tail->next = NULL;
  1256. }
  1257. return head;
  1258. }
  1259. /*----------------------------------------------------------------------
  1260. -- delete_formula - delete linear form.
  1261. --
  1262. -- This routine deletes specified linear form. */
  1263. void delete_formula
  1264. ( MPL *mpl,
  1265. FORMULA *form /* destroyed */
  1266. )
  1267. { FORMULA *temp;
  1268. while (form != NULL)
  1269. { temp = form;
  1270. form = form->next;
  1271. dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
  1272. }
  1273. return;
  1274. }
  1275. /*----------------------------------------------------------------------
  1276. -- linear_comb - linear combination of two linear forms.
  1277. --
  1278. -- This routine computes the linear combination:
  1279. --
  1280. -- a * fx + b * fy,
  1281. --
  1282. -- where a and b are numeric coefficients, fx and fy are linear forms
  1283. -- (destroyed on exit). */
  1284. FORMULA *linear_comb
  1285. ( MPL *mpl,
  1286. double a, FORMULA *fx, /* destroyed */
  1287. double b, FORMULA *fy /* destroyed */
  1288. )
  1289. { FORMULA *form = NULL, *term, *temp;
  1290. double c0 = 0.0;
  1291. for (term = fx; term != NULL; term = term->next)
  1292. { if (term->var == NULL)
  1293. c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef));
  1294. else
  1295. term->var->temp =
  1296. fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef));
  1297. }
  1298. for (term = fy; term != NULL; term = term->next)
  1299. { if (term->var == NULL)
  1300. c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef));
  1301. else
  1302. term->var->temp =
  1303. fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef));
  1304. }
  1305. for (term = fx; term != NULL; term = term->next)
  1306. { if (term->var != NULL && term->var->temp != 0.0)
  1307. { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
  1308. temp->coef = term->var->temp, temp->var = term->var;
  1309. temp->next = form, form = temp;
  1310. term->var->temp = 0.0;
  1311. }
  1312. }
  1313. for (term = fy; term != NULL; term = term->next)
  1314. { if (term->var != NULL && term->var->temp != 0.0)
  1315. { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
  1316. temp->coef = term->var->temp, temp->var = term->var;
  1317. temp->next = form, form = temp;
  1318. term->var->temp = 0.0;
  1319. }
  1320. }
  1321. if (c0 != 0.0)
  1322. { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
  1323. temp->coef = c0, temp->var = NULL;
  1324. temp->next = form, form = temp;
  1325. }
  1326. delete_formula(mpl, fx);
  1327. delete_formula(mpl, fy);
  1328. return form;
  1329. }
  1330. /*----------------------------------------------------------------------
  1331. -- remove_constant - remove constant term from linear form.
  1332. --
  1333. -- This routine removes constant term from linear form and stores its
  1334. -- value to given location. */
  1335. FORMULA *remove_constant
  1336. ( MPL *mpl,
  1337. FORMULA *form, /* destroyed */
  1338. double *coef /* modified */
  1339. )
  1340. { FORMULA *head = NULL, *temp;
  1341. *coef = 0.0;
  1342. while (form != NULL)
  1343. { temp = form;
  1344. form = form->next;
  1345. if (temp->var == NULL)
  1346. { /* constant term */
  1347. *coef = fp_add(mpl, *coef, temp->coef);
  1348. dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
  1349. }
  1350. else
  1351. { /* linear term */
  1352. temp->next = head;
  1353. head = temp;
  1354. }
  1355. }
  1356. return head;
  1357. }
  1358. /*----------------------------------------------------------------------
  1359. -- reduce_terms - reduce identical terms in linear form.
  1360. --
  1361. -- This routine reduces identical terms in specified linear form. */
  1362. FORMULA *reduce_terms
  1363. ( MPL *mpl,
  1364. FORMULA *form /* destroyed */
  1365. )
  1366. { FORMULA *term, *next_term;
  1367. double c0 = 0.0;
  1368. for (term = form; term != NULL; term = term->next)
  1369. { if (term->var == NULL)
  1370. c0 = fp_add(mpl, c0, term->coef);
  1371. else
  1372. term->var->temp = fp_add(mpl, term->var->temp, term->coef);
  1373. }
  1374. next_term = form, form = NULL;
  1375. for (term = next_term; term != NULL; term = next_term)
  1376. { next_term = term->next;
  1377. if (term->var == NULL && c0 != 0.0)
  1378. { term->coef = c0, c0 = 0.0;
  1379. term->next = form, form = term;
  1380. }
  1381. else if (term->var != NULL && term->var->temp != 0.0)
  1382. { term->coef = term->var->temp, term->var->temp = 0.0;
  1383. term->next = form, form = term;
  1384. }
  1385. else
  1386. dmp_free_atom(mpl->formulae, term, sizeof(FORMULA));
  1387. }
  1388. return form;
  1389. }
  1390. /**********************************************************************/
  1391. /* * * ELEMENTAL CONSTRAINTS * * */
  1392. /**********************************************************************/
  1393. /* (there are no specific routines for elemental constraints) */
  1394. /**********************************************************************/
  1395. /* * * GENERIC VALUES * * */
  1396. /**********************************************************************/
  1397. /*----------------------------------------------------------------------
  1398. -- delete_value - delete generic value.
  1399. --
  1400. -- This routine deletes specified generic value.
  1401. --
  1402. -- NOTE: The generic value to be deleted must be valid. */
  1403. void delete_value
  1404. ( MPL *mpl,
  1405. int type,
  1406. VALUE *value /* content destroyed */
  1407. )
  1408. { xassert(value != NULL);
  1409. switch (type)
  1410. { case A_NONE:
  1411. value->none = NULL;
  1412. break;
  1413. case A_NUMERIC:
  1414. value->num = 0.0;
  1415. break;
  1416. case A_SYMBOLIC:
  1417. delete_symbol(mpl, value->sym), value->sym = NULL;
  1418. break;
  1419. case A_LOGICAL:
  1420. value->bit = 0;
  1421. break;
  1422. case A_TUPLE:
  1423. delete_tuple(mpl, value->tuple), value->tuple = NULL;
  1424. break;
  1425. case A_ELEMSET:
  1426. delete_elemset(mpl, value->set), value->set = NULL;
  1427. break;
  1428. case A_ELEMVAR:
  1429. value->var = NULL;
  1430. break;
  1431. case A_FORMULA:
  1432. delete_formula(mpl, value->form), value->form = NULL;
  1433. break;
  1434. case A_ELEMCON:
  1435. value->con = NULL;
  1436. break;
  1437. default:
  1438. xassert(type != type);
  1439. }
  1440. return;
  1441. }
  1442. /**********************************************************************/
  1443. /* * * SYMBOLICALLY INDEXED ARRAYS * * */
  1444. /**********************************************************************/
  1445. /*----------------------------------------------------------------------
  1446. -- create_array - create array.
  1447. --
  1448. -- This routine creates an array of specified type and dimension. Being
  1449. -- created the array is initially empty.
  1450. --
  1451. -- The type indicator determines generic values, which can be assigned
  1452. -- to the array members:
  1453. --
  1454. -- A_NONE - none (members have no assigned values)
  1455. -- A_NUMERIC - floating-point numbers
  1456. -- A_SYMBOLIC - symbols
  1457. -- A_ELEMSET - elemental sets
  1458. -- A_ELEMVAR - elemental variables
  1459. -- A_ELEMCON - elemental constraints
  1460. --
  1461. -- The dimension may be 0, in which case the array consists of the only
  1462. -- member (such arrays represent 0-dimensional objects). */
  1463. ARRAY *create_array(MPL *mpl, int type, int dim)
  1464. { ARRAY *array;
  1465. xassert(type == A_NONE || type == A_NUMERIC ||
  1466. type == A_SYMBOLIC || type == A_ELEMSET ||
  1467. type == A_ELEMVAR || type == A_ELEMCON);
  1468. xassert(dim >= 0);
  1469. array = dmp_get_atom(mpl->arrays, sizeof(ARRAY));
  1470. array->type = type;
  1471. array->dim = dim;
  1472. array->size = 0;
  1473. array->head = NULL;
  1474. array->tail = NULL;
  1475. array->tree = NULL;
  1476. array->prev = NULL;
  1477. array->next = mpl->a_list;
  1478. /* include the array in the global array list */
  1479. if (array->next != NULL) array->next->prev = array;
  1480. mpl->a_list = array;
  1481. return array;
  1482. }
  1483. /*----------------------------------------------------------------------
  1484. -- find_member - find array member with given n-tuple.
  1485. --
  1486. -- This routine finds an array member, which has given n-tuple. If the
  1487. -- array is short, the linear search is used. Otherwise the routine
  1488. -- autimatically creates the search tree (i.e. the array index) to find
  1489. -- members for logarithmic time. */
  1490. static int compare_member_tuples(void *info, const void *key1,
  1491. const void *key2)
  1492. { /* this is an auxiliary routine used to compare keys, which are
  1493. n-tuples assigned to array members */
  1494. return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2);
  1495. }
  1496. MEMBER *find_member
  1497. ( MPL *mpl,
  1498. ARRAY *array, /* not changed */
  1499. TUPLE *tuple /* not changed */
  1500. )
  1501. { MEMBER *memb;
  1502. xassert(array != NULL);
  1503. /* the n-tuple must have the same dimension as the array */
  1504. xassert(tuple_dimen(mpl, tuple) == array->dim);
  1505. /* if the array is large enough, create the search tree and index
  1506. all existing members of the array */
  1507. if (array->size > 30 && array->tree == NULL)
  1508. { array->tree = avl_create_tree(compare_member_tuples, mpl);
  1509. for (memb = array->head; memb != NULL; memb = memb->next)
  1510. avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
  1511. (void *)memb);
  1512. }
  1513. /* find a member, which has the given tuple */
  1514. if (array->tree == NULL)
  1515. { /* the search tree doesn't exist; use the linear search */
  1516. for (memb = array->head; memb != NULL; memb = memb->next)
  1517. if (compare_tuples(mpl, memb->tuple, tuple) == 0) break;
  1518. }
  1519. else
  1520. { /* the search tree exists; use the binary search */
  1521. AVLNODE *node;
  1522. node = avl_find_node(array->tree, tuple);
  1523. memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node));
  1524. }
  1525. return memb;
  1526. }
  1527. /*----------------------------------------------------------------------
  1528. -- add_member - add new member to array.
  1529. --
  1530. -- This routine creates a new member with given n-tuple and adds it to
  1531. -- specified array.
  1532. --
  1533. -- For the sake of efficiency this routine doesn't check whether the
  1534. -- array already contains a member with the given n-tuple or not. Thus,
  1535. -- if necessary, the calling program should use the routine find_member
  1536. -- in order to be sure that the array contains no member with the same
  1537. -- n-tuple, because members with duplicate n-tuples are not allowed.
  1538. --
  1539. -- This routine assigns no generic value to the new member, because the
  1540. -- calling program must do that. */
  1541. MEMBER *add_member
  1542. ( MPL *mpl,
  1543. ARRAY *array, /* modified */
  1544. TUPLE *tuple /* destroyed */
  1545. )
  1546. { MEMBER *memb;
  1547. xassert(array != NULL);
  1548. /* the n-tuple must have the same dimension as the array */
  1549. xassert(tuple_dimen(mpl, tuple) == array->dim);
  1550. /* create new member */
  1551. memb = dmp_get_atom(mpl->members, sizeof(MEMBER));
  1552. memb->tuple = tuple;
  1553. memb->next = NULL;
  1554. memset(&memb->value, '?', sizeof(VALUE));
  1555. /* and append it to the member list */
  1556. array->size++;
  1557. if (array->head == NULL)
  1558. array->head = memb;
  1559. else
  1560. array->tail->next = memb;
  1561. array->tail = memb;
  1562. /* if the search tree exists, index the new member */
  1563. if (array->tree != NULL)
  1564. avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
  1565. (void *)memb);
  1566. return memb;
  1567. }
  1568. /*----------------------------------------------------------------------
  1569. -- delete_array - delete array.
  1570. --
  1571. -- This routine deletes specified array.
  1572. --
  1573. -- Generic values assigned to the array members are not deleted by this
  1574. -- routine. The calling program itself must delete all assigned generic
  1575. -- values before deleting the array. */
  1576. void delete_array
  1577. ( MPL *mpl,
  1578. ARRAY *array /* destroyed */
  1579. )
  1580. { MEMBER *memb;
  1581. xassert(array != NULL);
  1582. /* delete all existing array members */
  1583. while (array->head != NULL)
  1584. { memb = array->head;
  1585. array->head = memb->next;
  1586. delete_tuple(mpl, memb->tuple);
  1587. dmp_free_atom(mpl->members, memb, sizeof(MEMBER));
  1588. }
  1589. /* if the search tree exists, also delete it */
  1590. if (array->tree != NULL) avl_delete_tree(array->tree);
  1591. /* remove the array from the global array list */
  1592. if (array->prev == NULL)
  1593. mpl->a_list = array->next;
  1594. else
  1595. array->prev->next = array->next;
  1596. if (array->next == NULL)
  1597. ;
  1598. else
  1599. array->next->prev = array->prev;
  1600. /* delete the array descriptor */
  1601. dmp_free_atom(mpl->arrays, array, sizeof(ARRAY));
  1602. return;
  1603. }
  1604. /**********************************************************************/
  1605. /* * * DOMAINS AND DUMMY INDICES * * */
  1606. /**********************************************************************/
  1607. /*----------------------------------------------------------------------
  1608. -- assign_dummy_index - assign new value to dummy index.
  1609. --
  1610. -- This routine assigns new value to specified dummy index and, that is
  1611. -- important, invalidates all temporary resultant values, which depends
  1612. -- on that dummy index. */
  1613. void assign_dummy_index
  1614. ( MPL *mpl,
  1615. DOMAIN_SLOT *slot, /* modified */
  1616. SYMBOL *value /* not changed */
  1617. )
  1618. { CODE *leaf, *code;
  1619. xassert(slot != NULL);
  1620. xassert(value != NULL);
  1621. /* delete the current value assigned to the dummy index */
  1622. if (slot->value != NULL)
  1623. { /* if the current value and the new one are identical, actual
  1624. assignment is not needed */
  1625. if (compare_symbols(mpl, slot->value, value) == 0) goto done;
  1626. /* delete a symbol, which is the current value */
  1627. delete_symbol(mpl, slot->value), slot->value = NULL;
  1628. }
  1629. /* now walk through all the pseudo-codes with op = O_INDEX, which
  1630. refer to the dummy index to be changed (these pseudo-codes are
  1631. leaves in the forest of *all* expressions in the database) */
  1632. for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index.
  1633. next)
  1634. { xassert(leaf->op == O_INDEX);
  1635. /* invalidate all resultant values, which depend on the dummy
  1636. index, walking from the current leaf toward the root of the
  1637. corresponding expression tree */
  1638. for (code = leaf; code != NULL; code = code->up)
  1639. { if (code->valid)
  1640. { /* invalidate and delete resultant value */
  1641. code->valid = 0;
  1642. delete_value(mpl, code->type, &code->value);
  1643. }
  1644. }
  1645. }
  1646. /* assign new value to the dummy index */
  1647. slot->value = copy_symbol(mpl, value);
  1648. done: return;
  1649. }
  1650. /*----------------------------------------------------------------------
  1651. -- update_dummy_indices - update current values of dummy indices.
  1652. --
  1653. -- This routine assigns components of "backup" n-tuple to dummy indices
  1654. -- of specified domain block. If no "backup" n-tuple is defined for the
  1655. -- domain block, values of the dummy indices remain untouched. */
  1656. void update_dummy_indices
  1657. ( MPL *mpl,
  1658. DOMAIN_BLOCK *block /* not changed */
  1659. )
  1660. { DOMAIN_SLOT *slot;
  1661. TUPLE *temp;
  1662. if (block->backup != NULL)
  1663. { for (slot = block->list, temp = block->backup; slot != NULL;
  1664. slot = slot->next, temp = temp->next)
  1665. { xassert(temp != NULL);
  1666. xassert(temp->sym != NULL);
  1667. assign_dummy_index(mpl, slot, temp->sym);
  1668. }
  1669. }
  1670. return;
  1671. }
  1672. /*----------------------------------------------------------------------
  1673. -- enter_domain_block - enter domain block.
  1674. --
  1675. -- Let specified domain block have the form:
  1676. --
  1677. -- { ..., (j1, j2, ..., jn) in J, ... }
  1678. --
  1679. -- where j1, j2, ..., jn are dummy indices, J is a basic set.
  1680. --
  1681. -- This routine does the following:
  1682. --
  1683. -- 1. Checks if the given n-tuple is a member of the basic set J. Note
  1684. -- that J being *out of the scope* of the domain block cannot depend
  1685. -- on the dummy indices in the same and inner domain blocks, so it
  1686. -- can be computed before the dummy indices are assigned new values.
  1687. -- If this check fails, the routine returns with non-zero code.
  1688. --
  1689. -- 2. Saves current values of the dummy indices j1, j2, ..., jn.
  1690. --
  1691. -- 3. Assigns new values, which are components of the given n-tuple, to
  1692. -- the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is
  1693. -- larger than n, its extra components n+1, n+2, ... are not used.
  1694. --
  1695. -- 4. Calls the formal routine func which either enters the next domain
  1696. -- block or evaluates some code within the domain scope.
  1697. --
  1698. -- 5. Restores former values of the dummy indices j1, j2, ..., jn.
  1699. --
  1700. -- Since current values assigned to the dummy indices on entry to this
  1701. -- routine are restored on exit, the formal routine func is allowed to
  1702. -- call this routine recursively. */
  1703. int enter_domain_block
  1704. ( MPL *mpl,
  1705. DOMAIN_BLOCK *block, /* not changed */
  1706. TUPLE *tuple, /* not changed */
  1707. void *info, void (*func)(MPL *mpl, void *info)
  1708. )
  1709. { TUPLE *backup;
  1710. int ret = 0;
  1711. /* check if the given n-tuple is a member of the basic set */
  1712. xassert(block->code != NULL);
  1713. if (!is_member(mpl, block->code, tuple))
  1714. { ret = 1;
  1715. goto done;
  1716. }
  1717. /* save reference to "backup" n-tuple, which was used to assign
  1718. current values of the dummy indices (it is sufficient to save
  1719. reference, not value, because that n-tuple is defined in some
  1720. outer level of recursion and therefore cannot be changed on
  1721. this and deeper recursive calls) */
  1722. backup = block->backup;
  1723. /* set up new "backup" n-tuple, which defines new values of the
  1724. dummy indices */
  1725. block->backup = tuple;
  1726. /* assign new values to the dummy indices */
  1727. update_dummy_indices(mpl, block);
  1728. /* call the formal routine that does the rest part of the job */
  1729. func(mpl, info);
  1730. /* restore reference to the former "backup" n-tuple */
  1731. block->backup = backup;
  1732. /* restore former values of the dummy indices; note that if the
  1733. domain block just escaped has no other active instances which
  1734. may exist due to recursion (it is indicated by a null pointer
  1735. to the former n-tuple), former values of the dummy indices are
  1736. undefined; therefore in this case the routine keeps currently
  1737. assigned values of the dummy indices that involves keeping all
  1738. dependent temporary results and thereby, if this domain block
  1739. is not used recursively, allows improving efficiency */
  1740. update_dummy_indices(mpl, block);
  1741. done: return ret;
  1742. }
  1743. /*----------------------------------------------------------------------
  1744. -- eval_within_domain - perform evaluation within domain scope.
  1745. --
  1746. -- This routine assigns new values (symbols) to all dummy indices of
  1747. -- specified domain and calls the formal routine func, which is used to
  1748. -- evaluate some code in the domain scope. Each free dummy index in the
  1749. -- domain is assigned a value specified in the corresponding component
  1750. -- of given n-tuple. Non-free dummy indices are assigned values, which
  1751. -- are computed by this routine.
  1752. --
  1753. -- Number of components in the given n-tuple must be the same as number
  1754. -- of free indices in the domain.
  1755. --
  1756. -- If the given n-tuple is not a member of the domain set, the routine
  1757. -- func is not called, and non-zero code is returned.
  1758. --
  1759. -- For the sake of convenience it is allowed to specify domain as NULL
  1760. -- (then n-tuple also must be 0-tuple, i.e. empty), in which case this
  1761. -- routine just calls the routine func and returns zero.
  1762. --
  1763. -- This routine allows recursive calls from the routine func providing
  1764. -- correct values of dummy indices for each instance.
  1765. --
  1766. -- NOTE: The n-tuple passed to this routine must not be changed by any
  1767. -- other routines called from the formal routine func until this
  1768. -- routine has returned. */
  1769. struct eval_domain_info
  1770. { /* working info used by the routine eval_within_domain */
  1771. DOMAIN *domain;
  1772. /* domain, which has to be entered */
  1773. DOMAIN_BLOCK *block;
  1774. /* domain block, which is currently processed */
  1775. TUPLE *tuple;
  1776. /* tail of original n-tuple, whose components have to be assigned
  1777. to free dummy indices in the current domain block */
  1778. void *info;
  1779. /* transit pointer passed to the formal routine func */
  1780. void (*func)(MPL *mpl, void *info);
  1781. /* routine, which has to be executed in the domain scope */
  1782. int failure;
  1783. /* this flag indicates that given n-tuple is not a member of the
  1784. domain set */
  1785. };
  1786. static void eval_domain_func(MPL *mpl, void *_my_info)
  1787. { /* this routine recursively enters into the domain scope and then
  1788. calls the routine func */
  1789. struct eval_domain_info *my_info = _my_info;
  1790. if (my_info->block != NULL)
  1791. { /* the current domain block to be entered exists */
  1792. DOMAIN_BLOCK *block;
  1793. DOMAIN_SLOT *slot;
  1794. TUPLE *tuple = NULL, *temp = NULL;
  1795. /* save pointer to the current domain block */
  1796. block = my_info->block;
  1797. /* and get ready to enter the next block (if it exists) */
  1798. my_info->block = block->next;
  1799. /* construct temporary n-tuple, whose components correspond to
  1800. dummy indices (slots) of the current domain; components of
  1801. the temporary n-tuple that correspond to free dummy indices
  1802. are assigned references (not values!) to symbols specified
  1803. in the corresponding components of the given n-tuple, while
  1804. other components that correspond to non-free dummy indices
  1805. are assigned symbolic values computed here */
  1806. for (slot = block->list; slot != NULL; slot = slot->next)
  1807. { /* create component that corresponds to the current slot */
  1808. if (tuple == NULL)
  1809. tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
  1810. else
  1811. temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
  1812. if (slot->code == NULL)
  1813. { /* dummy index is free; take reference to symbol, which
  1814. is specified in the corresponding component of given
  1815. n-tuple */
  1816. xassert(my_info->tuple != NULL);
  1817. temp->sym = my_info->tuple->sym;
  1818. xassert(temp->sym != NULL);
  1819. my_info->tuple = my_info->tuple->next;
  1820. }
  1821. else
  1822. { /* dummy index is non-free; compute symbolic value to be
  1823. temporarily assigned to the dummy index */
  1824. temp->sym = eval_symbolic(mpl, slot->code);
  1825. }
  1826. }
  1827. temp->next = NULL;
  1828. /* enter the current domain block */
  1829. if (enter_domain_block(mpl, block, tuple, my_info,
  1830. eval_domain_func)) my_info->failure = 1;
  1831. /* delete temporary n-tuple as well as symbols that correspond
  1832. to non-free dummy indices (they were computed here) */
  1833. for (slot = block->list; slot != NULL; slot = slot->next)
  1834. { xassert(tuple != NULL);
  1835. temp = tuple;
  1836. tuple = tuple->next;
  1837. if (slot->code != NULL)
  1838. { /* dummy index is non-free; delete symbolic value */
  1839. delete_symbol(mpl, temp->sym);
  1840. }
  1841. /* delete component that corresponds to the current slot */
  1842. dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
  1843. }
  1844. }
  1845. else
  1846. { /* there are no more domain blocks, i.e. we have reached the
  1847. domain scope */
  1848. xassert(my_info->tuple == NULL);
  1849. /* check optional predicate specified for the domain */
  1850. if (my_info->domain->code != NULL && !eval_logical(mpl,
  1851. my_info->domain->code))
  1852. { /* the predicate is false */
  1853. my_info->failure = 2;
  1854. }
  1855. else
  1856. { /* the predicate is true; do the job */
  1857. my_info->func(mpl, my_info->info);
  1858. }
  1859. }
  1860. return;
  1861. }
  1862. int eval_within_domain
  1863. ( MPL *mpl,
  1864. DOMAIN *domain, /* not changed */
  1865. TUPLE *tuple, /* not changed */
  1866. void *info, void (*func)(MPL *mpl, void *info)
  1867. )
  1868. { /* this routine performs evaluation within domain scope */
  1869. struct eval_domain_info _my_info, *my_info = &_my_info;
  1870. if (domain == NULL)
  1871. { xassert(tuple == NULL);
  1872. func(mpl, info);
  1873. my_info->failure = 0;
  1874. }
  1875. else
  1876. { xassert(tuple != NULL);
  1877. my_info->domain = domain;
  1878. my_info->block = domain->list;
  1879. my_info->tuple = tuple;
  1880. my_info->info = info;
  1881. my_info->func = func;
  1882. my_info->failure = 0;
  1883. /* enter the very first domain block */
  1884. eval_domain_func(mpl, my_info);
  1885. }
  1886. return my_info->failure;
  1887. }
  1888. /*----------------------------------------------------------------------
  1889. -- loop_within_domain - perform iterations within domain scope.
  1890. --
  1891. -- This routine iteratively assigns new values (symbols) to the dummy
  1892. -- indices of specified domain by enumerating all n-tuples, which are
  1893. -- members of the domain set, and for every n-tuple it calls the formal
  1894. -- routine func to evaluate some code within the domain scope.
  1895. --
  1896. -- If the routine func returns non-zero, enumeration within the domain
  1897. -- is prematurely terminated.
  1898. --
  1899. -- For the sake of convenience it is allowed to specify domain as NULL,
  1900. -- in which case this routine just calls the routine func only once and
  1901. -- returns zero.
  1902. --
  1903. -- This routine allows recursive calls from the routine func providing
  1904. -- correct values of dummy indices for each instance. */
  1905. struct loop_domain_info
  1906. { /* working info used by the routine loop_within_domain */
  1907. DOMAIN *domain;
  1908. /* domain, which has to be entered */
  1909. DOMAIN_BLOCK *block;
  1910. /* domain block, which is currently processed */
  1911. int looping;
  1912. /* clearing this flag leads to terminating enumeration */
  1913. void *info;
  1914. /* transit pointer passed to the formal routine func */
  1915. int (*func)(MPL *mpl, void *info);
  1916. /* routine, which needs to be executed in the domain scope */
  1917. };
  1918. static void loop_domain_func(MPL *mpl, void *_my_info)
  1919. { /* this routine enumerates all n-tuples in the basic set of the
  1920. current domain block, enters recursively into the domain scope
  1921. for every n-tuple, and then calls the routine func */
  1922. struct loop_domain_info *my_info = _my_info;
  1923. if (my_info->block != NULL)
  1924. { /* the current domain block to be entered exists */
  1925. DOMAIN_BLOCK *block;
  1926. DOMAIN_SLOT *slot;
  1927. TUPLE *bound;
  1928. /* save pointer to the current domain block */
  1929. block = my_info->block;
  1930. /* and get ready to enter the next block (if it exists) */
  1931. my_info->block = block->next;
  1932. /* compute symbolic values, at which non-free dummy indices of
  1933. the current domain block are bound; since that values don't
  1934. depend on free dummy indices of the current block, they can
  1935. be computed once out of the enumeration loop */
  1936. bound = create_tuple(mpl);
  1937. for (slot = block->list; slot != NULL; slot = slot->next)
  1938. { if (slot->code != NULL)
  1939. bound = expand_tuple(mpl, bound, eval_symbolic(mpl,
  1940. slot->code));
  1941. }
  1942. /* start enumeration */
  1943. xassert(block->code != NULL);
  1944. if (block->code->op == O_DOTS)
  1945. { /* the basic set is "arithmetic", in which case it doesn't
  1946. need to be computed explicitly */
  1947. TUPLE *tuple;
  1948. int n, j;
  1949. double t0, tf, dt;
  1950. /* compute "parameters" of the basic set */
  1951. t0 = eval_numeric(mpl, block->code->arg.arg.x);
  1952. tf = eval_numeric(mpl, block->code->arg.arg.y);
  1953. if (block->code->arg.arg.z == NULL)
  1954. dt = 1.0;
  1955. else
  1956. dt = eval_numeric(mpl, block->code->arg.arg.z);
  1957. /* determine cardinality of the basic set */
  1958. n = arelset_size(mpl, t0, tf, dt);
  1959. /* create dummy 1-tuple for members of the basic set */
  1960. tuple = expand_tuple(mpl, create_tuple(mpl),
  1961. create_symbol_num(mpl, 0.0));
  1962. /* in case of "arithmetic" set there is exactly one dummy
  1963. index, which cannot be non-free */
  1964. xassert(bound == NULL);
  1965. /* walk through 1-tuples of the basic set */
  1966. for (j = 1; j <= n && my_info->looping; j++)
  1967. { /* construct dummy 1-tuple for the current member */
  1968. tuple->sym->num = arelset_member(mpl, t0, tf, dt, j);
  1969. /* enter the current domain block */
  1970. enter_domain_block(mpl, block, tuple, my_info,
  1971. loop_domain_func);
  1972. }
  1973. /* delete dummy 1-tuple */
  1974. delete_tuple(mpl, tuple);
  1975. }
  1976. else
  1977. { /* the basic set is of general kind, in which case it needs
  1978. to be explicitly computed */
  1979. ELEMSET *set;
  1980. MEMBER *memb;
  1981. TUPLE *temp1, *temp2;
  1982. /* compute the basic set */
  1983. set = eval_elemset(mpl, block->code);
  1984. /* walk through all n-tuples of the basic set */
  1985. for (memb = set->head; memb != NULL && my_info->looping;
  1986. memb = memb->next)
  1987. { /* all components of the current n-tuple that correspond
  1988. to non-free dummy indices must be feasible; otherwise
  1989. the n-tuple is not in the basic set */
  1990. temp1 = memb->tuple;
  1991. temp2 = bound;
  1992. for (slot = block->list; slot != NULL; slot = slot->next)
  1993. { xassert(temp1 != NULL);
  1994. if (slot->code != NULL)
  1995. { /* non-free dummy index */
  1996. xassert(temp2 != NULL);
  1997. if (compare_symbols(mpl, temp1->sym, temp2->sym)
  1998. != 0)
  1999. { /* the n-tuple is not in the basic set */
  2000. goto skip;
  2001. }
  2002. temp2 = temp2->next;
  2003. }
  2004. temp1 = temp1->next;
  2005. }
  2006. xassert(temp1 == NULL);
  2007. xassert(temp2 == NULL);
  2008. /* enter the current domain block */
  2009. enter_domain_block(mpl, block, memb->tuple, my_info,
  2010. loop_domain_func);
  2011. skip: ;
  2012. }
  2013. /* delete the basic set */
  2014. delete_elemset(mpl, set);
  2015. }
  2016. /* delete symbolic values binding non-free dummy indices */
  2017. delete_tuple(mpl, bound);
  2018. /* restore pointer to the current domain block */
  2019. my_info->block = block;
  2020. }
  2021. else
  2022. { /* there are no more domain blocks, i.e. we have reached the
  2023. domain scope */
  2024. /* check optional predicate specified for the domain */
  2025. if (my_info->domain->code != NULL && !eval_logical(mpl,
  2026. my_info->domain->code))
  2027. { /* the predicate is false */
  2028. /* nop */;
  2029. }
  2030. else
  2031. { /* the predicate is true; do the job */
  2032. my_info->looping = !my_info->func(mpl, my_info->info);
  2033. }
  2034. }
  2035. return;
  2036. }
  2037. void loop_within_domain
  2038. ( MPL *mpl,
  2039. DOMAIN *domain, /* not changed */
  2040. void *info, int (*func)(MPL *mpl, void *info)
  2041. )
  2042. { /* this routine performs iterations within domain scope */
  2043. struct loop_domain_info _my_info, *my_info = &_my_info;
  2044. if (domain == NULL)
  2045. func(mpl, info);
  2046. else
  2047. { my_info->domain = domain;
  2048. my_info->block = domain->list;
  2049. my_info->looping = 1;
  2050. my_info->info = info;
  2051. my_info->func = func;
  2052. /* enter the very first domain block */
  2053. loop_domain_func(mpl, my_info);
  2054. }
  2055. return;
  2056. }
  2057. /*----------------------------------------------------------------------
  2058. -- out_of_domain - raise domain exception.
  2059. --
  2060. -- This routine is called when a reference is made to a member of some
  2061. -- model object, but its n-tuple is out of the object domain. */
  2062. void out_of_domain
  2063. ( MPL *mpl,
  2064. char *name, /* not changed */
  2065. TUPLE *tuple /* not changed */
  2066. )
  2067. { xassert(name != NULL);
  2068. xassert(tuple != NULL);
  2069. mpl_error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[',
  2070. tuple));
  2071. /* no return */
  2072. }
  2073. /*----------------------------------------------------------------------
  2074. -- get_domain_tuple - obtain current n-tuple from domain.
  2075. --
  2076. -- This routine constructs n-tuple, whose components are current values
  2077. -- assigned to *free* dummy indices of specified domain.
  2078. --
  2079. -- For the sake of convenience it is allowed to specify domain as NULL,
  2080. -- in which case this routine returns 0-tuple.
  2081. --
  2082. -- NOTE: This routine must not be called out of domain scope. */
  2083. TUPLE *get_domain_tuple
  2084. ( MPL *mpl,
  2085. DOMAIN *domain /* not changed */
  2086. )
  2087. { DOMAIN_BLOCK *block;
  2088. DOMAIN_SLOT *slot;
  2089. TUPLE *tuple;
  2090. tuple = create_tuple(mpl);
  2091. if (domain != NULL)
  2092. { for (block = domain->list; block != NULL; block = block->next)
  2093. { for (slot = block->list; slot != NULL; slot = slot->next)
  2094. { if (slot->code == NULL)
  2095. { xassert(slot->value != NULL);
  2096. tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
  2097. slot->value));
  2098. }
  2099. }
  2100. }
  2101. }
  2102. return tuple;
  2103. }
  2104. /*----------------------------------------------------------------------
  2105. -- clean_domain - clean domain.
  2106. --
  2107. -- This routine cleans specified domain that assumes deleting all stuff
  2108. -- dynamically allocated during the generation phase. */
  2109. void clean_domain(MPL *mpl, DOMAIN *domain)
  2110. { DOMAIN_BLOCK *block;
  2111. DOMAIN_SLOT *slot;
  2112. /* if no domain is specified, do nothing */
  2113. if (domain == NULL) goto done;
  2114. /* clean all domain blocks */
  2115. for (block = domain->list; block != NULL; block = block->next)
  2116. { /* clean all domain slots */
  2117. for (slot = block->list; slot != NULL; slot = slot->next)
  2118. { /* clean pseudo-code for computing bound value */
  2119. clean_code(mpl, slot->code);
  2120. /* delete symbolic value assigned to dummy index */
  2121. if (slot->value != NULL)
  2122. delete_symbol(mpl, slot->value), slot->value = NULL;
  2123. }
  2124. /* clean pseudo-code for computing basic set */
  2125. clean_code(mpl, block->code);
  2126. }
  2127. /* clean pseudo-code for computing domain predicate */
  2128. clean_code(mpl, domain->code);
  2129. done: return;
  2130. }
  2131. /**********************************************************************/
  2132. /* * * MODEL SETS * * */
  2133. /**********************************************************************/
  2134. /*----------------------------------------------------------------------
  2135. -- check_elem_set - check elemental set assigned to set member.
  2136. --
  2137. -- This routine checks if given elemental set being assigned to member
  2138. -- of specified model set satisfies to all restrictions.
  2139. --
  2140. -- NOTE: This routine must not be called out of domain scope. */
  2141. void check_elem_set
  2142. ( MPL *mpl,
  2143. SET *set, /* not changed */
  2144. TUPLE *tuple, /* not changed */
  2145. ELEMSET *refer /* not changed */
  2146. )
  2147. { WITHIN *within;
  2148. MEMBER *memb;
  2149. int eqno;
  2150. /* elemental set must be within all specified supersets */
  2151. for (within = set->within, eqno = 1; within != NULL; within =
  2152. within->next, eqno++)
  2153. { xassert(within->code != NULL);
  2154. for (memb = refer->head; memb != NULL; memb = memb->next)
  2155. { if (!is_member(mpl, within->code, memb->tuple))
  2156. { char buf[255+1];
  2157. strcpy(buf, format_tuple(mpl, '(', memb->tuple));
  2158. xassert(strlen(buf) < sizeof(buf));
  2159. mpl_error(mpl, "%s%s contains %s which not within specified "
  2160. "set; see (%d)", set->name, format_tuple(mpl, '[',
  2161. tuple), buf, eqno);
  2162. }
  2163. }
  2164. }
  2165. return;
  2166. }
  2167. /*----------------------------------------------------------------------
  2168. -- take_member_set - obtain elemental set assigned to set member.
  2169. --
  2170. -- This routine obtains a reference to elemental set assigned to given
  2171. -- member of specified model set and returns it on exit.
  2172. --
  2173. -- NOTE: This routine must not be called out of domain scope. */
  2174. ELEMSET *take_member_set /* returns reference, not value */
  2175. ( MPL *mpl,
  2176. SET *set, /* not changed */
  2177. TUPLE *tuple /* not changed */
  2178. )
  2179. { MEMBER *memb;
  2180. ELEMSET *refer;
  2181. /* find member in the set array */
  2182. memb = find_member(mpl, set->array, tuple);
  2183. if (memb != NULL)
  2184. { /* member exists, so just take the reference */
  2185. refer = memb->value.set;
  2186. }
  2187. else if (set->assign != NULL)
  2188. { /* compute value using assignment expression */
  2189. refer = eval_elemset(mpl, set->assign);
  2190. add: /* check that the elemental set satisfies to all restrictions,
  2191. assign it to new member, and add the member to the array */
  2192. check_elem_set(mpl, set, tuple, refer);
  2193. memb = add_member(mpl, set->array, copy_tuple(mpl, tuple));
  2194. memb->value.set = refer;
  2195. }
  2196. else if (set->option != NULL)
  2197. { /* compute default elemental set */
  2198. refer = eval_elemset(mpl, set->option);
  2199. goto add;
  2200. }
  2201. else
  2202. { /* no value (elemental set) is provided */
  2203. mpl_error(mpl, "no value for %s%s", set->name, format_tuple(mpl,
  2204. '[', tuple));
  2205. }
  2206. return refer;
  2207. }
  2208. /*----------------------------------------------------------------------
  2209. -- eval_member_set - evaluate elemental set assigned to set member.
  2210. --
  2211. -- This routine evaluates a reference to elemental set assigned to given
  2212. -- member of specified model set and returns it on exit. */
  2213. struct eval_set_info
  2214. { /* working info used by the routine eval_member_set */
  2215. SET *set;
  2216. /* model set */
  2217. TUPLE *tuple;
  2218. /* n-tuple, which defines set member */
  2219. MEMBER *memb;
  2220. /* normally this pointer is NULL; the routine uses this pointer
  2221. to check data provided in the data section, in which case it
  2222. points to a member currently checked; this check is performed
  2223. automatically only once when a reference to any member occurs
  2224. for the first time */
  2225. ELEMSET *refer;
  2226. /* evaluated reference to elemental set */
  2227. };
  2228. static void eval_set_func(MPL *mpl, void *_info)
  2229. { /* this is auxiliary routine to work within domain scope */
  2230. struct eval_set_info *info = _info;
  2231. if (info->memb != NULL)
  2232. { /* checking call; check elemental set being assigned */
  2233. check_elem_set(mpl, info->set, info->memb->tuple,
  2234. info->memb->value.set);
  2235. }
  2236. else
  2237. { /* normal call; evaluate member, which has given n-tuple */
  2238. info->refer = take_member_set(mpl, info->set, info->tuple);
  2239. }
  2240. return;
  2241. }
  2242. #if 1 /* 12/XII-2008 */
  2243. static void saturate_set(MPL *mpl, SET *set)
  2244. { GADGET *gadget = set->gadget;
  2245. ELEMSET *data;
  2246. MEMBER *elem, *memb;
  2247. TUPLE *tuple, *work[20];
  2248. int i;
  2249. xprintf("Generating %s...\n", set->name);
  2250. eval_whole_set(mpl, gadget->set);
  2251. /* gadget set must have exactly one member */
  2252. xassert(gadget->set->array != NULL);
  2253. xassert(gadget->set->array->head != NULL);
  2254. xassert(gadget->set->array->head == gadget->set->array->tail);
  2255. data = gadget->set->array->head->value.set;
  2256. xassert(data->type == A_NONE);
  2257. xassert(data->dim == gadget->set->dimen);
  2258. /* walk thru all elements of the plain set */
  2259. for (elem = data->head; elem != NULL; elem = elem->next)
  2260. { /* create a copy of n-tuple */
  2261. tuple = copy_tuple(mpl, elem->tuple);
  2262. /* rearrange component of the n-tuple */
  2263. for (i = 0; i < gadget->set->dimen; i++)
  2264. work[i] = NULL;
  2265. for (i = 0; tuple != NULL; tuple = tuple->next)
  2266. work[gadget->ind[i++]-1] = tuple;
  2267. xassert(i == gadget->set->dimen);
  2268. for (i = 0; i < gadget->set->dimen; i++)
  2269. { xassert(work[i] != NULL);
  2270. work[i]->next = work[i+1];
  2271. }
  2272. /* construct subscript list from first set->dim components */
  2273. if (set->dim == 0)
  2274. tuple = NULL;
  2275. else
  2276. tuple = work[0], work[set->dim-1]->next = NULL;
  2277. /* find corresponding member of the set to be initialized */
  2278. memb = find_member(mpl, set->array, tuple);
  2279. if (memb == NULL)
  2280. { /* not found; add new member to the set and assign it empty
  2281. elemental set */
  2282. memb = add_member(mpl, set->array, tuple);
  2283. memb->value.set = create_elemset(mpl, set->dimen);
  2284. }
  2285. else
  2286. { /* found; free subscript list */
  2287. delete_tuple(mpl, tuple);
  2288. }
  2289. /* construct new n-tuple from rest set->dimen components */
  2290. tuple = work[set->dim];
  2291. xassert(set->dim + set->dimen == gadget->set->dimen);
  2292. work[gadget->set->dimen-1]->next = NULL;
  2293. /* and add it to the elemental set assigned to the member
  2294. (no check for duplicates is needed) */
  2295. add_tuple(mpl, memb->value.set, tuple);
  2296. }
  2297. /* the set has been saturated with data */
  2298. set->data = 1;
  2299. return;
  2300. }
  2301. #endif
  2302. ELEMSET *eval_member_set /* returns reference, not value */
  2303. ( MPL *mpl,
  2304. SET *set, /* not changed */
  2305. TUPLE *tuple /* not changed */
  2306. )
  2307. { /* this routine evaluates set member */
  2308. struct eval_set_info _info, *info = &_info;
  2309. xassert(set->dim == tuple_dimen(mpl, tuple));
  2310. info->set = set;
  2311. info->tuple = tuple;
  2312. #if 1 /* 12/XII-2008 */
  2313. if (set->gadget != NULL && set->data == 0)
  2314. { /* initialize the set with data from a plain set */
  2315. saturate_set(mpl, set);
  2316. }
  2317. #endif
  2318. if (set->data == 1)
  2319. { /* check data, which are provided in the data section, but not
  2320. checked yet */
  2321. /* save pointer to the last array member; note that during the
  2322. check new members may be added beyond the last member due to
  2323. references to the same parameter from default expression as
  2324. well as from expressions that define restricting supersets;
  2325. however, values assigned to the new members will be checked
  2326. by other routine, so we don't need to check them here */
  2327. MEMBER *tail = set->array->tail;
  2328. /* change the data status to prevent infinite recursive loop
  2329. due to references to the same set during the check */
  2330. set->data = 2;
  2331. /* check elemental sets assigned to array members in the data
  2332. section until the marked member has been reached */
  2333. for (info->memb = set->array->head; info->memb != NULL;
  2334. info->memb = info->memb->next)
  2335. { if (eval_within_domain(mpl, set->domain, info->memb->tuple,
  2336. info, eval_set_func))
  2337. out_of_domain(mpl, set->name, info->memb->tuple);
  2338. if (info->memb == tail) break;
  2339. }
  2340. /* the check has been finished */
  2341. }
  2342. /* evaluate member, which has given n-tuple */
  2343. info->memb = NULL;
  2344. if (eval_within_domain(mpl, info->set->domain, info->tuple, info,
  2345. eval_set_func))
  2346. out_of_domain(mpl, set->name, info->tuple);
  2347. /* bring evaluated reference to the calling program */
  2348. return info->refer;
  2349. }
  2350. /*----------------------------------------------------------------------
  2351. -- eval_whole_set - evaluate model set over entire domain.
  2352. --
  2353. -- This routine evaluates all members of specified model set over entire
  2354. -- domain. */
  2355. static int whole_set_func(MPL *mpl, void *info)
  2356. { /* this is auxiliary routine to work within domain scope */
  2357. SET *set = (SET *)info;
  2358. TUPLE *tuple = get_domain_tuple(mpl, set->domain);
  2359. eval_member_set(mpl, set, tuple);
  2360. delete_tuple(mpl, tuple);
  2361. return 0;
  2362. }
  2363. void eval_whole_set(MPL *mpl, SET *set)
  2364. { loop_within_domain(mpl, set->domain, set, whole_set_func);
  2365. return;
  2366. }
  2367. /*----------------------------------------------------------------------
  2368. -- clean set - clean model set.
  2369. --
  2370. -- This routine cleans specified model set that assumes deleting all
  2371. -- stuff dynamically allocated during the generation phase. */
  2372. void clean_set(MPL *mpl, SET *set)
  2373. { WITHIN *within;
  2374. MEMBER *memb;
  2375. /* clean subscript domain */
  2376. clean_domain(mpl, set->domain);
  2377. /* clean pseudo-code for computing supersets */
  2378. for (within = set->within; within != NULL; within = within->next)
  2379. clean_code(mpl, within->code);
  2380. /* clean pseudo-code for computing assigned value */
  2381. clean_code(mpl, set->assign);
  2382. /* clean pseudo-code for computing default value */
  2383. clean_code(mpl, set->option);
  2384. /* reset data status flag */
  2385. set->data = 0;
  2386. /* delete content array */
  2387. for (memb = set->array->head; memb != NULL; memb = memb->next)
  2388. delete_value(mpl, set->array->type, &memb->value);
  2389. delete_array(mpl, set->array), set->array = NULL;
  2390. return;
  2391. }
  2392. /**********************************************************************/
  2393. /* * * MODEL PARAMETERS * * */
  2394. /**********************************************************************/
  2395. /*----------------------------------------------------------------------
  2396. -- check_value_num - check numeric value assigned to parameter member.
  2397. --
  2398. -- This routine checks if numeric value being assigned to some member
  2399. -- of specified numeric model parameter satisfies to all restrictions.
  2400. --
  2401. -- NOTE: This routine must not be called out of domain scope. */
  2402. void check_value_num
  2403. ( MPL *mpl,
  2404. PARAMETER *par, /* not changed */
  2405. TUPLE *tuple, /* not changed */
  2406. double value
  2407. )
  2408. { CONDITION *cond;
  2409. WITHIN *in;
  2410. int eqno;
  2411. /* the value must satisfy to the parameter type */
  2412. switch (par->type)
  2413. { case A_NUMERIC:
  2414. break;
  2415. case A_INTEGER:
  2416. if (value != floor(value))
  2417. mpl_error(mpl, "%s%s = %.*g not integer", par->name,
  2418. format_tuple(mpl, '[', tuple), DBL_DIG, value);
  2419. break;
  2420. case A_BINARY:
  2421. if (!(value == 0.0 || value == 1.0))
  2422. mpl_error(mpl, "%s%s = %.*g not binary", par->name,
  2423. format_tuple(mpl, '[', tuple), DBL_DIG, value);
  2424. break;
  2425. default:
  2426. xassert(par != par);
  2427. }
  2428. /* the value must satisfy to all specified conditions */
  2429. for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
  2430. eqno++)
  2431. { double bound;
  2432. char *rho;
  2433. xassert(cond->code != NULL);
  2434. bound = eval_numeric(mpl, cond->code);
  2435. switch (cond->rho)
  2436. { case O_LT:
  2437. if (!(value < bound))
  2438. { rho = "<";
  2439. err: mpl_error(mpl, "%s%s = %.*g not %s %.*g; see (%d)",
  2440. par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
  2441. value, rho, DBL_DIG, bound, eqno);
  2442. }
  2443. break;
  2444. case O_LE:
  2445. if (!(value <= bound)) { rho = "<="; goto err; }
  2446. break;
  2447. case O_EQ:
  2448. if (!(value == bound)) { rho = "="; goto err; }
  2449. break;
  2450. case O_GE:
  2451. if (!(value >= bound)) { rho = ">="; goto err; }
  2452. break;
  2453. case O_GT:
  2454. if (!(value > bound)) { rho = ">"; goto err; }
  2455. break;
  2456. case O_NE:
  2457. if (!(value != bound)) { rho = "<>"; goto err; }
  2458. break;
  2459. default:
  2460. xassert(cond != cond);
  2461. }
  2462. }
  2463. /* the value must be in all specified supersets */
  2464. for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
  2465. { TUPLE *dummy;
  2466. xassert(in->code != NULL);
  2467. xassert(in->code->dim == 1);
  2468. dummy = expand_tuple(mpl, create_tuple(mpl),
  2469. create_symbol_num(mpl, value));
  2470. if (!is_member(mpl, in->code, dummy))
  2471. mpl_error(mpl, "%s%s = %.*g not in specified set; see (%d)",
  2472. par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
  2473. value, eqno);
  2474. delete_tuple(mpl, dummy);
  2475. }
  2476. return;
  2477. }
  2478. /*----------------------------------------------------------------------
  2479. -- take_member_num - obtain num. value assigned to parameter member.
  2480. --
  2481. -- This routine obtains a numeric value assigned to member of specified
  2482. -- numeric model parameter and returns it on exit.
  2483. --
  2484. -- NOTE: This routine must not be called out of domain scope. */
  2485. double take_member_num
  2486. ( MPL *mpl,
  2487. PARAMETER *par, /* not changed */
  2488. TUPLE *tuple /* not changed */
  2489. )
  2490. { MEMBER *memb;
  2491. double value;
  2492. /* find member in the parameter array */
  2493. memb = find_member(mpl, par->array, tuple);
  2494. if (memb != NULL)
  2495. { /* member exists, so just take its value */
  2496. value = memb->value.num;
  2497. }
  2498. else if (par->assign != NULL)
  2499. { /* compute value using assignment expression */
  2500. value = eval_numeric(mpl, par->assign);
  2501. add: /* check that the value satisfies to all restrictions, assign
  2502. it to new member, and add the member to the array */
  2503. check_value_num(mpl, par, tuple, value);
  2504. memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
  2505. memb->value.num = value;
  2506. }
  2507. else if (par->option != NULL)
  2508. { /* compute default value */
  2509. value = eval_numeric(mpl, par->option);
  2510. goto add;
  2511. }
  2512. else if (par->defval != NULL)
  2513. { /* take default value provided in the data section */
  2514. if (par->defval->str != NULL)
  2515. mpl_error(mpl, "cannot convert %s to floating-point number",
  2516. format_symbol(mpl, par->defval));
  2517. value = par->defval->num;
  2518. goto add;
  2519. }
  2520. else
  2521. { /* no value is provided */
  2522. mpl_error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
  2523. '[', tuple));
  2524. }
  2525. return value;
  2526. }
  2527. /*----------------------------------------------------------------------
  2528. -- eval_member_num - evaluate num. value assigned to parameter member.
  2529. --
  2530. -- This routine evaluates a numeric value assigned to given member of
  2531. -- specified numeric model parameter and returns it on exit. */
  2532. struct eval_num_info
  2533. { /* working info used by the routine eval_member_num */
  2534. PARAMETER *par;
  2535. /* model parameter */
  2536. TUPLE *tuple;
  2537. /* n-tuple, which defines parameter member */
  2538. MEMBER *memb;
  2539. /* normally this pointer is NULL; the routine uses this pointer
  2540. to check data provided in the data section, in which case it
  2541. points to a member currently checked; this check is performed
  2542. automatically only once when a reference to any member occurs
  2543. for the first time */
  2544. double value;
  2545. /* evaluated numeric value */
  2546. };
  2547. static void eval_num_func(MPL *mpl, void *_info)
  2548. { /* this is auxiliary routine to work within domain scope */
  2549. struct eval_num_info *info = _info;
  2550. if (info->memb != NULL)
  2551. { /* checking call; check numeric value being assigned */
  2552. check_value_num(mpl, info->par, info->memb->tuple,
  2553. info->memb->value.num);
  2554. }
  2555. else
  2556. { /* normal call; evaluate member, which has given n-tuple */
  2557. info->value = take_member_num(mpl, info->par, info->tuple);
  2558. }
  2559. return;
  2560. }
  2561. double eval_member_num
  2562. ( MPL *mpl,
  2563. PARAMETER *par, /* not changed */
  2564. TUPLE *tuple /* not changed */
  2565. )
  2566. { /* this routine evaluates numeric parameter member */
  2567. struct eval_num_info _info, *info = &_info;
  2568. xassert(par->type == A_NUMERIC || par->type == A_INTEGER ||
  2569. par->type == A_BINARY);
  2570. xassert(par->dim == tuple_dimen(mpl, tuple));
  2571. info->par = par;
  2572. info->tuple = tuple;
  2573. if (par->data == 1)
  2574. { /* check data, which are provided in the data section, but not
  2575. checked yet */
  2576. /* save pointer to the last array member; note that during the
  2577. check new members may be added beyond the last member due to
  2578. references to the same parameter from default expression as
  2579. well as from expressions that define restricting conditions;
  2580. however, values assigned to the new members will be checked
  2581. by other routine, so we don't need to check them here */
  2582. MEMBER *tail = par->array->tail;
  2583. /* change the data status to prevent infinite recursive loop
  2584. due to references to the same parameter during the check */
  2585. par->data = 2;
  2586. /* check values assigned to array members in the data section
  2587. until the marked member has been reached */
  2588. for (info->memb = par->array->head; info->memb != NULL;
  2589. info->memb = info->memb->next)
  2590. { if (eval_within_domain(mpl, par->domain, info->memb->tuple,
  2591. info, eval_num_func))
  2592. out_of_domain(mpl, par->name, info->memb->tuple);
  2593. if (info->memb == tail) break;
  2594. }
  2595. /* the check has been finished */
  2596. }
  2597. /* evaluate member, which has given n-tuple */
  2598. info->memb = NULL;
  2599. if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
  2600. eval_num_func))
  2601. out_of_domain(mpl, par->name, info->tuple);
  2602. /* bring evaluated value to the calling program */
  2603. return info->value;
  2604. }
  2605. /*----------------------------------------------------------------------
  2606. -- check_value_sym - check symbolic value assigned to parameter member.
  2607. --
  2608. -- This routine checks if symbolic value being assigned to some member
  2609. -- of specified symbolic model parameter satisfies to all restrictions.
  2610. --
  2611. -- NOTE: This routine must not be called out of domain scope. */
  2612. void check_value_sym
  2613. ( MPL *mpl,
  2614. PARAMETER *par, /* not changed */
  2615. TUPLE *tuple, /* not changed */
  2616. SYMBOL *value /* not changed */
  2617. )
  2618. { CONDITION *cond;
  2619. WITHIN *in;
  2620. int eqno;
  2621. /* the value must satisfy to all specified conditions */
  2622. for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
  2623. eqno++)
  2624. { SYMBOL *bound;
  2625. char buf[255+1];
  2626. xassert(cond->code != NULL);
  2627. bound = eval_symbolic(mpl, cond->code);
  2628. switch (cond->rho)
  2629. {
  2630. #if 1 /* 13/VIII-2008 */
  2631. case O_LT:
  2632. if (!(compare_symbols(mpl, value, bound) < 0))
  2633. { strcpy(buf, format_symbol(mpl, bound));
  2634. xassert(strlen(buf) < sizeof(buf));
  2635. mpl_error(mpl, "%s%s = %s not < %s",
  2636. par->name, format_tuple(mpl, '[', tuple),
  2637. format_symbol(mpl, value), buf, eqno);
  2638. }
  2639. break;
  2640. case O_LE:
  2641. if (!(compare_symbols(mpl, value, bound) <= 0))
  2642. { strcpy(buf, format_symbol(mpl, bound));
  2643. xassert(strlen(buf) < sizeof(buf));
  2644. mpl_error(mpl, "%s%s = %s not <= %s",
  2645. par->name, format_tuple(mpl, '[', tuple),
  2646. format_symbol(mpl, value), buf, eqno);
  2647. }
  2648. break;
  2649. #endif
  2650. case O_EQ:
  2651. if (!(compare_symbols(mpl, value, bound) == 0))
  2652. { strcpy(buf, format_symbol(mpl, bound));
  2653. xassert(strlen(buf) < sizeof(buf));
  2654. mpl_error(mpl, "%s%s = %s not = %s",
  2655. par->name, format_tuple(mpl, '[', tuple),
  2656. format_symbol(mpl, value), buf, eqno);
  2657. }
  2658. break;
  2659. #if 1 /* 13/VIII-2008 */
  2660. case O_GE:
  2661. if (!(compare_symbols(mpl, value, bound) >= 0))
  2662. { strcpy(buf, format_symbol(mpl, bound));
  2663. xassert(strlen(buf) < sizeof(buf));
  2664. mpl_error(mpl, "%s%s = %s not >= %s",
  2665. par->name, format_tuple(mpl, '[', tuple),
  2666. format_symbol(mpl, value), buf, eqno);
  2667. }
  2668. break;
  2669. case O_GT:
  2670. if (!(compare_symbols(mpl, value, bound) > 0))
  2671. { strcpy(buf, format_symbol(mpl, bound));
  2672. xassert(strlen(buf) < sizeof(buf));
  2673. mpl_error(mpl, "%s%s = %s not > %s",
  2674. par->name, format_tuple(mpl, '[', tuple),
  2675. format_symbol(mpl, value), buf, eqno);
  2676. }
  2677. break;
  2678. #endif
  2679. case O_NE:
  2680. if (!(compare_symbols(mpl, value, bound) != 0))
  2681. { strcpy(buf, format_symbol(mpl, bound));
  2682. xassert(strlen(buf) < sizeof(buf));
  2683. mpl_error(mpl, "%s%s = %s not <> %s",
  2684. par->name, format_tuple(mpl, '[', tuple),
  2685. format_symbol(mpl, value), buf, eqno);
  2686. }
  2687. break;
  2688. default:
  2689. xassert(cond != cond);
  2690. }
  2691. delete_symbol(mpl, bound);
  2692. }
  2693. /* the value must be in all specified supersets */
  2694. for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
  2695. { TUPLE *dummy;
  2696. xassert(in->code != NULL);
  2697. xassert(in->code->dim == 1);
  2698. dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl,
  2699. value));
  2700. if (!is_member(mpl, in->code, dummy))
  2701. mpl_error(mpl, "%s%s = %s not in specified set; see (%d)",
  2702. par->name, format_tuple(mpl, '[', tuple),
  2703. format_symbol(mpl, value), eqno);
  2704. delete_tuple(mpl, dummy);
  2705. }
  2706. return;
  2707. }
  2708. /*----------------------------------------------------------------------
  2709. -- take_member_sym - obtain symb. value assigned to parameter member.
  2710. --
  2711. -- This routine obtains a symbolic value assigned to member of specified
  2712. -- symbolic model parameter and returns it on exit.
  2713. --
  2714. -- NOTE: This routine must not be called out of domain scope. */
  2715. SYMBOL *take_member_sym /* returns value, not reference */
  2716. ( MPL *mpl,
  2717. PARAMETER *par, /* not changed */
  2718. TUPLE *tuple /* not changed */
  2719. )
  2720. { MEMBER *memb;
  2721. SYMBOL *value;
  2722. /* find member in the parameter array */
  2723. memb = find_member(mpl, par->array, tuple);
  2724. if (memb != NULL)
  2725. { /* member exists, so just take its value */
  2726. value = copy_symbol(mpl, memb->value.sym);
  2727. }
  2728. else if (par->assign != NULL)
  2729. { /* compute value using assignment expression */
  2730. value = eval_symbolic(mpl, par->assign);
  2731. add: /* check that the value satisfies to all restrictions, assign
  2732. it to new member, and add the member to the array */
  2733. check_value_sym(mpl, par, tuple, value);
  2734. memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
  2735. memb->value.sym = copy_symbol(mpl, value);
  2736. }
  2737. else if (par->option != NULL)
  2738. { /* compute default value */
  2739. value = eval_symbolic(mpl, par->option);
  2740. goto add;
  2741. }
  2742. else if (par->defval != NULL)
  2743. { /* take default value provided in the data section */
  2744. value = copy_symbol(mpl, par->defval);
  2745. goto add;
  2746. }
  2747. else
  2748. { /* no value is provided */
  2749. mpl_error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
  2750. '[', tuple));
  2751. }
  2752. return value;
  2753. }
  2754. /*----------------------------------------------------------------------
  2755. -- eval_member_sym - evaluate symb. value assigned to parameter member.
  2756. --
  2757. -- This routine evaluates a symbolic value assigned to given member of
  2758. -- specified symbolic model parameter and returns it on exit. */
  2759. struct eval_sym_info
  2760. { /* working info used by the routine eval_member_sym */
  2761. PARAMETER *par;
  2762. /* model parameter */
  2763. TUPLE *tuple;
  2764. /* n-tuple, which defines parameter member */
  2765. MEMBER *memb;
  2766. /* normally this pointer is NULL; the routine uses this pointer
  2767. to check data provided in the data section, in which case it
  2768. points to a member currently checked; this check is performed
  2769. automatically only once when a reference to any member occurs
  2770. for the first time */
  2771. SYMBOL *value;
  2772. /* evaluated symbolic value */
  2773. };
  2774. static void eval_sym_func(MPL *mpl, void *_info)
  2775. { /* this is auxiliary routine to work within domain scope */
  2776. struct eval_sym_info *info = _info;
  2777. if (info->memb != NULL)
  2778. { /* checking call; check symbolic value being assigned */
  2779. check_value_sym(mpl, info->par, info->memb->tuple,
  2780. info->memb->value.sym);
  2781. }
  2782. else
  2783. { /* normal call; evaluate member, which has given n-tuple */
  2784. info->value = take_member_sym(mpl, info->par, info->tuple);
  2785. }
  2786. return;
  2787. }
  2788. SYMBOL *eval_member_sym /* returns value, not reference */
  2789. ( MPL *mpl,
  2790. PARAMETER *par, /* not changed */
  2791. TUPLE *tuple /* not changed */
  2792. )
  2793. { /* this routine evaluates symbolic parameter member */
  2794. struct eval_sym_info _info, *info = &_info;
  2795. xassert(par->type == A_SYMBOLIC);
  2796. xassert(par->dim == tuple_dimen(mpl, tuple));
  2797. info->par = par;
  2798. info->tuple = tuple;
  2799. if (par->data == 1)
  2800. { /* check data, which are provided in the data section, but not
  2801. checked yet */
  2802. /* save pointer to the last array member; note that during the
  2803. check new members may be added beyond the last member due to
  2804. references to the same parameter from default expression as
  2805. well as from expressions that define restricting conditions;
  2806. however, values assigned to the new members will be checked
  2807. by other routine, so we don't need to check them here */
  2808. MEMBER *tail = par->array->tail;
  2809. /* change the data status to prevent infinite recursive loop
  2810. due to references to the same parameter during the check */
  2811. par->data = 2;
  2812. /* check values assigned to array members in the data section
  2813. until the marked member has been reached */
  2814. for (info->memb = par->array->head; info->memb != NULL;
  2815. info->memb = info->memb->next)
  2816. { if (eval_within_domain(mpl, par->domain, info->memb->tuple,
  2817. info, eval_sym_func))
  2818. out_of_domain(mpl, par->name, info->memb->tuple);
  2819. if (info->memb == tail) break;
  2820. }
  2821. /* the check has been finished */
  2822. }
  2823. /* evaluate member, which has given n-tuple */
  2824. info->memb = NULL;
  2825. if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
  2826. eval_sym_func))
  2827. out_of_domain(mpl, par->name, info->tuple);
  2828. /* bring evaluated value to the calling program */
  2829. return info->value;
  2830. }
  2831. /*----------------------------------------------------------------------
  2832. -- eval_whole_par - evaluate model parameter over entire domain.
  2833. --
  2834. -- This routine evaluates all members of specified model parameter over
  2835. -- entire domain. */
  2836. static int whole_par_func(MPL *mpl, void *info)
  2837. { /* this is auxiliary routine to work within domain scope */
  2838. PARAMETER *par = (PARAMETER *)info;
  2839. TUPLE *tuple = get_domain_tuple(mpl, par->domain);
  2840. switch (par->type)
  2841. { case A_NUMERIC:
  2842. case A_INTEGER:
  2843. case A_BINARY:
  2844. eval_member_num(mpl, par, tuple);
  2845. break;
  2846. case A_SYMBOLIC:
  2847. delete_symbol(mpl, eval_member_sym(mpl, par, tuple));
  2848. break;
  2849. default:
  2850. xassert(par != par);
  2851. }
  2852. delete_tuple(mpl, tuple);
  2853. return 0;
  2854. }
  2855. void eval_whole_par(MPL *mpl, PARAMETER *par)
  2856. { loop_within_domain(mpl, par->domain, par, whole_par_func);
  2857. return;
  2858. }
  2859. /*----------------------------------------------------------------------
  2860. -- clean_parameter - clean model parameter.
  2861. --
  2862. -- This routine cleans specified model parameter that assumes deleting
  2863. -- all stuff dynamically allocated during the generation phase. */
  2864. void clean_parameter(MPL *mpl, PARAMETER *par)
  2865. { CONDITION *cond;
  2866. WITHIN *in;
  2867. MEMBER *memb;
  2868. /* clean subscript domain */
  2869. clean_domain(mpl, par->domain);
  2870. /* clean pseudo-code for computing restricting conditions */
  2871. for (cond = par->cond; cond != NULL; cond = cond->next)
  2872. clean_code(mpl, cond->code);
  2873. /* clean pseudo-code for computing restricting supersets */
  2874. for (in = par->in; in != NULL; in = in->next)
  2875. clean_code(mpl, in->code);
  2876. /* clean pseudo-code for computing assigned value */
  2877. clean_code(mpl, par->assign);
  2878. /* clean pseudo-code for computing default value */
  2879. clean_code(mpl, par->option);
  2880. /* reset data status flag */
  2881. par->data = 0;
  2882. /* delete default symbolic value */
  2883. if (par->defval != NULL)
  2884. delete_symbol(mpl, par->defval), par->defval = NULL;
  2885. /* delete content array */
  2886. for (memb = par->array->head; memb != NULL; memb = memb->next)
  2887. delete_value(mpl, par->array->type, &memb->value);
  2888. delete_array(mpl, par->array), par->array = NULL;
  2889. return;
  2890. }
  2891. /**********************************************************************/
  2892. /* * * MODEL VARIABLES * * */
  2893. /**********************************************************************/
  2894. /*----------------------------------------------------------------------
  2895. -- take_member_var - obtain reference to elemental variable.
  2896. --
  2897. -- This routine obtains a reference to elemental variable assigned to
  2898. -- given member of specified model variable and returns it on exit. If
  2899. -- necessary, new elemental variable is created.
  2900. --
  2901. -- NOTE: This routine must not be called out of domain scope. */
  2902. ELEMVAR *take_member_var /* returns reference */
  2903. ( MPL *mpl,
  2904. VARIABLE *var, /* not changed */
  2905. TUPLE *tuple /* not changed */
  2906. )
  2907. { MEMBER *memb;
  2908. ELEMVAR *refer;
  2909. /* find member in the variable array */
  2910. memb = find_member(mpl, var->array, tuple);
  2911. if (memb != NULL)
  2912. { /* member exists, so just take the reference */
  2913. refer = memb->value.var;
  2914. }
  2915. else
  2916. { /* member is referenced for the first time and therefore does
  2917. not exist; create new elemental variable, assign it to new
  2918. member, and add the member to the variable array */
  2919. memb = add_member(mpl, var->array, copy_tuple(mpl, tuple));
  2920. refer = (memb->value.var =
  2921. dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR)));
  2922. refer->j = 0;
  2923. refer->var = var;
  2924. refer->memb = memb;
  2925. /* compute lower bound */
  2926. if (var->lbnd == NULL)
  2927. refer->lbnd = 0.0;
  2928. else
  2929. refer->lbnd = eval_numeric(mpl, var->lbnd);
  2930. /* compute upper bound */
  2931. if (var->ubnd == NULL)
  2932. refer->ubnd = 0.0;
  2933. else if (var->ubnd == var->lbnd)
  2934. refer->ubnd = refer->lbnd;
  2935. else
  2936. refer->ubnd = eval_numeric(mpl, var->ubnd);
  2937. /* nullify working quantity */
  2938. refer->temp = 0.0;
  2939. #if 1 /* 15/V-2010 */
  2940. /* solution has not been obtained by the solver yet */
  2941. refer->stat = 0;
  2942. refer->prim = refer->dual = 0.0;
  2943. #endif
  2944. }
  2945. return refer;
  2946. }
  2947. /*----------------------------------------------------------------------
  2948. -- eval_member_var - evaluate reference to elemental variable.
  2949. --
  2950. -- This routine evaluates a reference to elemental variable assigned to
  2951. -- member of specified model variable and returns it on exit. */
  2952. struct eval_var_info
  2953. { /* working info used by the routine eval_member_var */
  2954. VARIABLE *var;
  2955. /* model variable */
  2956. TUPLE *tuple;
  2957. /* n-tuple, which defines variable member */
  2958. ELEMVAR *refer;
  2959. /* evaluated reference to elemental variable */
  2960. };
  2961. static void eval_var_func(MPL *mpl, void *_info)
  2962. { /* this is auxiliary routine to work within domain scope */
  2963. struct eval_var_info *info = _info;
  2964. info->refer = take_member_var(mpl, info->var, info->tuple);
  2965. return;
  2966. }
  2967. ELEMVAR *eval_member_var /* returns reference */
  2968. ( MPL *mpl,
  2969. VARIABLE *var, /* not changed */
  2970. TUPLE *tuple /* not changed */
  2971. )
  2972. { /* this routine evaluates variable member */
  2973. struct eval_var_info _info, *info = &_info;
  2974. xassert(var->dim == tuple_dimen(mpl, tuple));
  2975. info->var = var;
  2976. info->tuple = tuple;
  2977. /* evaluate member, which has given n-tuple */
  2978. if (eval_within_domain(mpl, info->var->domain, info->tuple, info,
  2979. eval_var_func))
  2980. out_of_domain(mpl, var->name, info->tuple);
  2981. /* bring evaluated reference to the calling program */
  2982. return info->refer;
  2983. }
  2984. /*----------------------------------------------------------------------
  2985. -- eval_whole_var - evaluate model variable over entire domain.
  2986. --
  2987. -- This routine evaluates all members of specified model variable over
  2988. -- entire domain. */
  2989. static int whole_var_func(MPL *mpl, void *info)
  2990. { /* this is auxiliary routine to work within domain scope */
  2991. VARIABLE *var = (VARIABLE *)info;
  2992. TUPLE *tuple = get_domain_tuple(mpl, var->domain);
  2993. eval_member_var(mpl, var, tuple);
  2994. delete_tuple(mpl, tuple);
  2995. return 0;
  2996. }
  2997. void eval_whole_var(MPL *mpl, VARIABLE *var)
  2998. { loop_within_domain(mpl, var->domain, var, whole_var_func);
  2999. return;
  3000. }
  3001. /*----------------------------------------------------------------------
  3002. -- clean_variable - clean model variable.
  3003. --
  3004. -- This routine cleans specified model variable that assumes deleting
  3005. -- all stuff dynamically allocated during the generation phase. */
  3006. void clean_variable(MPL *mpl, VARIABLE *var)
  3007. { MEMBER *memb;
  3008. /* clean subscript domain */
  3009. clean_domain(mpl, var->domain);
  3010. /* clean code for computing lower bound */
  3011. clean_code(mpl, var->lbnd);
  3012. /* clean code for computing upper bound */
  3013. if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd);
  3014. /* delete content array */
  3015. for (memb = var->array->head; memb != NULL; memb = memb->next)
  3016. dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR));
  3017. delete_array(mpl, var->array), var->array = NULL;
  3018. return;
  3019. }
  3020. /**********************************************************************/
  3021. /* * * MODEL CONSTRAINTS AND OBJECTIVES * * */
  3022. /**********************************************************************/
  3023. /*----------------------------------------------------------------------
  3024. -- take_member_con - obtain reference to elemental constraint.
  3025. --
  3026. -- This routine obtains a reference to elemental constraint assigned
  3027. -- to given member of specified model constraint and returns it on exit.
  3028. -- If necessary, new elemental constraint is created.
  3029. --
  3030. -- NOTE: This routine must not be called out of domain scope. */
  3031. ELEMCON *take_member_con /* returns reference */
  3032. ( MPL *mpl,
  3033. CONSTRAINT *con, /* not changed */
  3034. TUPLE *tuple /* not changed */
  3035. )
  3036. { MEMBER *memb;
  3037. ELEMCON *refer;
  3038. /* find member in the constraint array */
  3039. memb = find_member(mpl, con->array, tuple);
  3040. if (memb != NULL)
  3041. { /* member exists, so just take the reference */
  3042. refer = memb->value.con;
  3043. }
  3044. else
  3045. { /* member is referenced for the first time and therefore does
  3046. not exist; create new elemental constraint, assign it to new
  3047. member, and add the member to the constraint array */
  3048. memb = add_member(mpl, con->array, copy_tuple(mpl, tuple));
  3049. refer = (memb->value.con =
  3050. dmp_get_atom(mpl->elemcons, sizeof(ELEMCON)));
  3051. refer->i = 0;
  3052. refer->con = con;
  3053. refer->memb = memb;
  3054. /* compute linear form */
  3055. xassert(con->code != NULL);
  3056. refer->form = eval_formula(mpl, con->code);
  3057. /* compute lower and upper bounds */
  3058. if (con->lbnd == NULL && con->ubnd == NULL)
  3059. { /* objective has no bounds */
  3060. double temp;
  3061. xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE);
  3062. /* carry the constant term to the right-hand side */
  3063. refer->form = remove_constant(mpl, refer->form, &temp);
  3064. refer->lbnd = refer->ubnd = - temp;
  3065. }
  3066. else if (con->lbnd != NULL && con->ubnd == NULL)
  3067. { /* constraint a * x + b >= c * y + d is transformed to the
  3068. standard form a * x - c * y >= d - b */
  3069. double temp;
  3070. xassert(con->type == A_CONSTRAINT);
  3071. refer->form = linear_comb(mpl,
  3072. +1.0, refer->form,
  3073. -1.0, eval_formula(mpl, con->lbnd));
  3074. refer->form = remove_constant(mpl, refer->form, &temp);
  3075. refer->lbnd = - temp;
  3076. refer->ubnd = 0.0;
  3077. }
  3078. else if (con->lbnd == NULL && con->ubnd != NULL)
  3079. { /* constraint a * x + b <= c * y + d is transformed to the
  3080. standard form a * x - c * y <= d - b */
  3081. double temp;
  3082. xassert(con->type == A_CONSTRAINT);
  3083. refer->form = linear_comb(mpl,
  3084. +1.0, refer->form,
  3085. -1.0, eval_formula(mpl, con->ubnd));
  3086. refer->form = remove_constant(mpl, refer->form, &temp);
  3087. refer->lbnd = 0.0;
  3088. refer->ubnd = - temp;
  3089. }
  3090. else if (con->lbnd == con->ubnd)
  3091. { /* constraint a * x + b = c * y + d is transformed to the
  3092. standard form a * x - c * y = d - b */
  3093. double temp;
  3094. xassert(con->type == A_CONSTRAINT);
  3095. refer->form = linear_comb(mpl,
  3096. +1.0, refer->form,
  3097. -1.0, eval_formula(mpl, con->lbnd));
  3098. refer->form = remove_constant(mpl, refer->form, &temp);
  3099. refer->lbnd = refer->ubnd = - temp;
  3100. }
  3101. else
  3102. { /* ranged constraint c <= a * x + b <= d is transformed to
  3103. the standard form c - b <= a * x <= d - b */
  3104. double temp, temp1, temp2;
  3105. xassert(con->type == A_CONSTRAINT);
  3106. refer->form = remove_constant(mpl, refer->form, &temp);
  3107. xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd),
  3108. &temp1) == NULL);
  3109. xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd),
  3110. &temp2) == NULL);
  3111. refer->lbnd = fp_sub(mpl, temp1, temp);
  3112. refer->ubnd = fp_sub(mpl, temp2, temp);
  3113. }
  3114. #if 1 /* 15/V-2010 */
  3115. /* solution has not been obtained by the solver yet */
  3116. refer->stat = 0;
  3117. refer->prim = refer->dual = 0.0;
  3118. #endif
  3119. }
  3120. return refer;
  3121. }
  3122. /*----------------------------------------------------------------------
  3123. -- eval_member_con - evaluate reference to elemental constraint.
  3124. --
  3125. -- This routine evaluates a reference to elemental constraint assigned
  3126. -- to member of specified model constraint and returns it on exit. */
  3127. struct eval_con_info
  3128. { /* working info used by the routine eval_member_con */
  3129. CONSTRAINT *con;
  3130. /* model constraint */
  3131. TUPLE *tuple;
  3132. /* n-tuple, which defines constraint member */
  3133. ELEMCON *refer;
  3134. /* evaluated reference to elemental constraint */
  3135. };
  3136. static void eval_con_func(MPL *mpl, void *_info)
  3137. { /* this is auxiliary routine to work within domain scope */
  3138. struct eval_con_info *info = _info;
  3139. info->refer = take_member_con(mpl, info->con, info->tuple);
  3140. return;
  3141. }
  3142. ELEMCON *eval_member_con /* returns reference */
  3143. ( MPL *mpl,
  3144. CONSTRAINT *con, /* not changed */
  3145. TUPLE *tuple /* not changed */
  3146. )
  3147. { /* this routine evaluates constraint member */
  3148. struct eval_con_info _info, *info = &_info;
  3149. xassert(con->dim == tuple_dimen(mpl, tuple));
  3150. info->con = con;
  3151. info->tuple = tuple;
  3152. /* evaluate member, which has given n-tuple */
  3153. if (eval_within_domain(mpl, info->con->domain, info->tuple, info,
  3154. eval_con_func))
  3155. out_of_domain(mpl, con->name, info->tuple);
  3156. /* bring evaluated reference to the calling program */
  3157. return info->refer;
  3158. }
  3159. /*----------------------------------------------------------------------
  3160. -- eval_whole_con - evaluate model constraint over entire domain.
  3161. --
  3162. -- This routine evaluates all members of specified model constraint over
  3163. -- entire domain. */
  3164. static int whole_con_func(MPL *mpl, void *info)
  3165. { /* this is auxiliary routine to work within domain scope */
  3166. CONSTRAINT *con = (CONSTRAINT *)info;
  3167. TUPLE *tuple = get_domain_tuple(mpl, con->domain);
  3168. eval_member_con(mpl, con, tuple);
  3169. delete_tuple(mpl, tuple);
  3170. return 0;
  3171. }
  3172. void eval_whole_con(MPL *mpl, CONSTRAINT *con)
  3173. { loop_within_domain(mpl, con->domain, con, whole_con_func);
  3174. return;
  3175. }
  3176. /*----------------------------------------------------------------------
  3177. -- clean_constraint - clean model constraint.
  3178. --
  3179. -- This routine cleans specified model constraint that assumes deleting
  3180. -- all stuff dynamically allocated during the generation phase. */
  3181. void clean_constraint(MPL *mpl, CONSTRAINT *con)
  3182. { MEMBER *memb;
  3183. /* clean subscript domain */
  3184. clean_domain(mpl, con->domain);
  3185. /* clean code for computing main linear form */
  3186. clean_code(mpl, con->code);
  3187. /* clean code for computing lower bound */
  3188. clean_code(mpl, con->lbnd);
  3189. /* clean code for computing upper bound */
  3190. if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd);
  3191. /* delete content array */
  3192. for (memb = con->array->head; memb != NULL; memb = memb->next)
  3193. { delete_formula(mpl, memb->value.con->form);
  3194. dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON));
  3195. }
  3196. delete_array(mpl, con->array), con->array = NULL;
  3197. return;
  3198. }
  3199. /**********************************************************************/
  3200. /* * * PSEUDO-CODE * * */
  3201. /**********************************************************************/
  3202. /*----------------------------------------------------------------------
  3203. -- eval_numeric - evaluate pseudo-code to determine numeric value.
  3204. --
  3205. -- This routine evaluates specified pseudo-code to determine resultant
  3206. -- numeric value, which is returned on exit. */
  3207. struct iter_num_info
  3208. { /* working info used by the routine iter_num_func */
  3209. CODE *code;
  3210. /* pseudo-code for iterated operation to be performed */
  3211. double value;
  3212. /* resultant value */
  3213. };
  3214. static int iter_num_func(MPL *mpl, void *_info)
  3215. { /* this is auxiliary routine used to perform iterated operation
  3216. on numeric "integrand" within domain scope */
  3217. struct iter_num_info *info = _info;
  3218. double temp;
  3219. temp = eval_numeric(mpl, info->code->arg.loop.x);
  3220. switch (info->code->op)
  3221. { case O_SUM:
  3222. /* summation over domain */
  3223. info->value = fp_add(mpl, info->value, temp);
  3224. break;
  3225. case O_PROD:
  3226. /* multiplication over domain */
  3227. info->value = fp_mul(mpl, info->value, temp);
  3228. break;
  3229. case O_MINIMUM:
  3230. /* minimum over domain */
  3231. if (info->value > temp) info->value = temp;
  3232. break;
  3233. case O_MAXIMUM:
  3234. /* maximum over domain */
  3235. if (info->value < temp) info->value = temp;
  3236. break;
  3237. default:
  3238. xassert(info != info);
  3239. }
  3240. return 0;
  3241. }
  3242. double eval_numeric(MPL *mpl, CODE *code)
  3243. { double value;
  3244. xassert(code != NULL);
  3245. xassert(code->type == A_NUMERIC);
  3246. xassert(code->dim == 0);
  3247. /* if the operation has a side effect, invalidate and delete the
  3248. resultant value */
  3249. if (code->vflag && code->valid)
  3250. { code->valid = 0;
  3251. delete_value(mpl, code->type, &code->value);
  3252. }
  3253. /* if resultant value is valid, no evaluation is needed */
  3254. if (code->valid)
  3255. { value = code->value.num;
  3256. goto done;
  3257. }
  3258. /* evaluate pseudo-code recursively */
  3259. switch (code->op)
  3260. { case O_NUMBER:
  3261. /* take floating-point number */
  3262. value = code->arg.num;
  3263. break;
  3264. case O_MEMNUM:
  3265. /* take member of numeric parameter */
  3266. { TUPLE *tuple;
  3267. ARG_LIST *e;
  3268. tuple = create_tuple(mpl);
  3269. for (e = code->arg.par.list; e != NULL; e = e->next)
  3270. tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
  3271. e->x));
  3272. value = eval_member_num(mpl, code->arg.par.par, tuple);
  3273. delete_tuple(mpl, tuple);
  3274. }
  3275. break;
  3276. case O_MEMVAR:
  3277. /* take computed value of elemental variable */
  3278. { TUPLE *tuple;
  3279. ARG_LIST *e;
  3280. #if 1 /* 15/V-2010 */
  3281. ELEMVAR *var;
  3282. #endif
  3283. tuple = create_tuple(mpl);
  3284. for (e = code->arg.var.list; e != NULL; e = e->next)
  3285. tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
  3286. e->x));
  3287. #if 0 /* 15/V-2010 */
  3288. value = eval_member_var(mpl, code->arg.var.var, tuple)
  3289. ->value;
  3290. #else
  3291. var = eval_member_var(mpl, code->arg.var.var, tuple);
  3292. switch (code->arg.var.suff)
  3293. { case DOT_LB:
  3294. if (var->var->lbnd == NULL)
  3295. value = -DBL_MAX;
  3296. else
  3297. value = var->lbnd;
  3298. break;
  3299. case DOT_UB:
  3300. if (var->var->ubnd == NULL)
  3301. value = +DBL_MAX;
  3302. else
  3303. value = var->ubnd;
  3304. break;
  3305. case DOT_STATUS:
  3306. value = var->stat;
  3307. break;
  3308. case DOT_VAL:
  3309. value = var->prim;
  3310. break;
  3311. case DOT_DUAL:
  3312. value = var->dual;
  3313. break;
  3314. default:
  3315. xassert(code != code);
  3316. }
  3317. #endif
  3318. delete_tuple(mpl, tuple);
  3319. }
  3320. break;
  3321. #if 1 /* 15/V-2010 */
  3322. case O_MEMCON:
  3323. /* take computed value of elemental constraint */
  3324. { TUPLE *tuple;
  3325. ARG_LIST *e;
  3326. ELEMCON *con;
  3327. tuple = create_tuple(mpl);
  3328. for (e = code->arg.con.list; e != NULL; e = e->next)
  3329. tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
  3330. e->x));
  3331. con = eval_member_con(mpl, code->arg.con.con, tuple);
  3332. switch (code->arg.con.suff)
  3333. { case DOT_LB:
  3334. if (con->con->lbnd == NULL)
  3335. value = -DBL_MAX;
  3336. else
  3337. value = con->lbnd;
  3338. break;
  3339. case DOT_UB:
  3340. if (con->con->ubnd == NULL)
  3341. value = +DBL_MAX;
  3342. else
  3343. value = con->ubnd;
  3344. break;
  3345. case DOT_STATUS:
  3346. value = con->stat;
  3347. break;
  3348. case DOT_VAL:
  3349. value = con->prim;
  3350. break;
  3351. case DOT_DUAL:
  3352. value = con->dual;
  3353. break;
  3354. default:
  3355. xassert(code != code);
  3356. }
  3357. delete_tuple(mpl, tuple);
  3358. }
  3359. break;
  3360. #endif
  3361. case O_IRAND224:
  3362. /* pseudo-random in [0, 2^24-1] */
  3363. value = fp_irand224(mpl);
  3364. break;
  3365. case O_UNIFORM01:
  3366. /* pseudo-random in [0, 1) */
  3367. value = fp_uniform01(mpl);
  3368. break;
  3369. case O_NORMAL01:
  3370. /* gaussian random, mu = 0, sigma = 1 */
  3371. value = fp_normal01(mpl);
  3372. break;
  3373. case O_GMTIME:
  3374. /* current calendar time */
  3375. value = fn_gmtime(mpl);
  3376. break;
  3377. case O_CVTNUM:
  3378. /* conversion to numeric */
  3379. { SYMBOL *sym;
  3380. sym = eval_symbolic(mpl, code->arg.arg.x);
  3381. #if 0 /* 23/XI-2008 */
  3382. if (sym->str != NULL)
  3383. mpl_error(mpl, "cannot convert %s to floating-point numbe"
  3384. "r", format_symbol(mpl, sym));
  3385. value = sym->num;
  3386. #else
  3387. if (sym->str == NULL)
  3388. value = sym->num;
  3389. else
  3390. { if (str2num(sym->str, &value))
  3391. mpl_error(mpl, "cannot convert %s to floating-point nu"
  3392. "mber", format_symbol(mpl, sym));
  3393. }
  3394. #endif
  3395. delete_symbol(mpl, sym);
  3396. }
  3397. break;
  3398. case O_PLUS:
  3399. /* unary plus */
  3400. value = + eval_numeric(mpl, code->arg.arg.x);
  3401. break;
  3402. case O_MINUS:
  3403. /* unary minus */
  3404. value = - eval_numeric(mpl, code->arg.arg.x);
  3405. break;
  3406. case O_ABS:
  3407. /* absolute value */
  3408. value = fabs(eval_numeric(mpl, code->arg.arg.x));
  3409. break;
  3410. case O_CEIL:
  3411. /* round upward ("ceiling of x") */
  3412. value = ceil(eval_numeric(mpl, code->arg.arg.x));
  3413. break;
  3414. case O_FLOOR:
  3415. /* round downward ("floor of x") */
  3416. value = floor(eval_numeric(mpl, code->arg.arg.x));
  3417. break;
  3418. case O_EXP:
  3419. /* base-e exponential */
  3420. value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x));
  3421. break;
  3422. case O_LOG:
  3423. /* natural logarithm */
  3424. value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x));
  3425. break;
  3426. case O_LOG10:
  3427. /* common (decimal) logarithm */
  3428. value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x));
  3429. break;
  3430. case O_SQRT:
  3431. /* square root */
  3432. value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x));
  3433. break;
  3434. case O_SIN:
  3435. /* trigonometric sine */
  3436. value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x));
  3437. break;
  3438. case O_COS:
  3439. /* trigonometric cosine */
  3440. value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x));
  3441. break;
  3442. case O_ATAN:
  3443. /* trigonometric arctangent (one argument) */
  3444. value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x));
  3445. break;
  3446. case O_ATAN2:
  3447. /* trigonometric arctangent (two arguments) */
  3448. value = fp_atan2(mpl,
  3449. eval_numeric(mpl, code->arg.arg.x),
  3450. eval_numeric(mpl, code->arg.arg.y));
  3451. break;
  3452. case O_ROUND:
  3453. /* round to nearest integer */
  3454. value = fp_round(mpl,
  3455. eval_numeric(mpl, code->arg.arg.x), 0.0);
  3456. break;
  3457. case O_ROUND2:
  3458. /* round to n fractional digits */
  3459. value = fp_round(mpl,
  3460. eval_numeric(mpl, code->arg.arg.x),
  3461. eval_numeric(mpl, code->arg.arg.y));
  3462. break;
  3463. case O_TRUNC:
  3464. /* truncate to nearest integer */
  3465. value = fp_trunc(mpl,
  3466. eval_numeric(mpl, code->arg.arg.x), 0.0);
  3467. break;
  3468. case O_TRUNC2:
  3469. /* truncate to n fractional digits */
  3470. value = fp_trunc(mpl,
  3471. eval_numeric(mpl, code->arg.arg.x),
  3472. eval_numeric(mpl, code->arg.arg.y));
  3473. break;
  3474. case O_ADD:
  3475. /* addition */
  3476. value = fp_add(mpl,
  3477. eval_numeric(mpl, code->arg.arg.x),
  3478. eval_numeric(mpl, code->arg.arg.y));
  3479. break;
  3480. case O_SUB:
  3481. /* subtraction */
  3482. value = fp_sub(mpl,
  3483. eval_numeric(mpl, code->arg.arg.x),
  3484. eval_numeric(mpl, code->arg.arg.y));
  3485. break;
  3486. case O_LESS:
  3487. /* non-negative subtraction */
  3488. value = fp_less(mpl,
  3489. eval_numeric(mpl, code->arg.arg.x),
  3490. eval_numeric(mpl, code->arg.arg.y));
  3491. break;
  3492. case O_MUL:
  3493. /* multiplication */
  3494. value = fp_mul(mpl,
  3495. eval_numeric(mpl, code->arg.arg.x),
  3496. eval_numeric(mpl, code->arg.arg.y));
  3497. break;
  3498. case O_DIV:
  3499. /* division */
  3500. value = fp_div(mpl,
  3501. eval_numeric(mpl, code->arg.arg.x),
  3502. eval_numeric(mpl, code->arg.arg.y));
  3503. break;
  3504. case O_IDIV:
  3505. /* quotient of exact division */
  3506. value = fp_idiv(mpl,
  3507. eval_numeric(mpl, code->arg.arg.x),
  3508. eval_numeric(mpl, code->arg.arg.y));
  3509. break;
  3510. case O_MOD:
  3511. /* remainder of exact division */
  3512. value = fp_mod(mpl,
  3513. eval_numeric(mpl, code->arg.arg.x),
  3514. eval_numeric(mpl, code->arg.arg.y));
  3515. break;
  3516. case O_POWER:
  3517. /* exponentiation (raise to power) */
  3518. value = fp_power(mpl,
  3519. eval_numeric(mpl, code->arg.arg.x),
  3520. eval_numeric(mpl, code->arg.arg.y));
  3521. break;
  3522. case O_UNIFORM:
  3523. /* pseudo-random in [a, b) */
  3524. value = fp_uniform(mpl,
  3525. eval_numeric(mpl, code->arg.arg.x),
  3526. eval_numeric(mpl, code->arg.arg.y));
  3527. break;
  3528. case O_NORMAL:
  3529. /* gaussian random, given mu and sigma */
  3530. value = fp_normal(mpl,
  3531. eval_numeric(mpl, code->arg.arg.x),
  3532. eval_numeric(mpl, code->arg.arg.y));
  3533. break;
  3534. case O_CARD:
  3535. { ELEMSET *set;
  3536. set = eval_elemset(mpl, code->arg.arg.x);
  3537. value = set->size;
  3538. delete_array(mpl, set);
  3539. }
  3540. break;
  3541. case O_LENGTH:
  3542. { SYMBOL *sym;
  3543. char str[MAX_LENGTH+1];
  3544. sym = eval_symbolic(mpl, code->arg.arg.x);
  3545. if (sym->str == NULL)
  3546. sprintf(str, "%.*g", DBL_DIG, sym->num);
  3547. else
  3548. fetch_string(mpl, sym->str, str);
  3549. delete_symbol(mpl, sym);
  3550. value = strlen(str);
  3551. }
  3552. break;
  3553. case O_STR2TIME:
  3554. { SYMBOL *sym;
  3555. char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
  3556. sym = eval_symbolic(mpl, code->arg.arg.x);
  3557. if (sym->str == NULL)
  3558. sprintf(str, "%.*g", DBL_DIG, sym->num);
  3559. else
  3560. fetch_string(mpl, sym->str, str);
  3561. delete_symbol(mpl, sym);
  3562. sym = eval_symbolic(mpl, code->arg.arg.y);
  3563. if (sym->str == NULL)
  3564. sprintf(fmt, "%.*g", DBL_DIG, sym->num);
  3565. else
  3566. fetch_string(mpl, sym->str, fmt);
  3567. delete_symbol(mpl, sym);
  3568. value = fn_str2time(mpl, str, fmt);
  3569. }
  3570. break;
  3571. case O_FORK:
  3572. /* if-then-else */
  3573. if (eval_logical(mpl, code->arg.arg.x))
  3574. value = eval_numeric(mpl, code->arg.arg.y);
  3575. else if (code->arg.arg.z == NULL)
  3576. value = 0.0;
  3577. else
  3578. value = eval_numeric(mpl, code->arg.arg.z);
  3579. break;
  3580. case O_MIN:
  3581. /* minimal value (n-ary) */
  3582. { ARG_LIST *e;
  3583. double temp;
  3584. value = +DBL_MAX;
  3585. for (e = code->arg.list; e != NULL; e = e->next)
  3586. { temp = eval_numeric(mpl, e->x);
  3587. if (value > temp) value = temp;
  3588. }
  3589. }
  3590. break;
  3591. case O_MAX:
  3592. /* maximal value (n-ary) */
  3593. { ARG_LIST *e;
  3594. double temp;
  3595. value = -DBL_MAX;
  3596. for (e = code->arg.list; e != NULL; e = e->next)
  3597. { temp = eval_numeric(mpl, e->x);
  3598. if (value < temp) value = temp;
  3599. }
  3600. }
  3601. break;
  3602. case O_SUM:
  3603. /* summation over domain */
  3604. { struct iter_num_info _info, *info = &_info;
  3605. info->code = code;
  3606. info->value = 0.0;
  3607. loop_within_domain(mpl, code->arg.loop.domain, info,
  3608. iter_num_func);
  3609. value = info->value;
  3610. }
  3611. break;
  3612. case O_PROD:
  3613. /* multiplication over domain */
  3614. { struct iter_num_info _info, *info = &_info;
  3615. info->code = code;
  3616. info->value = 1.0;
  3617. loop_within_domain(mpl, code->arg.loop.domain, info,
  3618. iter_num_func);
  3619. value = info->value;
  3620. }
  3621. break;
  3622. case O_MINIMUM:
  3623. /* minimum over domain */
  3624. { struct iter_num_info _info, *info = &_info;
  3625. info->code = code;
  3626. info->value = +DBL_MAX;
  3627. loop_within_domain(mpl, code->arg.loop.domain, info,
  3628. iter_num_func);
  3629. if (info->value == +DBL_MAX)
  3630. mpl_error(mpl, "min{} over empty set; result undefined");
  3631. value = info->value;
  3632. }
  3633. break;
  3634. case O_MAXIMUM:
  3635. /* maximum over domain */
  3636. { struct iter_num_info _info, *info = &_info;
  3637. info->code = code;
  3638. info->value = -DBL_MAX;
  3639. loop_within_domain(mpl, code->arg.loop.domain, info,
  3640. iter_num_func);
  3641. if (info->value == -DBL_MAX)
  3642. mpl_error(mpl, "max{} over empty set; result undefined");
  3643. value = info->value;
  3644. }
  3645. break;
  3646. default:
  3647. xassert(code != code);
  3648. }
  3649. /* save resultant value */
  3650. xassert(!code->valid);
  3651. code->valid = 1;
  3652. code->value.num = value;
  3653. done: return value;
  3654. }
  3655. /*----------------------------------------------------------------------
  3656. -- eval_symbolic - evaluate pseudo-code to determine symbolic value.
  3657. --
  3658. -- This routine evaluates specified pseudo-code to determine resultant
  3659. -- symbolic value, which is returned on exit. */
  3660. SYMBOL *eval_symbolic(MPL *mpl, CODE *code)
  3661. { SYMBOL *value;
  3662. xassert(code != NULL);
  3663. xassert(code->type == A_SYMBOLIC);
  3664. xassert(code->dim == 0);
  3665. /* if the operation has a side effect, invalidate and delete the
  3666. resultant value */
  3667. if (code->vflag && code->valid)
  3668. { code->valid = 0;
  3669. delete_value(mpl, code->type, &code->value);
  3670. }
  3671. /* if resultant value is valid, no evaluation is needed */
  3672. if (code->valid)
  3673. { value = copy_symbol(mpl, code->value.sym);
  3674. goto done;
  3675. }
  3676. /* evaluate pseudo-code recursively */
  3677. switch (code->op)
  3678. { case O_STRING:
  3679. /* take character string */
  3680. value = create_symbol_str(mpl, create_string(mpl,
  3681. code->arg.str));
  3682. break;
  3683. case O_INDEX:
  3684. /* take dummy index */
  3685. xassert(code->arg.index.slot->value != NULL);
  3686. value = copy_symbol(mpl, code->arg.index.slot->value);
  3687. break;
  3688. case O_MEMSYM:
  3689. /* take member of symbolic parameter */
  3690. { TUPLE *tuple;
  3691. ARG_LIST *e;
  3692. tuple = create_tuple(mpl);
  3693. for (e = code->arg.par.list; e != NULL; e = e->next)
  3694. tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
  3695. e->x));
  3696. value = eval_member_sym(mpl, code->arg.par.par, tuple);
  3697. delete_tuple(mpl, tuple);
  3698. }
  3699. break;
  3700. case O_CVTSYM:
  3701. /* conversion to symbolic */
  3702. value = create_symbol_num(mpl, eval_numeric(mpl,
  3703. code->arg.arg.x));
  3704. break;
  3705. case O_CONCAT:
  3706. /* concatenation */
  3707. value = concat_symbols(mpl,
  3708. eval_symbolic(mpl, code->arg.arg.x),
  3709. eval_symbolic(mpl, code->arg.arg.y));
  3710. break;
  3711. case O_FORK:
  3712. /* if-then-else */
  3713. if (eval_logical(mpl, code->arg.arg.x))
  3714. value = eval_symbolic(mpl, code->arg.arg.y);
  3715. else if (code->arg.arg.z == NULL)
  3716. value = create_symbol_num(mpl, 0.0);
  3717. else
  3718. value = eval_symbolic(mpl, code->arg.arg.z);
  3719. break;
  3720. case O_SUBSTR:
  3721. case O_SUBSTR3:
  3722. { double pos, len;
  3723. char str[MAX_LENGTH+1];
  3724. value = eval_symbolic(mpl, code->arg.arg.x);
  3725. if (value->str == NULL)
  3726. sprintf(str, "%.*g", DBL_DIG, value->num);
  3727. else
  3728. fetch_string(mpl, value->str, str);
  3729. delete_symbol(mpl, value);
  3730. if (code->op == O_SUBSTR)
  3731. { pos = eval_numeric(mpl, code->arg.arg.y);
  3732. if (pos != floor(pos))
  3733. mpl_error(mpl, "substr('...', %.*g); non-integer secon"
  3734. "d argument", DBL_DIG, pos);
  3735. if (pos < 1 || pos > strlen(str) + 1)
  3736. mpl_error(mpl, "substr('...', %.*g); substring out of "
  3737. "range", DBL_DIG, pos);
  3738. }
  3739. else
  3740. { pos = eval_numeric(mpl, code->arg.arg.y);
  3741. len = eval_numeric(mpl, code->arg.arg.z);
  3742. if (pos != floor(pos) || len != floor(len))
  3743. mpl_error(mpl, "substr('...', %.*g, %.*g); non-integer"
  3744. " second and/or third argument", DBL_DIG, pos,
  3745. DBL_DIG, len);
  3746. if (pos < 1 || len < 0 || pos + len > strlen(str) + 1)
  3747. mpl_error(mpl, "substr('...', %.*g, %.*g); substring o"
  3748. "ut of range", DBL_DIG, pos, DBL_DIG, len);
  3749. str[(int)pos + (int)len - 1] = '\0';
  3750. }
  3751. value = create_symbol_str(mpl, create_string(mpl, str +
  3752. (int)pos - 1));
  3753. }
  3754. break;
  3755. case O_TIME2STR:
  3756. { double num;
  3757. SYMBOL *sym;
  3758. char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
  3759. num = eval_numeric(mpl, code->arg.arg.x);
  3760. sym = eval_symbolic(mpl, code->arg.arg.y);
  3761. if (sym->str == NULL)
  3762. sprintf(fmt, "%.*g", DBL_DIG, sym->num);
  3763. else
  3764. fetch_string(mpl, sym->str, fmt);
  3765. delete_symbol(mpl, sym);
  3766. fn_time2str(mpl, str, num, fmt);
  3767. value = create_symbol_str(mpl, create_string(mpl, str));
  3768. }
  3769. break;
  3770. default:
  3771. xassert(code != code);
  3772. }
  3773. /* save resultant value */
  3774. xassert(!code->valid);
  3775. code->valid = 1;
  3776. code->value.sym = copy_symbol(mpl, value);
  3777. done: return value;
  3778. }
  3779. /*----------------------------------------------------------------------
  3780. -- eval_logical - evaluate pseudo-code to determine logical value.
  3781. --
  3782. -- This routine evaluates specified pseudo-code to determine resultant
  3783. -- logical value, which is returned on exit. */
  3784. struct iter_log_info
  3785. { /* working info used by the routine iter_log_func */
  3786. CODE *code;
  3787. /* pseudo-code for iterated operation to be performed */
  3788. int value;
  3789. /* resultant value */
  3790. };
  3791. static int iter_log_func(MPL *mpl, void *_info)
  3792. { /* this is auxiliary routine used to perform iterated operation
  3793. on logical "integrand" within domain scope */
  3794. struct iter_log_info *info = _info;
  3795. int ret = 0;
  3796. switch (info->code->op)
  3797. { case O_FORALL:
  3798. /* conjunction over domain */
  3799. info->value &= eval_logical(mpl, info->code->arg.loop.x);
  3800. if (!info->value) ret = 1;
  3801. break;
  3802. case O_EXISTS:
  3803. /* disjunction over domain */
  3804. info->value |= eval_logical(mpl, info->code->arg.loop.x);
  3805. if (info->value) ret = 1;
  3806. break;
  3807. default:
  3808. xassert(info != info);
  3809. }
  3810. return ret;
  3811. }
  3812. int eval_logical(MPL *mpl, CODE *code)
  3813. { int value;
  3814. xassert(code->type == A_LOGICAL);
  3815. xassert(code->dim == 0);
  3816. /* if the operation has a side effect, invalidate and delete the
  3817. resultant value */
  3818. if (code->vflag && code->valid)
  3819. { code->valid = 0;
  3820. delete_value(mpl, code->type, &code->value);
  3821. }
  3822. /* if resultant value is valid, no evaluation is needed */
  3823. if (code->valid)
  3824. { value = code->value.bit;
  3825. goto done;
  3826. }
  3827. /* evaluate pseudo-code recursively */
  3828. switch (code->op)
  3829. { case O_CVTLOG:
  3830. /* conversion to logical */
  3831. value = (eval_numeric(mpl, code->arg.arg.x) != 0.0);
  3832. break;
  3833. case O_NOT:
  3834. /* negation (logical "not") */
  3835. value = !eval_logical(mpl, code->arg.arg.x);
  3836. break;
  3837. case O_LT:
  3838. /* comparison on 'less than' */
  3839. #if 0 /* 02/VIII-2008 */
  3840. value = (eval_numeric(mpl, code->arg.arg.x) <
  3841. eval_numeric(mpl, code->arg.arg.y));
  3842. #else
  3843. xassert(code->arg.arg.x != NULL);
  3844. if (code->arg.arg.x->type == A_NUMERIC)
  3845. value = (eval_numeric(mpl, code->arg.arg.x) <
  3846. eval_numeric(mpl, code->arg.arg.y));
  3847. else
  3848. { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
  3849. SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
  3850. value = (compare_symbols(mpl, sym1, sym2) < 0);
  3851. delete_symbol(mpl, sym1);
  3852. delete_symbol(mpl, sym2);
  3853. }
  3854. #endif
  3855. break;
  3856. case O_LE:
  3857. /* comparison on 'not greater than' */
  3858. #if 0 /* 02/VIII-2008 */
  3859. value = (eval_numeric(mpl, code->arg.arg.x) <=
  3860. eval_numeric(mpl, code->arg.arg.y));
  3861. #else
  3862. xassert(code->arg.arg.x != NULL);
  3863. if (code->arg.arg.x->type == A_NUMERIC)
  3864. value = (eval_numeric(mpl, code->arg.arg.x) <=
  3865. eval_numeric(mpl, code->arg.arg.y));
  3866. else
  3867. { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
  3868. SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
  3869. value = (compare_symbols(mpl, sym1, sym2) <= 0);
  3870. delete_symbol(mpl, sym1);
  3871. delete_symbol(mpl, sym2);
  3872. }
  3873. #endif
  3874. break;
  3875. case O_EQ:
  3876. /* comparison on 'equal to' */
  3877. xassert(code->arg.arg.x != NULL);
  3878. if (code->arg.arg.x->type == A_NUMERIC)
  3879. value = (eval_numeric(mpl, code->arg.arg.x) ==
  3880. eval_numeric(mpl, code->arg.arg.y));
  3881. else
  3882. { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
  3883. SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
  3884. value = (compare_symbols(mpl, sym1, sym2) == 0);
  3885. delete_symbol(mpl, sym1);
  3886. delete_symbol(mpl, sym2);
  3887. }
  3888. break;
  3889. case O_GE:
  3890. /* comparison on 'not less than' */
  3891. #if 0 /* 02/VIII-2008 */
  3892. value = (eval_numeric(mpl, code->arg.arg.x) >=
  3893. eval_numeric(mpl, code->arg.arg.y));
  3894. #else
  3895. xassert(code->arg.arg.x != NULL);
  3896. if (code->arg.arg.x->type == A_NUMERIC)
  3897. value = (eval_numeric(mpl, code->arg.arg.x) >=
  3898. eval_numeric(mpl, code->arg.arg.y));
  3899. else
  3900. { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
  3901. SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
  3902. value = (compare_symbols(mpl, sym1, sym2) >= 0);
  3903. delete_symbol(mpl, sym1);
  3904. delete_symbol(mpl, sym2);
  3905. }
  3906. #endif
  3907. break;
  3908. case O_GT:
  3909. /* comparison on 'greater than' */
  3910. #if 0 /* 02/VIII-2008 */
  3911. value = (eval_numeric(mpl, code->arg.arg.x) >
  3912. eval_numeric(mpl, code->arg.arg.y));
  3913. #else
  3914. xassert(code->arg.arg.x != NULL);
  3915. if (code->arg.arg.x->type == A_NUMERIC)
  3916. value = (eval_numeric(mpl, code->arg.arg.x) >
  3917. eval_numeric(mpl, code->arg.arg.y));
  3918. else
  3919. { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
  3920. SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
  3921. value = (compare_symbols(mpl, sym1, sym2) > 0);
  3922. delete_symbol(mpl, sym1);
  3923. delete_symbol(mpl, sym2);
  3924. }
  3925. #endif
  3926. break;
  3927. case O_NE:
  3928. /* comparison on 'not equal to' */
  3929. xassert(code->arg.arg.x != NULL);
  3930. if (code->arg.arg.x->type == A_NUMERIC)
  3931. value = (eval_numeric(mpl, code->arg.arg.x) !=
  3932. eval_numeric(mpl, code->arg.arg.y));
  3933. else
  3934. { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
  3935. SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
  3936. value = (compare_symbols(mpl, sym1, sym2) != 0);
  3937. delete_symbol(mpl, sym1);
  3938. delete_symbol(mpl, sym2);
  3939. }
  3940. break;
  3941. case O_AND:
  3942. /* conjunction (logical "and") */
  3943. value = eval_logical(mpl, code->arg.arg.x) &&
  3944. eval_logical(mpl, code->arg.arg.y);
  3945. break;
  3946. case O_OR:
  3947. /* disjunction (logical "or") */
  3948. value = eval_logical(mpl, code->arg.arg.x) ||
  3949. eval_logical(mpl, code->arg.arg.y);
  3950. break;
  3951. case O_IN:
  3952. /* test on 'x in Y' */
  3953. { TUPLE *tuple;
  3954. tuple = eval_tuple(mpl, code->arg.arg.x);
  3955. value = is_member(mpl, code->arg.arg.y, tuple);
  3956. delete_tuple(mpl, tuple);
  3957. }
  3958. break;
  3959. case O_NOTIN:
  3960. /* test on 'x not in Y' */
  3961. { TUPLE *tuple;
  3962. tuple = eval_tuple(mpl, code->arg.arg.x);
  3963. value = !is_member(mpl, code->arg.arg.y, tuple);
  3964. delete_tuple(mpl, tuple);
  3965. }
  3966. break;
  3967. case O_WITHIN:
  3968. /* test on 'X within Y' */
  3969. { ELEMSET *set;
  3970. MEMBER *memb;
  3971. set = eval_elemset(mpl, code->arg.arg.x);
  3972. value = 1;
  3973. for (memb = set->head; memb != NULL; memb = memb->next)
  3974. { if (!is_member(mpl, code->arg.arg.y, memb->tuple))
  3975. { value = 0;
  3976. break;
  3977. }
  3978. }
  3979. delete_elemset(mpl, set);
  3980. }
  3981. break;
  3982. case O_NOTWITHIN:
  3983. /* test on 'X not within Y' */
  3984. { ELEMSET *set;
  3985. MEMBER *memb;
  3986. set = eval_elemset(mpl, code->arg.arg.x);
  3987. value = 1;
  3988. for (memb = set->head; memb != NULL; memb = memb->next)
  3989. { if (is_member(mpl, code->arg.arg.y, memb->tuple))
  3990. { value = 0;
  3991. break;
  3992. }
  3993. }
  3994. delete_elemset(mpl, set);
  3995. }
  3996. break;
  3997. case O_FORALL:
  3998. /* conjunction (A-quantification) */
  3999. { struct iter_log_info _info, *info = &_info;
  4000. info->code = code;
  4001. info->value = 1;
  4002. loop_within_domain(mpl, code->arg.loop.domain, info,
  4003. iter_log_func);
  4004. value = info->value;
  4005. }
  4006. break;
  4007. case O_EXISTS:
  4008. /* disjunction (E-quantification) */
  4009. { struct iter_log_info _info, *info = &_info;
  4010. info->code = code;
  4011. info->value = 0;
  4012. loop_within_domain(mpl, code->arg.loop.domain, info,
  4013. iter_log_func);
  4014. value = info->value;
  4015. }
  4016. break;
  4017. default:
  4018. xassert(code != code);
  4019. }
  4020. /* save resultant value */
  4021. xassert(!code->valid);
  4022. code->valid = 1;
  4023. code->value.bit = value;
  4024. done: return value;
  4025. }
  4026. /*----------------------------------------------------------------------
  4027. -- eval_tuple - evaluate pseudo-code to construct n-tuple.
  4028. --
  4029. -- This routine evaluates specified pseudo-code to construct resultant
  4030. -- n-tuple, which is returned on exit. */
  4031. TUPLE *eval_tuple(MPL *mpl, CODE *code)
  4032. { TUPLE *value;
  4033. xassert(code != NULL);
  4034. xassert(code->type == A_TUPLE);
  4035. xassert(code->dim > 0);
  4036. /* if the operation has a side effect, invalidate and delete the
  4037. resultant value */
  4038. if (code->vflag && code->valid)
  4039. { code->valid = 0;
  4040. delete_value(mpl, code->type, &code->value);
  4041. }
  4042. /* if resultant value is valid, no evaluation is needed */
  4043. if (code->valid)
  4044. { value = copy_tuple(mpl, code->value.tuple);
  4045. goto done;
  4046. }
  4047. /* evaluate pseudo-code recursively */
  4048. switch (code->op)
  4049. { case O_TUPLE:
  4050. /* make n-tuple */
  4051. { ARG_LIST *e;
  4052. value = create_tuple(mpl);
  4053. for (e = code->arg.list; e != NULL; e = e->next)
  4054. value = expand_tuple(mpl, value, eval_symbolic(mpl,
  4055. e->x));
  4056. }
  4057. break;
  4058. case O_CVTTUP:
  4059. /* convert to 1-tuple */
  4060. value = expand_tuple(mpl, create_tuple(mpl),
  4061. eval_symbolic(mpl, code->arg.arg.x));
  4062. break;
  4063. default:
  4064. xassert(code != code);
  4065. }
  4066. /* save resultant value */
  4067. xassert(!code->valid);
  4068. code->valid = 1;
  4069. code->value.tuple = copy_tuple(mpl, value);
  4070. done: return value;
  4071. }
  4072. /*----------------------------------------------------------------------
  4073. -- eval_elemset - evaluate pseudo-code to construct elemental set.
  4074. --
  4075. -- This routine evaluates specified pseudo-code to construct resultant
  4076. -- elemental set, which is returned on exit. */
  4077. struct iter_set_info
  4078. { /* working info used by the routine iter_set_func */
  4079. CODE *code;
  4080. /* pseudo-code for iterated operation to be performed */
  4081. ELEMSET *value;
  4082. /* resultant value */
  4083. };
  4084. static int iter_set_func(MPL *mpl, void *_info)
  4085. { /* this is auxiliary routine used to perform iterated operation
  4086. on n-tuple "integrand" within domain scope */
  4087. struct iter_set_info *info = _info;
  4088. TUPLE *tuple;
  4089. switch (info->code->op)
  4090. { case O_SETOF:
  4091. /* compute next n-tuple and add it to the set; in this case
  4092. duplicate n-tuples are silently ignored */
  4093. tuple = eval_tuple(mpl, info->code->arg.loop.x);
  4094. if (find_tuple(mpl, info->value, tuple) == NULL)
  4095. add_tuple(mpl, info->value, tuple);
  4096. else
  4097. delete_tuple(mpl, tuple);
  4098. break;
  4099. case O_BUILD:
  4100. /* construct next n-tuple using current values assigned to
  4101. *free* dummy indices as its components and add it to the
  4102. set; in this case duplicate n-tuples cannot appear */
  4103. add_tuple(mpl, info->value, get_domain_tuple(mpl,
  4104. info->code->arg.loop.domain));
  4105. break;
  4106. default:
  4107. xassert(info != info);
  4108. }
  4109. return 0;
  4110. }
  4111. ELEMSET *eval_elemset(MPL *mpl, CODE *code)
  4112. { ELEMSET *value;
  4113. xassert(code != NULL);
  4114. xassert(code->type == A_ELEMSET);
  4115. xassert(code->dim > 0);
  4116. /* if the operation has a side effect, invalidate and delete the
  4117. resultant value */
  4118. if (code->vflag && code->valid)
  4119. { code->valid = 0;
  4120. delete_value(mpl, code->type, &code->value);
  4121. }
  4122. /* if resultant value is valid, no evaluation is needed */
  4123. if (code->valid)
  4124. { value = copy_elemset(mpl, code->value.set);
  4125. goto done;
  4126. }
  4127. /* evaluate pseudo-code recursively */
  4128. switch (code->op)
  4129. { case O_MEMSET:
  4130. /* take member of set */
  4131. { TUPLE *tuple;
  4132. ARG_LIST *e;
  4133. tuple = create_tuple(mpl);
  4134. for (e = code->arg.set.list; e != NULL; e = e->next)
  4135. tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
  4136. e->x));
  4137. value = copy_elemset(mpl,
  4138. eval_member_set(mpl, code->arg.set.set, tuple));
  4139. delete_tuple(mpl, tuple);
  4140. }
  4141. break;
  4142. case O_MAKE:
  4143. /* make elemental set of n-tuples */
  4144. { ARG_LIST *e;
  4145. value = create_elemset(mpl, code->dim);
  4146. for (e = code->arg.list; e != NULL; e = e->next)
  4147. check_then_add(mpl, value, eval_tuple(mpl, e->x));
  4148. }
  4149. break;
  4150. case O_UNION:
  4151. /* union of two elemental sets */
  4152. value = set_union(mpl,
  4153. eval_elemset(mpl, code->arg.arg.x),
  4154. eval_elemset(mpl, code->arg.arg.y));
  4155. break;
  4156. case O_DIFF:
  4157. /* difference between two elemental sets */
  4158. value = set_diff(mpl,
  4159. eval_elemset(mpl, code->arg.arg.x),
  4160. eval_elemset(mpl, code->arg.arg.y));
  4161. break;
  4162. case O_SYMDIFF:
  4163. /* symmetric difference between two elemental sets */
  4164. value = set_symdiff(mpl,
  4165. eval_elemset(mpl, code->arg.arg.x),
  4166. eval_elemset(mpl, code->arg.arg.y));
  4167. break;
  4168. case O_INTER:
  4169. /* intersection of two elemental sets */
  4170. value = set_inter(mpl,
  4171. eval_elemset(mpl, code->arg.arg.x),
  4172. eval_elemset(mpl, code->arg.arg.y));
  4173. break;
  4174. case O_CROSS:
  4175. /* cross (Cartesian) product of two elemental sets */
  4176. value = set_cross(mpl,
  4177. eval_elemset(mpl, code->arg.arg.x),
  4178. eval_elemset(mpl, code->arg.arg.y));
  4179. break;
  4180. case O_DOTS:
  4181. /* build "arithmetic" elemental set */
  4182. value = create_arelset(mpl,
  4183. eval_numeric(mpl, code->arg.arg.x),
  4184. eval_numeric(mpl, code->arg.arg.y),
  4185. code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl,
  4186. code->arg.arg.z));
  4187. break;
  4188. case O_FORK:
  4189. /* if-then-else */
  4190. if (eval_logical(mpl, code->arg.arg.x))
  4191. value = eval_elemset(mpl, code->arg.arg.y);
  4192. else
  4193. value = eval_elemset(mpl, code->arg.arg.z);
  4194. break;
  4195. case O_SETOF:
  4196. /* compute elemental set */
  4197. { struct iter_set_info _info, *info = &_info;
  4198. info->code = code;
  4199. info->value = create_elemset(mpl, code->dim);
  4200. loop_within_domain(mpl, code->arg.loop.domain, info,
  4201. iter_set_func);
  4202. value = info->value;
  4203. }
  4204. break;
  4205. case O_BUILD:
  4206. /* build elemental set identical to domain set */
  4207. { struct iter_set_info _info, *info = &_info;
  4208. info->code = code;
  4209. info->value = create_elemset(mpl, code->dim);
  4210. loop_within_domain(mpl, code->arg.loop.domain, info,
  4211. iter_set_func);
  4212. value = info->value;
  4213. }
  4214. break;
  4215. default:
  4216. xassert(code != code);
  4217. }
  4218. /* save resultant value */
  4219. xassert(!code->valid);
  4220. code->valid = 1;
  4221. code->value.set = copy_elemset(mpl, value);
  4222. done: return value;
  4223. }
  4224. /*----------------------------------------------------------------------
  4225. -- is_member - check if n-tuple is in set specified by pseudo-code.
  4226. --
  4227. -- This routine checks if given n-tuple is a member of elemental set
  4228. -- specified in the form of pseudo-code (i.e. by expression).
  4229. --
  4230. -- The n-tuple may have more components that dimension of the elemental
  4231. -- set, in which case the extra components are ignored. */
  4232. static void null_func(MPL *mpl, void *info)
  4233. { /* this is dummy routine used to enter the domain scope */
  4234. xassert(mpl == mpl);
  4235. xassert(info == NULL);
  4236. return;
  4237. }
  4238. int is_member(MPL *mpl, CODE *code, TUPLE *tuple)
  4239. { int value;
  4240. xassert(code != NULL);
  4241. xassert(code->type == A_ELEMSET);
  4242. xassert(code->dim > 0);
  4243. xassert(tuple != NULL);
  4244. switch (code->op)
  4245. { case O_MEMSET:
  4246. /* check if given n-tuple is member of elemental set, which
  4247. is assigned to member of model set */
  4248. { ARG_LIST *e;
  4249. TUPLE *temp;
  4250. ELEMSET *set;
  4251. /* evaluate reference to elemental set */
  4252. temp = create_tuple(mpl);
  4253. for (e = code->arg.set.list; e != NULL; e = e->next)
  4254. temp = expand_tuple(mpl, temp, eval_symbolic(mpl,
  4255. e->x));
  4256. set = eval_member_set(mpl, code->arg.set.set, temp);
  4257. delete_tuple(mpl, temp);
  4258. /* check if the n-tuple is contained in the set array */
  4259. temp = build_subtuple(mpl, tuple, set->dim);
  4260. value = (find_tuple(mpl, set, temp) != NULL);
  4261. delete_tuple(mpl, temp);
  4262. }
  4263. break;
  4264. case O_MAKE:
  4265. /* check if given n-tuple is member of literal set */
  4266. { ARG_LIST *e;
  4267. TUPLE *temp, *that;
  4268. value = 0;
  4269. temp = build_subtuple(mpl, tuple, code->dim);
  4270. for (e = code->arg.list; e != NULL; e = e->next)
  4271. { that = eval_tuple(mpl, e->x);
  4272. value = (compare_tuples(mpl, temp, that) == 0);
  4273. delete_tuple(mpl, that);
  4274. if (value) break;
  4275. }
  4276. delete_tuple(mpl, temp);
  4277. }
  4278. break;
  4279. case O_UNION:
  4280. value = is_member(mpl, code->arg.arg.x, tuple) ||
  4281. is_member(mpl, code->arg.arg.y, tuple);
  4282. break;
  4283. case O_DIFF:
  4284. value = is_member(mpl, code->arg.arg.x, tuple) &&
  4285. !is_member(mpl, code->arg.arg.y, tuple);
  4286. break;
  4287. case O_SYMDIFF:
  4288. { int in1 = is_member(mpl, code->arg.arg.x, tuple);
  4289. int in2 = is_member(mpl, code->arg.arg.y, tuple);
  4290. value = (in1 && !in2) || (!in1 && in2);
  4291. }
  4292. break;
  4293. case O_INTER:
  4294. value = is_member(mpl, code->arg.arg.x, tuple) &&
  4295. is_member(mpl, code->arg.arg.y, tuple);
  4296. break;
  4297. case O_CROSS:
  4298. { int j;
  4299. value = is_member(mpl, code->arg.arg.x, tuple);
  4300. if (value)
  4301. { for (j = 1; j <= code->arg.arg.x->dim; j++)
  4302. { xassert(tuple != NULL);
  4303. tuple = tuple->next;
  4304. }
  4305. value = is_member(mpl, code->arg.arg.y, tuple);
  4306. }
  4307. }
  4308. break;
  4309. case O_DOTS:
  4310. /* check if given 1-tuple is member of "arithmetic" set */
  4311. { int j;
  4312. double x, t0, tf, dt;
  4313. xassert(code->dim == 1);
  4314. /* compute "parameters" of the "arithmetic" set */
  4315. t0 = eval_numeric(mpl, code->arg.arg.x);
  4316. tf = eval_numeric(mpl, code->arg.arg.y);
  4317. if (code->arg.arg.z == NULL)
  4318. dt = 1.0;
  4319. else
  4320. dt = eval_numeric(mpl, code->arg.arg.z);
  4321. /* make sure the parameters are correct */
  4322. arelset_size(mpl, t0, tf, dt);
  4323. /* if component of 1-tuple is symbolic, not numeric, the
  4324. 1-tuple cannot be member of "arithmetic" set */
  4325. xassert(tuple->sym != NULL);
  4326. if (tuple->sym->str != NULL)
  4327. { value = 0;
  4328. break;
  4329. }
  4330. /* determine numeric value of the component */
  4331. x = tuple->sym->num;
  4332. /* if the component value is out of the set range, the
  4333. 1-tuple is not in the set */
  4334. if (dt > 0.0 && !(t0 <= x && x <= tf) ||
  4335. dt < 0.0 && !(tf <= x && x <= t0))
  4336. { value = 0;
  4337. break;
  4338. }
  4339. /* estimate ordinal number of the 1-tuple in the set */
  4340. j = (int)(((x - t0) / dt) + 0.5) + 1;
  4341. /* perform the main check */
  4342. value = (arelset_member(mpl, t0, tf, dt, j) == x);
  4343. }
  4344. break;
  4345. case O_FORK:
  4346. /* check if given n-tuple is member of conditional set */
  4347. if (eval_logical(mpl, code->arg.arg.x))
  4348. value = is_member(mpl, code->arg.arg.y, tuple);
  4349. else
  4350. value = is_member(mpl, code->arg.arg.z, tuple);
  4351. break;
  4352. case O_SETOF:
  4353. /* check if given n-tuple is member of computed set */
  4354. /* it is not clear how to efficiently perform the check not
  4355. computing the entire elemental set :+( */
  4356. mpl_error(mpl, "implementation restriction; in/within setof{} n"
  4357. "ot allowed");
  4358. break;
  4359. case O_BUILD:
  4360. /* check if given n-tuple is member of domain set */
  4361. { TUPLE *temp;
  4362. temp = build_subtuple(mpl, tuple, code->dim);
  4363. /* try to enter the domain scope; if it is successful,
  4364. the n-tuple is in the domain set */
  4365. value = (eval_within_domain(mpl, code->arg.loop.domain,
  4366. temp, NULL, null_func) == 0);
  4367. delete_tuple(mpl, temp);
  4368. }
  4369. break;
  4370. default:
  4371. xassert(code != code);
  4372. }
  4373. return value;
  4374. }
  4375. /*----------------------------------------------------------------------
  4376. -- eval_formula - evaluate pseudo-code to construct linear form.
  4377. --
  4378. -- This routine evaluates specified pseudo-code to construct resultant
  4379. -- linear form, which is returned on exit. */
  4380. struct iter_form_info
  4381. { /* working info used by the routine iter_form_func */
  4382. CODE *code;
  4383. /* pseudo-code for iterated operation to be performed */
  4384. FORMULA *value;
  4385. /* resultant value */
  4386. FORMULA *tail;
  4387. /* pointer to the last term */
  4388. };
  4389. static int iter_form_func(MPL *mpl, void *_info)
  4390. { /* this is auxiliary routine used to perform iterated operation
  4391. on linear form "integrand" within domain scope */
  4392. struct iter_form_info *info = _info;
  4393. switch (info->code->op)
  4394. { case O_SUM:
  4395. /* summation over domain */
  4396. #if 0
  4397. info->value =
  4398. linear_comb(mpl,
  4399. +1.0, info->value,
  4400. +1.0, eval_formula(mpl, info->code->arg.loop.x));
  4401. #else
  4402. /* the routine linear_comb needs to look through all terms
  4403. of both linear forms to reduce identical terms, so using
  4404. it here is not a good idea (for example, evaluation of
  4405. sum{i in 1..n} x[i] required quadratic time); the better
  4406. idea is to gather all terms of the integrand in one list
  4407. and reduce identical terms only once after all terms of
  4408. the resultant linear form have been evaluated */
  4409. { FORMULA *form, *term;
  4410. form = eval_formula(mpl, info->code->arg.loop.x);
  4411. if (info->value == NULL)
  4412. { xassert(info->tail == NULL);
  4413. info->value = form;
  4414. }
  4415. else
  4416. { xassert(info->tail != NULL);
  4417. info->tail->next = form;
  4418. }
  4419. for (term = form; term != NULL; term = term->next)
  4420. info->tail = term;
  4421. }
  4422. #endif
  4423. break;
  4424. default:
  4425. xassert(info != info);
  4426. }
  4427. return 0;
  4428. }
  4429. FORMULA *eval_formula(MPL *mpl, CODE *code)
  4430. { FORMULA *value;
  4431. xassert(code != NULL);
  4432. xassert(code->type == A_FORMULA);
  4433. xassert(code->dim == 0);
  4434. /* if the operation has a side effect, invalidate and delete the
  4435. resultant value */
  4436. if (code->vflag && code->valid)
  4437. { code->valid = 0;
  4438. delete_value(mpl, code->type, &code->value);
  4439. }
  4440. /* if resultant value is valid, no evaluation is needed */
  4441. if (code->valid)
  4442. { value = copy_formula(mpl, code->value.form);
  4443. goto done;
  4444. }
  4445. /* evaluate pseudo-code recursively */
  4446. switch (code->op)
  4447. { case O_MEMVAR:
  4448. /* take member of variable */
  4449. { TUPLE *tuple;
  4450. ARG_LIST *e;
  4451. tuple = create_tuple(mpl);
  4452. for (e = code->arg.var.list; e != NULL; e = e->next)
  4453. tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
  4454. e->x));
  4455. #if 1 /* 15/V-2010 */
  4456. xassert(code->arg.var.suff == DOT_NONE);
  4457. #endif
  4458. value = single_variable(mpl,
  4459. eval_member_var(mpl, code->arg.var.var, tuple));
  4460. delete_tuple(mpl, tuple);
  4461. }
  4462. break;
  4463. case O_CVTLFM:
  4464. /* convert to linear form */
  4465. value = constant_term(mpl, eval_numeric(mpl,
  4466. code->arg.arg.x));
  4467. break;
  4468. case O_PLUS:
  4469. /* unary plus */
  4470. value = linear_comb(mpl,
  4471. 0.0, constant_term(mpl, 0.0),
  4472. +1.0, eval_formula(mpl, code->arg.arg.x));
  4473. break;
  4474. case O_MINUS:
  4475. /* unary minus */
  4476. value = linear_comb(mpl,
  4477. 0.0, constant_term(mpl, 0.0),
  4478. -1.0, eval_formula(mpl, code->arg.arg.x));
  4479. break;
  4480. case O_ADD:
  4481. /* addition */
  4482. value = linear_comb(mpl,
  4483. +1.0, eval_formula(mpl, code->arg.arg.x),
  4484. +1.0, eval_formula(mpl, code->arg.arg.y));
  4485. break;
  4486. case O_SUB:
  4487. /* subtraction */
  4488. value = linear_comb(mpl,
  4489. +1.0, eval_formula(mpl, code->arg.arg.x),
  4490. -1.0, eval_formula(mpl, code->arg.arg.y));
  4491. break;
  4492. case O_MUL:
  4493. /* multiplication */
  4494. xassert(code->arg.arg.x != NULL);
  4495. xassert(code->arg.arg.y != NULL);
  4496. if (code->arg.arg.x->type == A_NUMERIC)
  4497. { xassert(code->arg.arg.y->type == A_FORMULA);
  4498. value = linear_comb(mpl,
  4499. eval_numeric(mpl, code->arg.arg.x),
  4500. eval_formula(mpl, code->arg.arg.y),
  4501. 0.0, constant_term(mpl, 0.0));
  4502. }
  4503. else
  4504. { xassert(code->arg.arg.x->type == A_FORMULA);
  4505. xassert(code->arg.arg.y->type == A_NUMERIC);
  4506. value = linear_comb(mpl,
  4507. eval_numeric(mpl, code->arg.arg.y),
  4508. eval_formula(mpl, code->arg.arg.x),
  4509. 0.0, constant_term(mpl, 0.0));
  4510. }
  4511. break;
  4512. case O_DIV:
  4513. /* division */
  4514. value = linear_comb(mpl,
  4515. fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)),
  4516. eval_formula(mpl, code->arg.arg.x),
  4517. 0.0, constant_term(mpl, 0.0));
  4518. break;
  4519. case O_FORK:
  4520. /* if-then-else */
  4521. if (eval_logical(mpl, code->arg.arg.x))
  4522. value = eval_formula(mpl, code->arg.arg.y);
  4523. else if (code->arg.arg.z == NULL)
  4524. value = constant_term(mpl, 0.0);
  4525. else
  4526. value = eval_formula(mpl, code->arg.arg.z);
  4527. break;
  4528. case O_SUM:
  4529. /* summation over domain */
  4530. { struct iter_form_info _info, *info = &_info;
  4531. info->code = code;
  4532. info->value = constant_term(mpl, 0.0);
  4533. info->tail = NULL;
  4534. loop_within_domain(mpl, code->arg.loop.domain, info,
  4535. iter_form_func);
  4536. value = reduce_terms(mpl, info->value);
  4537. }
  4538. break;
  4539. default:
  4540. xassert(code != code);
  4541. }
  4542. /* save resultant value */
  4543. xassert(!code->valid);
  4544. code->valid = 1;
  4545. code->value.form = copy_formula(mpl, value);
  4546. done: return value;
  4547. }
  4548. /*----------------------------------------------------------------------
  4549. -- clean_code - clean pseudo-code.
  4550. --
  4551. -- This routine recursively cleans specified pseudo-code that assumes
  4552. -- deleting all temporary resultant values. */
  4553. void clean_code(MPL *mpl, CODE *code)
  4554. { ARG_LIST *e;
  4555. /* if no pseudo-code is specified, do nothing */
  4556. if (code == NULL) goto done;
  4557. /* if resultant value is valid (exists), delete it */
  4558. if (code->valid)
  4559. { code->valid = 0;
  4560. delete_value(mpl, code->type, &code->value);
  4561. }
  4562. /* recursively clean pseudo-code for operands */
  4563. switch (code->op)
  4564. { case O_NUMBER:
  4565. case O_STRING:
  4566. case O_INDEX:
  4567. break;
  4568. case O_MEMNUM:
  4569. case O_MEMSYM:
  4570. for (e = code->arg.par.list; e != NULL; e = e->next)
  4571. clean_code(mpl, e->x);
  4572. break;
  4573. case O_MEMSET:
  4574. for (e = code->arg.set.list; e != NULL; e = e->next)
  4575. clean_code(mpl, e->x);
  4576. break;
  4577. case O_MEMVAR:
  4578. for (e = code->arg.var.list; e != NULL; e = e->next)
  4579. clean_code(mpl, e->x);
  4580. break;
  4581. #if 1 /* 15/V-2010 */
  4582. case O_MEMCON:
  4583. for (e = code->arg.con.list; e != NULL; e = e->next)
  4584. clean_code(mpl, e->x);
  4585. break;
  4586. #endif
  4587. case O_TUPLE:
  4588. case O_MAKE:
  4589. for (e = code->arg.list; e != NULL; e = e->next)
  4590. clean_code(mpl, e->x);
  4591. break;
  4592. case O_SLICE:
  4593. xassert(code != code);
  4594. case O_IRAND224:
  4595. case O_UNIFORM01:
  4596. case O_NORMAL01:
  4597. case O_GMTIME:
  4598. break;
  4599. case O_CVTNUM:
  4600. case O_CVTSYM:
  4601. case O_CVTLOG:
  4602. case O_CVTTUP:
  4603. case O_CVTLFM:
  4604. case O_PLUS:
  4605. case O_MINUS:
  4606. case O_NOT:
  4607. case O_ABS:
  4608. case O_CEIL:
  4609. case O_FLOOR:
  4610. case O_EXP:
  4611. case O_LOG:
  4612. case O_LOG10:
  4613. case O_SQRT:
  4614. case O_SIN:
  4615. case O_COS:
  4616. case O_ATAN:
  4617. case O_ROUND:
  4618. case O_TRUNC:
  4619. case O_CARD:
  4620. case O_LENGTH:
  4621. /* unary operation */
  4622. clean_code(mpl, code->arg.arg.x);
  4623. break;
  4624. case O_ADD:
  4625. case O_SUB:
  4626. case O_LESS:
  4627. case O_MUL:
  4628. case O_DIV:
  4629. case O_IDIV:
  4630. case O_MOD:
  4631. case O_POWER:
  4632. case O_ATAN2:
  4633. case O_ROUND2:
  4634. case O_TRUNC2:
  4635. case O_UNIFORM:
  4636. case O_NORMAL:
  4637. case O_CONCAT:
  4638. case O_LT:
  4639. case O_LE:
  4640. case O_EQ:
  4641. case O_GE:
  4642. case O_GT:
  4643. case O_NE:
  4644. case O_AND:
  4645. case O_OR:
  4646. case O_UNION:
  4647. case O_DIFF:
  4648. case O_SYMDIFF:
  4649. case O_INTER:
  4650. case O_CROSS:
  4651. case O_IN:
  4652. case O_NOTIN:
  4653. case O_WITHIN:
  4654. case O_NOTWITHIN:
  4655. case O_SUBSTR:
  4656. case O_STR2TIME:
  4657. case O_TIME2STR:
  4658. /* binary operation */
  4659. clean_code(mpl, code->arg.arg.x);
  4660. clean_code(mpl, code->arg.arg.y);
  4661. break;
  4662. case O_DOTS:
  4663. case O_FORK:
  4664. case O_SUBSTR3:
  4665. /* ternary operation */
  4666. clean_code(mpl, code->arg.arg.x);
  4667. clean_code(mpl, code->arg.arg.y);
  4668. clean_code(mpl, code->arg.arg.z);
  4669. break;
  4670. case O_MIN:
  4671. case O_MAX:
  4672. /* n-ary operation */
  4673. for (e = code->arg.list; e != NULL; e = e->next)
  4674. clean_code(mpl, e->x);
  4675. break;
  4676. case O_SUM:
  4677. case O_PROD:
  4678. case O_MINIMUM:
  4679. case O_MAXIMUM:
  4680. case O_FORALL:
  4681. case O_EXISTS:
  4682. case O_SETOF:
  4683. case O_BUILD:
  4684. /* iterated operation */
  4685. clean_domain(mpl, code->arg.loop.domain);
  4686. clean_code(mpl, code->arg.loop.x);
  4687. break;
  4688. default:
  4689. xassert(code->op != code->op);
  4690. }
  4691. done: return;
  4692. }
  4693. #if 1 /* 11/II-2008 */
  4694. /**********************************************************************/
  4695. /* * * DATA TABLES * * */
  4696. /**********************************************************************/
  4697. int mpl_tab_num_args(TABDCA *dca)
  4698. { /* returns the number of arguments */
  4699. return dca->na;
  4700. }
  4701. const char *mpl_tab_get_arg(TABDCA *dca, int k)
  4702. { /* returns pointer to k-th argument */
  4703. xassert(1 <= k && k <= dca->na);
  4704. return dca->arg[k];
  4705. }
  4706. int mpl_tab_num_flds(TABDCA *dca)
  4707. { /* returns the number of fields */
  4708. return dca->nf;
  4709. }
  4710. const char *mpl_tab_get_name(TABDCA *dca, int k)
  4711. { /* returns pointer to name of k-th field */
  4712. xassert(1 <= k && k <= dca->nf);
  4713. return dca->name[k];
  4714. }
  4715. int mpl_tab_get_type(TABDCA *dca, int k)
  4716. { /* returns type of k-th field */
  4717. xassert(1 <= k && k <= dca->nf);
  4718. return dca->type[k];
  4719. }
  4720. double mpl_tab_get_num(TABDCA *dca, int k)
  4721. { /* returns numeric value of k-th field */
  4722. xassert(1 <= k && k <= dca->nf);
  4723. xassert(dca->type[k] == 'N');
  4724. return dca->num[k];
  4725. }
  4726. const char *mpl_tab_get_str(TABDCA *dca, int k)
  4727. { /* returns pointer to string value of k-th field */
  4728. xassert(1 <= k && k <= dca->nf);
  4729. xassert(dca->type[k] == 'S');
  4730. xassert(dca->str[k] != NULL);
  4731. return dca->str[k];
  4732. }
  4733. void mpl_tab_set_num(TABDCA *dca, int k, double num)
  4734. { /* assign numeric value to k-th field */
  4735. xassert(1 <= k && k <= dca->nf);
  4736. xassert(dca->type[k] == '?');
  4737. dca->type[k] = 'N';
  4738. dca->num[k] = num;
  4739. return;
  4740. }
  4741. void mpl_tab_set_str(TABDCA *dca, int k, const char *str)
  4742. { /* assign string value to k-th field */
  4743. xassert(1 <= k && k <= dca->nf);
  4744. xassert(dca->type[k] == '?');
  4745. xassert(strlen(str) <= MAX_LENGTH);
  4746. xassert(dca->str[k] != NULL);
  4747. dca->type[k] = 'S';
  4748. strcpy(dca->str[k], str);
  4749. return;
  4750. }
  4751. static int write_func(MPL *mpl, void *info)
  4752. { /* this is auxiliary routine to work within domain scope */
  4753. TABLE *tab = info;
  4754. TABDCA *dca = mpl->dca;
  4755. TABOUT *out;
  4756. SYMBOL *sym;
  4757. int k;
  4758. char buf[MAX_LENGTH+1];
  4759. /* evaluate field values */
  4760. k = 0;
  4761. for (out = tab->u.out.list; out != NULL; out = out->next)
  4762. { k++;
  4763. switch (out->code->type)
  4764. { case A_NUMERIC:
  4765. dca->type[k] = 'N';
  4766. dca->num[k] = eval_numeric(mpl, out->code);
  4767. dca->str[k][0] = '\0';
  4768. break;
  4769. case A_SYMBOLIC:
  4770. sym = eval_symbolic(mpl, out->code);
  4771. if (sym->str == NULL)
  4772. { dca->type[k] = 'N';
  4773. dca->num[k] = sym->num;
  4774. dca->str[k][0] = '\0';
  4775. }
  4776. else
  4777. { dca->type[k] = 'S';
  4778. dca->num[k] = 0.0;
  4779. fetch_string(mpl, sym->str, buf);
  4780. strcpy(dca->str[k], buf);
  4781. }
  4782. delete_symbol(mpl, sym);
  4783. break;
  4784. default:
  4785. xassert(out != out);
  4786. }
  4787. }
  4788. /* write record to output table */
  4789. mpl_tab_drv_write(mpl);
  4790. return 0;
  4791. }
  4792. void execute_table(MPL *mpl, TABLE *tab)
  4793. { /* execute table statement */
  4794. TABARG *arg;
  4795. TABFLD *fld;
  4796. TABIN *in;
  4797. TABOUT *out;
  4798. TABDCA *dca;
  4799. SET *set;
  4800. int k;
  4801. char buf[MAX_LENGTH+1];
  4802. /* allocate table driver communication area */
  4803. xassert(mpl->dca == NULL);
  4804. mpl->dca = dca = xmalloc(sizeof(TABDCA));
  4805. dca->id = 0;
  4806. dca->link = NULL;
  4807. dca->na = 0;
  4808. dca->arg = NULL;
  4809. dca->nf = 0;
  4810. dca->name = NULL;
  4811. dca->type = NULL;
  4812. dca->num = NULL;
  4813. dca->str = NULL;
  4814. /* allocate arguments */
  4815. xassert(dca->na == 0);
  4816. for (arg = tab->arg; arg != NULL; arg = arg->next)
  4817. dca->na++;
  4818. dca->arg = xcalloc(1+dca->na, sizeof(char *));
  4819. #if 1 /* 28/IX-2008 */
  4820. for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL;
  4821. #endif
  4822. /* evaluate argument values */
  4823. k = 0;
  4824. for (arg = tab->arg; arg != NULL; arg = arg->next)
  4825. { SYMBOL *sym;
  4826. k++;
  4827. xassert(arg->code->type == A_SYMBOLIC);
  4828. sym = eval_symbolic(mpl, arg->code);
  4829. if (sym->str == NULL)
  4830. sprintf(buf, "%.*g", DBL_DIG, sym->num);
  4831. else
  4832. fetch_string(mpl, sym->str, buf);
  4833. delete_symbol(mpl, sym);
  4834. dca->arg[k] = xmalloc(strlen(buf)+1);
  4835. strcpy(dca->arg[k], buf);
  4836. }
  4837. /* perform table input/output */
  4838. switch (tab->type)
  4839. { case A_INPUT: goto read_table;
  4840. case A_OUTPUT: goto write_table;
  4841. default: xassert(tab != tab);
  4842. }
  4843. read_table:
  4844. /* read data from input table */
  4845. /* add the only member to the control set and assign it empty
  4846. elemental set */
  4847. set = tab->u.in.set;
  4848. if (set != NULL)
  4849. { if (set->data)
  4850. mpl_error(mpl, "%s already provided with data", set->name);
  4851. xassert(set->array->head == NULL);
  4852. add_member(mpl, set->array, NULL)->value.set =
  4853. create_elemset(mpl, set->dimen);
  4854. set->data = 1;
  4855. }
  4856. /* check parameters specified in the input list */
  4857. for (in = tab->u.in.list; in != NULL; in = in->next)
  4858. { if (in->par->data)
  4859. mpl_error(mpl, "%s already provided with data", in->par->name);
  4860. in->par->data = 1;
  4861. }
  4862. /* allocate and initialize fields */
  4863. xassert(dca->nf == 0);
  4864. for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
  4865. dca->nf++;
  4866. for (in = tab->u.in.list; in != NULL; in = in->next)
  4867. dca->nf++;
  4868. dca->name = xcalloc(1+dca->nf, sizeof(char *));
  4869. dca->type = xcalloc(1+dca->nf, sizeof(int));
  4870. dca->num = xcalloc(1+dca->nf, sizeof(double));
  4871. dca->str = xcalloc(1+dca->nf, sizeof(char *));
  4872. k = 0;
  4873. for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
  4874. { k++;
  4875. dca->name[k] = fld->name;
  4876. dca->type[k] = '?';
  4877. dca->num[k] = 0.0;
  4878. dca->str[k] = xmalloc(MAX_LENGTH+1);
  4879. dca->str[k][0] = '\0';
  4880. }
  4881. for (in = tab->u.in.list; in != NULL; in = in->next)
  4882. { k++;
  4883. dca->name[k] = in->name;
  4884. dca->type[k] = '?';
  4885. dca->num[k] = 0.0;
  4886. dca->str[k] = xmalloc(MAX_LENGTH+1);
  4887. dca->str[k][0] = '\0';
  4888. }
  4889. /* open input table */
  4890. mpl_tab_drv_open(mpl, 'R');
  4891. /* read and process records */
  4892. for (;;)
  4893. { TUPLE *tup;
  4894. /* reset field types */
  4895. for (k = 1; k <= dca->nf; k++)
  4896. dca->type[k] = '?';
  4897. /* read next record */
  4898. if (mpl_tab_drv_read(mpl)) break;
  4899. /* all fields must be set by the driver */
  4900. for (k = 1; k <= dca->nf; k++)
  4901. { if (dca->type[k] == '?')
  4902. mpl_error(mpl, "field %s missing in input table",
  4903. dca->name[k]);
  4904. }
  4905. /* construct n-tuple */
  4906. tup = create_tuple(mpl);
  4907. k = 0;
  4908. for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
  4909. { k++;
  4910. xassert(k <= dca->nf);
  4911. switch (dca->type[k])
  4912. { case 'N':
  4913. tup = expand_tuple(mpl, tup, create_symbol_num(mpl,
  4914. dca->num[k]));
  4915. break;
  4916. case 'S':
  4917. xassert(strlen(dca->str[k]) <= MAX_LENGTH);
  4918. tup = expand_tuple(mpl, tup, create_symbol_str(mpl,
  4919. create_string(mpl, dca->str[k])));
  4920. break;
  4921. default:
  4922. xassert(dca != dca);
  4923. }
  4924. }
  4925. /* add n-tuple just read to the control set */
  4926. if (tab->u.in.set != NULL)
  4927. check_then_add(mpl, tab->u.in.set->array->head->value.set,
  4928. copy_tuple(mpl, tup));
  4929. /* assign values to the parameters in the input list */
  4930. for (in = tab->u.in.list; in != NULL; in = in->next)
  4931. { MEMBER *memb;
  4932. k++;
  4933. xassert(k <= dca->nf);
  4934. /* there must be no member with the same n-tuple */
  4935. if (find_member(mpl, in->par->array, tup) != NULL)
  4936. mpl_error(mpl, "%s%s already defined", in->par->name,
  4937. format_tuple(mpl, '[', tup));
  4938. /* create new parameter member with given n-tuple */
  4939. memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup))
  4940. ;
  4941. /* assign value to the parameter member */
  4942. switch (in->par->type)
  4943. { case A_NUMERIC:
  4944. case A_INTEGER:
  4945. case A_BINARY:
  4946. if (dca->type[k] != 'N')
  4947. mpl_error(mpl, "%s requires numeric data",
  4948. in->par->name);
  4949. memb->value.num = dca->num[k];
  4950. break;
  4951. case A_SYMBOLIC:
  4952. switch (dca->type[k])
  4953. { case 'N':
  4954. memb->value.sym = create_symbol_num(mpl,
  4955. dca->num[k]);
  4956. break;
  4957. case 'S':
  4958. xassert(strlen(dca->str[k]) <= MAX_LENGTH);
  4959. memb->value.sym = create_symbol_str(mpl,
  4960. create_string(mpl,dca->str[k]));
  4961. break;
  4962. default:
  4963. xassert(dca != dca);
  4964. }
  4965. break;
  4966. default:
  4967. xassert(in != in);
  4968. }
  4969. }
  4970. /* n-tuple is no more needed */
  4971. delete_tuple(mpl, tup);
  4972. }
  4973. /* close input table */
  4974. mpl_tab_drv_close(mpl);
  4975. goto done;
  4976. write_table:
  4977. /* write data to output table */
  4978. /* allocate and initialize fields */
  4979. xassert(dca->nf == 0);
  4980. for (out = tab->u.out.list; out != NULL; out = out->next)
  4981. dca->nf++;
  4982. dca->name = xcalloc(1+dca->nf, sizeof(char *));
  4983. dca->type = xcalloc(1+dca->nf, sizeof(int));
  4984. dca->num = xcalloc(1+dca->nf, sizeof(double));
  4985. dca->str = xcalloc(1+dca->nf, sizeof(char *));
  4986. k = 0;
  4987. for (out = tab->u.out.list; out != NULL; out = out->next)
  4988. { k++;
  4989. dca->name[k] = out->name;
  4990. dca->type[k] = '?';
  4991. dca->num[k] = 0.0;
  4992. dca->str[k] = xmalloc(MAX_LENGTH+1);
  4993. dca->str[k][0] = '\0';
  4994. }
  4995. /* open output table */
  4996. mpl_tab_drv_open(mpl, 'W');
  4997. /* evaluate fields and write records */
  4998. loop_within_domain(mpl, tab->u.out.domain, tab, write_func);
  4999. /* close output table */
  5000. mpl_tab_drv_close(mpl);
  5001. done: /* free table driver communication area */
  5002. free_dca(mpl);
  5003. return;
  5004. }
  5005. void free_dca(MPL *mpl)
  5006. { /* free table driver communucation area */
  5007. TABDCA *dca = mpl->dca;
  5008. int k;
  5009. if (dca != NULL)
  5010. { if (dca->link != NULL)
  5011. mpl_tab_drv_close(mpl);
  5012. if (dca->arg != NULL)
  5013. { for (k = 1; k <= dca->na; k++)
  5014. #if 1 /* 28/IX-2008 */
  5015. if (dca->arg[k] != NULL)
  5016. #endif
  5017. xfree(dca->arg[k]);
  5018. xfree(dca->arg);
  5019. }
  5020. if (dca->name != NULL) xfree(dca->name);
  5021. if (dca->type != NULL) xfree(dca->type);
  5022. if (dca->num != NULL) xfree(dca->num);
  5023. if (dca->str != NULL)
  5024. { for (k = 1; k <= dca->nf; k++)
  5025. xfree(dca->str[k]);
  5026. xfree(dca->str);
  5027. }
  5028. xfree(dca), mpl->dca = NULL;
  5029. }
  5030. return;
  5031. }
  5032. void clean_table(MPL *mpl, TABLE *tab)
  5033. { /* clean table statement */
  5034. TABARG *arg;
  5035. TABOUT *out;
  5036. /* clean string list */
  5037. for (arg = tab->arg; arg != NULL; arg = arg->next)
  5038. clean_code(mpl, arg->code);
  5039. switch (tab->type)
  5040. { case A_INPUT:
  5041. break;
  5042. case A_OUTPUT:
  5043. /* clean subscript domain */
  5044. clean_domain(mpl, tab->u.out.domain);
  5045. /* clean output list */
  5046. for (out = tab->u.out.list; out != NULL; out = out->next)
  5047. clean_code(mpl, out->code);
  5048. break;
  5049. default:
  5050. xassert(tab != tab);
  5051. }
  5052. return;
  5053. }
  5054. #endif
  5055. /**********************************************************************/
  5056. /* * * MODEL STATEMENTS * * */
  5057. /**********************************************************************/
  5058. /*----------------------------------------------------------------------
  5059. -- execute_check - execute check statement.
  5060. --
  5061. -- This routine executes specified check statement. */
  5062. static int check_func(MPL *mpl, void *info)
  5063. { /* this is auxiliary routine to work within domain scope */
  5064. CHECK *chk = (CHECK *)info;
  5065. if (!eval_logical(mpl, chk->code))
  5066. mpl_error(mpl, "check%s failed", format_tuple(mpl, '[',
  5067. get_domain_tuple(mpl, chk->domain)));
  5068. return 0;
  5069. }
  5070. void execute_check(MPL *mpl, CHECK *chk)
  5071. { loop_within_domain(mpl, chk->domain, chk, check_func);
  5072. return;
  5073. }
  5074. /*----------------------------------------------------------------------
  5075. -- clean_check - clean check statement.
  5076. --
  5077. -- This routine cleans specified check statement that assumes deleting
  5078. -- all stuff dynamically allocated on generating/postsolving phase. */
  5079. void clean_check(MPL *mpl, CHECK *chk)
  5080. { /* clean subscript domain */
  5081. clean_domain(mpl, chk->domain);
  5082. /* clean pseudo-code for computing predicate */
  5083. clean_code(mpl, chk->code);
  5084. return;
  5085. }
  5086. /*----------------------------------------------------------------------
  5087. -- execute_display - execute display statement.
  5088. --
  5089. -- This routine executes specified display statement. */
  5090. static void display_set(MPL *mpl, SET *set, MEMBER *memb)
  5091. { /* display member of model set */
  5092. ELEMSET *s = memb->value.set;
  5093. MEMBER *m;
  5094. write_text(mpl, "%s%s%s\n", set->name,
  5095. format_tuple(mpl, '[', memb->tuple),
  5096. s->head == NULL ? " is empty" : ":");
  5097. for (m = s->head; m != NULL; m = m->next)
  5098. write_text(mpl, " %s\n", format_tuple(mpl, '(', m->tuple));
  5099. return;
  5100. }
  5101. static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb)
  5102. { /* display member of model parameter */
  5103. switch (par->type)
  5104. { case A_NUMERIC:
  5105. case A_INTEGER:
  5106. case A_BINARY:
  5107. write_text(mpl, "%s%s = %.*g\n", par->name,
  5108. format_tuple(mpl, '[', memb->tuple),
  5109. DBL_DIG, memb->value.num);
  5110. break;
  5111. case A_SYMBOLIC:
  5112. write_text(mpl, "%s%s = %s\n", par->name,
  5113. format_tuple(mpl, '[', memb->tuple),
  5114. format_symbol(mpl, memb->value.sym));
  5115. break;
  5116. default:
  5117. xassert(par != par);
  5118. }
  5119. return;
  5120. }
  5121. #if 1 /* 15/V-2010 */
  5122. static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb,
  5123. int suff)
  5124. { /* display member of model variable */
  5125. if (suff == DOT_NONE || suff == DOT_VAL)
  5126. write_text(mpl, "%s%s.val = %.*g\n", var->name,
  5127. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5128. memb->value.var->prim);
  5129. else if (suff == DOT_LB)
  5130. write_text(mpl, "%s%s.lb = %.*g\n", var->name,
  5131. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5132. memb->value.var->var->lbnd == NULL ? -DBL_MAX :
  5133. memb->value.var->lbnd);
  5134. else if (suff == DOT_UB)
  5135. write_text(mpl, "%s%s.ub = %.*g\n", var->name,
  5136. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5137. memb->value.var->var->ubnd == NULL ? +DBL_MAX :
  5138. memb->value.var->ubnd);
  5139. else if (suff == DOT_STATUS)
  5140. write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple
  5141. (mpl, '[', memb->tuple), memb->value.var->stat);
  5142. else if (suff == DOT_DUAL)
  5143. write_text(mpl, "%s%s.dual = %.*g\n", var->name,
  5144. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5145. memb->value.var->dual);
  5146. else
  5147. xassert(suff != suff);
  5148. return;
  5149. }
  5150. #endif
  5151. #if 1 /* 15/V-2010 */
  5152. static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb,
  5153. int suff)
  5154. { /* display member of model constraint */
  5155. if (suff == DOT_NONE || suff == DOT_VAL)
  5156. write_text(mpl, "%s%s.val = %.*g\n", con->name,
  5157. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5158. memb->value.con->prim);
  5159. else if (suff == DOT_LB)
  5160. write_text(mpl, "%s%s.lb = %.*g\n", con->name,
  5161. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5162. memb->value.con->con->lbnd == NULL ? -DBL_MAX :
  5163. memb->value.con->lbnd);
  5164. else if (suff == DOT_UB)
  5165. write_text(mpl, "%s%s.ub = %.*g\n", con->name,
  5166. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5167. memb->value.con->con->ubnd == NULL ? +DBL_MAX :
  5168. memb->value.con->ubnd);
  5169. else if (suff == DOT_STATUS)
  5170. write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple
  5171. (mpl, '[', memb->tuple), memb->value.con->stat);
  5172. else if (suff == DOT_DUAL)
  5173. write_text(mpl, "%s%s.dual = %.*g\n", con->name,
  5174. format_tuple(mpl, '[', memb->tuple), DBL_DIG,
  5175. memb->value.con->dual);
  5176. else
  5177. xassert(suff != suff);
  5178. return;
  5179. }
  5180. #endif
  5181. static void display_memb(MPL *mpl, CODE *code)
  5182. { /* display member specified by pseudo-code */
  5183. MEMBER memb;
  5184. ARG_LIST *e;
  5185. xassert(code->op == O_MEMNUM || code->op == O_MEMSYM
  5186. || code->op == O_MEMSET || code->op == O_MEMVAR
  5187. || code->op == O_MEMCON);
  5188. memb.tuple = create_tuple(mpl);
  5189. for (e = code->arg.par.list; e != NULL; e = e->next)
  5190. memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl,
  5191. e->x));
  5192. switch (code->op)
  5193. { case O_MEMNUM:
  5194. memb.value.num = eval_member_num(mpl, code->arg.par.par,
  5195. memb.tuple);
  5196. display_par(mpl, code->arg.par.par, &memb);
  5197. break;
  5198. case O_MEMSYM:
  5199. memb.value.sym = eval_member_sym(mpl, code->arg.par.par,
  5200. memb.tuple);
  5201. display_par(mpl, code->arg.par.par, &memb);
  5202. delete_symbol(mpl, memb.value.sym);
  5203. break;
  5204. case O_MEMSET:
  5205. memb.value.set = eval_member_set(mpl, code->arg.set.set,
  5206. memb.tuple);
  5207. display_set(mpl, code->arg.set.set, &memb);
  5208. break;
  5209. case O_MEMVAR:
  5210. memb.value.var = eval_member_var(mpl, code->arg.var.var,
  5211. memb.tuple);
  5212. display_var
  5213. (mpl, code->arg.var.var, &memb, code->arg.var.suff);
  5214. break;
  5215. case O_MEMCON:
  5216. memb.value.con = eval_member_con(mpl, code->arg.con.con,
  5217. memb.tuple);
  5218. display_con
  5219. (mpl, code->arg.con.con, &memb, code->arg.con.suff);
  5220. break;
  5221. default:
  5222. xassert(code != code);
  5223. }
  5224. delete_tuple(mpl, memb.tuple);
  5225. return;
  5226. }
  5227. static void display_code(MPL *mpl, CODE *code)
  5228. { /* display value of expression */
  5229. switch (code->type)
  5230. { case A_NUMERIC:
  5231. /* numeric value */
  5232. { double num;
  5233. num = eval_numeric(mpl, code);
  5234. write_text(mpl, "%.*g\n", DBL_DIG, num);
  5235. }
  5236. break;
  5237. case A_SYMBOLIC:
  5238. /* symbolic value */
  5239. { SYMBOL *sym;
  5240. sym = eval_symbolic(mpl, code);
  5241. write_text(mpl, "%s\n", format_symbol(mpl, sym));
  5242. delete_symbol(mpl, sym);
  5243. }
  5244. break;
  5245. case A_LOGICAL:
  5246. /* logical value */
  5247. { int bit;
  5248. bit = eval_logical(mpl, code);
  5249. write_text(mpl, "%s\n", bit ? "true" : "false");
  5250. }
  5251. break;
  5252. case A_TUPLE:
  5253. /* n-tuple */
  5254. { TUPLE *tuple;
  5255. tuple = eval_tuple(mpl, code);
  5256. write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple));
  5257. delete_tuple(mpl, tuple);
  5258. }
  5259. break;
  5260. case A_ELEMSET:
  5261. /* elemental set */
  5262. { ELEMSET *set;
  5263. MEMBER *memb;
  5264. set = eval_elemset(mpl, code);
  5265. if (set->head == 0)
  5266. write_text(mpl, "set is empty\n");
  5267. for (memb = set->head; memb != NULL; memb = memb->next)
  5268. write_text(mpl, " %s\n", format_tuple(mpl, '(',
  5269. memb->tuple));
  5270. delete_elemset(mpl, set);
  5271. }
  5272. break;
  5273. case A_FORMULA:
  5274. /* linear form */
  5275. { FORMULA *form, *term;
  5276. form = eval_formula(mpl, code);
  5277. if (form == NULL)
  5278. write_text(mpl, "linear form is empty\n");
  5279. for (term = form; term != NULL; term = term->next)
  5280. { if (term->var == NULL)
  5281. write_text(mpl, " %.*g\n", term->coef);
  5282. else
  5283. write_text(mpl, " %.*g %s%s\n", DBL_DIG,
  5284. term->coef, term->var->var->name,
  5285. format_tuple(mpl, '[', term->var->memb->tuple));
  5286. }
  5287. delete_formula(mpl, form);
  5288. }
  5289. break;
  5290. default:
  5291. xassert(code != code);
  5292. }
  5293. return;
  5294. }
  5295. static int display_func(MPL *mpl, void *info)
  5296. { /* this is auxiliary routine to work within domain scope */
  5297. DISPLAY *dpy = (DISPLAY *)info;
  5298. DISPLAY1 *entry;
  5299. for (entry = dpy->list; entry != NULL; entry = entry->next)
  5300. { if (entry->type == A_INDEX)
  5301. { /* dummy index */
  5302. DOMAIN_SLOT *slot = entry->u.slot;
  5303. write_text(mpl, "%s = %s\n", slot->name,
  5304. format_symbol(mpl, slot->value));
  5305. }
  5306. else if (entry->type == A_SET)
  5307. { /* model set */
  5308. SET *set = entry->u.set;
  5309. MEMBER *memb;
  5310. if (set->assign != NULL)
  5311. { /* the set has assignment expression; evaluate all its
  5312. members over entire domain */
  5313. eval_whole_set(mpl, set);
  5314. }
  5315. else
  5316. { /* the set has no assignment expression; refer to its
  5317. any existing member ignoring resultant value to check
  5318. the data provided the data section */
  5319. #if 1 /* 12/XII-2008 */
  5320. if (set->gadget != NULL && set->data == 0)
  5321. { /* initialize the set with data from a plain set */
  5322. saturate_set(mpl, set);
  5323. }
  5324. #endif
  5325. if (set->array->head != NULL)
  5326. eval_member_set(mpl, set, set->array->head->tuple);
  5327. }
  5328. /* display all members of the set array */
  5329. if (set->array->head == NULL)
  5330. write_text(mpl, "%s has empty content\n", set->name);
  5331. for (memb = set->array->head; memb != NULL; memb =
  5332. memb->next) display_set(mpl, set, memb);
  5333. }
  5334. else if (entry->type == A_PARAMETER)
  5335. { /* model parameter */
  5336. PARAMETER *par = entry->u.par;
  5337. MEMBER *memb;
  5338. if (par->assign != NULL)
  5339. { /* the parameter has an assignment expression; evaluate
  5340. all its member over entire domain */
  5341. eval_whole_par(mpl, par);
  5342. }
  5343. else
  5344. { /* the parameter has no assignment expression; refer to
  5345. its any existing member ignoring resultant value to
  5346. check the data provided in the data section */
  5347. if (par->array->head != NULL)
  5348. { if (par->type != A_SYMBOLIC)
  5349. eval_member_num(mpl, par, par->array->head->tuple);
  5350. else
  5351. delete_symbol(mpl, eval_member_sym(mpl, par,
  5352. par->array->head->tuple));
  5353. }
  5354. }
  5355. /* display all members of the parameter array */
  5356. if (par->array->head == NULL)
  5357. write_text(mpl, "%s has empty content\n", par->name);
  5358. for (memb = par->array->head; memb != NULL; memb =
  5359. memb->next) display_par(mpl, par, memb);
  5360. }
  5361. else if (entry->type == A_VARIABLE)
  5362. { /* model variable */
  5363. VARIABLE *var = entry->u.var;
  5364. MEMBER *memb;
  5365. xassert(mpl->flag_p);
  5366. /* display all members of the variable array */
  5367. if (var->array->head == NULL)
  5368. write_text(mpl, "%s has empty content\n", var->name);
  5369. for (memb = var->array->head; memb != NULL; memb =
  5370. memb->next) display_var(mpl, var, memb, DOT_NONE);
  5371. }
  5372. else if (entry->type == A_CONSTRAINT)
  5373. { /* model constraint */
  5374. CONSTRAINT *con = entry->u.con;
  5375. MEMBER *memb;
  5376. xassert(mpl->flag_p);
  5377. /* display all members of the constraint array */
  5378. if (con->array->head == NULL)
  5379. write_text(mpl, "%s has empty content\n", con->name);
  5380. for (memb = con->array->head; memb != NULL; memb =
  5381. memb->next) display_con(mpl, con, memb, DOT_NONE);
  5382. }
  5383. else if (entry->type == A_EXPRESSION)
  5384. { /* expression */
  5385. CODE *code = entry->u.code;
  5386. if (code->op == O_MEMNUM || code->op == O_MEMSYM ||
  5387. code->op == O_MEMSET || code->op == O_MEMVAR ||
  5388. code->op == O_MEMCON)
  5389. display_memb(mpl, code);
  5390. else
  5391. display_code(mpl, code);
  5392. }
  5393. else
  5394. xassert(entry != entry);
  5395. }
  5396. return 0;
  5397. }
  5398. void execute_display(MPL *mpl, DISPLAY *dpy)
  5399. { loop_within_domain(mpl, dpy->domain, dpy, display_func);
  5400. return;
  5401. }
  5402. /*----------------------------------------------------------------------
  5403. -- clean_display - clean display statement.
  5404. --
  5405. -- This routine cleans specified display statement that assumes deleting
  5406. -- all stuff dynamically allocated on generating/postsolving phase. */
  5407. void clean_display(MPL *mpl, DISPLAY *dpy)
  5408. { DISPLAY1 *d;
  5409. #if 0 /* 15/V-2010 */
  5410. ARG_LIST *e;
  5411. #endif
  5412. /* clean subscript domain */
  5413. clean_domain(mpl, dpy->domain);
  5414. /* clean display list */
  5415. for (d = dpy->list; d != NULL; d = d->next)
  5416. { /* clean pseudo-code for computing expression */
  5417. if (d->type == A_EXPRESSION)
  5418. clean_code(mpl, d->u.code);
  5419. #if 0 /* 15/V-2010 */
  5420. /* clean pseudo-code for computing subscripts */
  5421. for (e = d->list; e != NULL; e = e->next)
  5422. clean_code(mpl, e->x);
  5423. #endif
  5424. }
  5425. return;
  5426. }
  5427. /*----------------------------------------------------------------------
  5428. -- execute_printf - execute printf statement.
  5429. --
  5430. -- This routine executes specified printf statement. */
  5431. #if 1 /* 14/VII-2006 */
  5432. static void print_char(MPL *mpl, int c)
  5433. { if (mpl->prt_fp == NULL)
  5434. write_char(mpl, c);
  5435. else
  5436. xfputc(c, mpl->prt_fp);
  5437. return;
  5438. }
  5439. static void print_text(MPL *mpl, char *fmt, ...)
  5440. { va_list arg;
  5441. char buf[OUTBUF_SIZE], *c;
  5442. va_start(arg, fmt);
  5443. vsprintf(buf, fmt, arg);
  5444. xassert(strlen(buf) < sizeof(buf));
  5445. va_end(arg);
  5446. for (c = buf; *c != '\0'; c++) print_char(mpl, *c);
  5447. return;
  5448. }
  5449. #endif
  5450. static int printf_func(MPL *mpl, void *info)
  5451. { /* this is auxiliary routine to work within domain scope */
  5452. PRINTF *prt = (PRINTF *)info;
  5453. PRINTF1 *entry;
  5454. SYMBOL *sym;
  5455. char fmt[MAX_LENGTH+1], *c, *from, save;
  5456. /* evaluate format control string */
  5457. sym = eval_symbolic(mpl, prt->fmt);
  5458. if (sym->str == NULL)
  5459. sprintf(fmt, "%.*g", DBL_DIG, sym->num);
  5460. else
  5461. fetch_string(mpl, sym->str, fmt);
  5462. delete_symbol(mpl, sym);
  5463. /* scan format control string and perform formatting output */
  5464. entry = prt->list;
  5465. for (c = fmt; *c != '\0'; c++)
  5466. { if (*c == '%')
  5467. { /* scan format specifier */
  5468. from = c++;
  5469. if (*c == '%')
  5470. { print_char(mpl, '%');
  5471. continue;
  5472. }
  5473. if (entry == NULL) break;
  5474. /* scan optional flags */
  5475. while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' ||
  5476. *c == '0') c++;
  5477. /* scan optional minimum field width */
  5478. while (isdigit((unsigned char)*c)) c++;
  5479. /* scan optional precision */
  5480. if (*c == '.')
  5481. { c++;
  5482. while (isdigit((unsigned char)*c)) c++;
  5483. }
  5484. /* scan conversion specifier and perform formatting */
  5485. save = *(c+1), *(c+1) = '\0';
  5486. if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' ||
  5487. *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G')
  5488. { /* the specifier requires numeric value */
  5489. double value;
  5490. xassert(entry != NULL);
  5491. switch (entry->code->type)
  5492. { case A_NUMERIC:
  5493. value = eval_numeric(mpl, entry->code);
  5494. break;
  5495. case A_SYMBOLIC:
  5496. sym = eval_symbolic(mpl, entry->code);
  5497. if (sym->str != NULL)
  5498. mpl_error(mpl, "cannot convert %s to floating-point"
  5499. " number", format_symbol(mpl, sym));
  5500. value = sym->num;
  5501. delete_symbol(mpl, sym);
  5502. break;
  5503. case A_LOGICAL:
  5504. if (eval_logical(mpl, entry->code))
  5505. value = 1.0;
  5506. else
  5507. value = 0.0;
  5508. break;
  5509. default:
  5510. xassert(entry != entry);
  5511. }
  5512. if (*c == 'd' || *c == 'i')
  5513. { double int_max = (double)INT_MAX;
  5514. if (!(-int_max <= value && value <= +int_max))
  5515. mpl_error(mpl, "cannot convert %.*g to integer",
  5516. DBL_DIG, value);
  5517. print_text(mpl, from, (int)floor(value + 0.5));
  5518. }
  5519. else
  5520. print_text(mpl, from, value);
  5521. }
  5522. else if (*c == 's')
  5523. { /* the specifier requires symbolic value */
  5524. char value[MAX_LENGTH+1];
  5525. switch (entry->code->type)
  5526. { case A_NUMERIC:
  5527. sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl,
  5528. entry->code));
  5529. break;
  5530. case A_LOGICAL:
  5531. if (eval_logical(mpl, entry->code))
  5532. strcpy(value, "T");
  5533. else
  5534. strcpy(value, "F");
  5535. break;
  5536. case A_SYMBOLIC:
  5537. sym = eval_symbolic(mpl, entry->code);
  5538. if (sym->str == NULL)
  5539. sprintf(value, "%.*g", DBL_DIG, sym->num);
  5540. else
  5541. fetch_string(mpl, sym->str, value);
  5542. delete_symbol(mpl, sym);
  5543. break;
  5544. default:
  5545. xassert(entry != entry);
  5546. }
  5547. print_text(mpl, from, value);
  5548. }
  5549. else
  5550. mpl_error(mpl, "format specifier missing or invalid");
  5551. *(c+1) = save;
  5552. entry = entry->next;
  5553. }
  5554. else if (*c == '\\')
  5555. { /* write some control character */
  5556. c++;
  5557. if (*c == 't')
  5558. print_char(mpl, '\t');
  5559. else if (*c == 'n')
  5560. print_char(mpl, '\n');
  5561. else
  5562. print_char(mpl, *c);
  5563. }
  5564. else
  5565. { /* write character without formatting */
  5566. print_char(mpl, *c);
  5567. }
  5568. }
  5569. return 0;
  5570. }
  5571. #if 0 /* 14/VII-2006 */
  5572. void execute_printf(MPL *mpl, PRINTF *prt)
  5573. { loop_within_domain(mpl, prt->domain, prt, printf_func);
  5574. return;
  5575. }
  5576. #else
  5577. void execute_printf(MPL *mpl, PRINTF *prt)
  5578. { if (prt->fname == NULL)
  5579. { /* switch to the standard output */
  5580. if (mpl->prt_fp != NULL)
  5581. { xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
  5582. xfree(mpl->prt_file), mpl->prt_file = NULL;
  5583. }
  5584. }
  5585. else
  5586. { /* evaluate file name string */
  5587. SYMBOL *sym;
  5588. char fname[MAX_LENGTH+1];
  5589. sym = eval_symbolic(mpl, prt->fname);
  5590. if (sym->str == NULL)
  5591. sprintf(fname, "%.*g", DBL_DIG, sym->num);
  5592. else
  5593. fetch_string(mpl, sym->str, fname);
  5594. delete_symbol(mpl, sym);
  5595. /* close the current print file, if necessary */
  5596. if (mpl->prt_fp != NULL &&
  5597. (!prt->app || strcmp(mpl->prt_file, fname) != 0))
  5598. { xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
  5599. xfree(mpl->prt_file), mpl->prt_file = NULL;
  5600. }
  5601. /* open the specified print file, if necessary */
  5602. if (mpl->prt_fp == NULL)
  5603. { mpl->prt_fp = xfopen(fname, prt->app ? "a" : "w");
  5604. if (mpl->prt_fp == NULL)
  5605. mpl_error(mpl, "unable to open `%s' for writing - %s",
  5606. fname, xerrmsg());
  5607. mpl->prt_file = xmalloc(strlen(fname)+1);
  5608. strcpy(mpl->prt_file, fname);
  5609. }
  5610. }
  5611. loop_within_domain(mpl, prt->domain, prt, printf_func);
  5612. if (mpl->prt_fp != NULL)
  5613. { xfflush(mpl->prt_fp);
  5614. if (xferror(mpl->prt_fp))
  5615. mpl_error(mpl, "writing error to `%s' - %s", mpl->prt_file,
  5616. xerrmsg());
  5617. }
  5618. return;
  5619. }
  5620. #endif
  5621. /*----------------------------------------------------------------------
  5622. -- clean_printf - clean printf statement.
  5623. --
  5624. -- This routine cleans specified printf statement that assumes deleting
  5625. -- all stuff dynamically allocated on generating/postsolving phase. */
  5626. void clean_printf(MPL *mpl, PRINTF *prt)
  5627. { PRINTF1 *p;
  5628. /* clean subscript domain */
  5629. clean_domain(mpl, prt->domain);
  5630. /* clean pseudo-code for computing format string */
  5631. clean_code(mpl, prt->fmt);
  5632. /* clean printf list */
  5633. for (p = prt->list; p != NULL; p = p->next)
  5634. { /* clean pseudo-code for computing value to be printed */
  5635. clean_code(mpl, p->code);
  5636. }
  5637. #if 1 /* 14/VII-2006 */
  5638. /* clean pseudo-code for computing file name string */
  5639. clean_code(mpl, prt->fname);
  5640. #endif
  5641. return;
  5642. }
  5643. /*----------------------------------------------------------------------
  5644. -- execute_for - execute for statement.
  5645. --
  5646. -- This routine executes specified for statement. */
  5647. static int for_func(MPL *mpl, void *info)
  5648. { /* this is auxiliary routine to work within domain scope */
  5649. FOR *fur = (FOR *)info;
  5650. STATEMENT *stmt, *save;
  5651. save = mpl->stmt;
  5652. for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
  5653. execute_statement(mpl, stmt);
  5654. mpl->stmt = save;
  5655. return 0;
  5656. }
  5657. void execute_for(MPL *mpl, FOR *fur)
  5658. { loop_within_domain(mpl, fur->domain, fur, for_func);
  5659. return;
  5660. }
  5661. /*----------------------------------------------------------------------
  5662. -- clean_for - clean for statement.
  5663. --
  5664. -- This routine cleans specified for statement that assumes deleting all
  5665. -- stuff dynamically allocated on generating/postsolving phase. */
  5666. void clean_for(MPL *mpl, FOR *fur)
  5667. { STATEMENT *stmt;
  5668. /* clean subscript domain */
  5669. clean_domain(mpl, fur->domain);
  5670. /* clean all sub-statements */
  5671. for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
  5672. clean_statement(mpl, stmt);
  5673. return;
  5674. }
  5675. /*----------------------------------------------------------------------
  5676. -- execute_statement - execute specified model statement.
  5677. --
  5678. -- This routine executes specified model statement. */
  5679. void execute_statement(MPL *mpl, STATEMENT *stmt)
  5680. { mpl->stmt = stmt;
  5681. switch (stmt->type)
  5682. { case A_SET:
  5683. case A_PARAMETER:
  5684. case A_VARIABLE:
  5685. break;
  5686. case A_CONSTRAINT:
  5687. xprintf("Generating %s...\n", stmt->u.con->name);
  5688. eval_whole_con(mpl, stmt->u.con);
  5689. break;
  5690. case A_TABLE:
  5691. switch (stmt->u.tab->type)
  5692. { case A_INPUT:
  5693. xprintf("Reading %s...\n", stmt->u.tab->name);
  5694. break;
  5695. case A_OUTPUT:
  5696. xprintf("Writing %s...\n", stmt->u.tab->name);
  5697. break;
  5698. default:
  5699. xassert(stmt != stmt);
  5700. }
  5701. execute_table(mpl, stmt->u.tab);
  5702. break;
  5703. case A_SOLVE:
  5704. break;
  5705. case A_CHECK:
  5706. xprintf("Checking (line %d)...\n", stmt->line);
  5707. execute_check(mpl, stmt->u.chk);
  5708. break;
  5709. case A_DISPLAY:
  5710. write_text(mpl, "Display statement at line %d\n",
  5711. stmt->line);
  5712. execute_display(mpl, stmt->u.dpy);
  5713. break;
  5714. case A_PRINTF:
  5715. execute_printf(mpl, stmt->u.prt);
  5716. break;
  5717. case A_FOR:
  5718. execute_for(mpl, stmt->u.fur);
  5719. break;
  5720. default:
  5721. xassert(stmt != stmt);
  5722. }
  5723. return;
  5724. }
  5725. /*----------------------------------------------------------------------
  5726. -- clean_statement - clean specified model statement.
  5727. --
  5728. -- This routine cleans specified model statement that assumes deleting
  5729. -- all stuff dynamically allocated on generating/postsolving phase. */
  5730. void clean_statement(MPL *mpl, STATEMENT *stmt)
  5731. { switch(stmt->type)
  5732. { case A_SET:
  5733. clean_set(mpl, stmt->u.set); break;
  5734. case A_PARAMETER:
  5735. clean_parameter(mpl, stmt->u.par); break;
  5736. case A_VARIABLE:
  5737. clean_variable(mpl, stmt->u.var); break;
  5738. case A_CONSTRAINT:
  5739. clean_constraint(mpl, stmt->u.con); break;
  5740. #if 1 /* 11/II-2008 */
  5741. case A_TABLE:
  5742. clean_table(mpl, stmt->u.tab); break;
  5743. #endif
  5744. case A_SOLVE:
  5745. break;
  5746. case A_CHECK:
  5747. clean_check(mpl, stmt->u.chk); break;
  5748. case A_DISPLAY:
  5749. clean_display(mpl, stmt->u.dpy); break;
  5750. case A_PRINTF:
  5751. clean_printf(mpl, stmt->u.prt); break;
  5752. case A_FOR:
  5753. clean_for(mpl, stmt->u.fur); break;
  5754. default:
  5755. xassert(stmt != stmt);
  5756. }
  5757. return;
  5758. }
  5759. /* eof */