Teknillinen korkeakoulu T-76.115 Tietojenkäsittelyopin ohjelmatyö Lineaaristen rajoitteiden tyydyttämistehtävän ratkaisija L m o d els Tekninen määrittely Ryhmä Rajoitteiset Versio Päivämäärä Tekijä Muutokset 0.1 17.10.2003 Tuomas Luttinen Ensimmäinen alustava versio. 0.2 22.10.2003 Tuomas Luttinen Enemmän sisältöä rungon päälle. Tätä iteraatiota koskemattomat otsikot on poistettu. 0.3 23.10.2003 Tuomas Luttinen Lisäys translaattorin toiminnan kuvaukseen: semanttinen analyysi, hylätyt ratkaisut mukaan. 0.4 24.10.2003 Tuomas Luttinen Palautteiden perusteella uuteen pohjaan muokattu versio. 1.0 26.10.2003 Jouni Karppinen & Mitro Kuha Dokumentti tarkastettu ja korjattu PP-vaiheen palautusta varten. 1.1 25.11.2003 Tuomas Luttinen Edelleen kehitetty versio ensimmäistä toteutusiteraatiota varten. 1.2 29.11.2003 Tuomas Luttinen Ensimmäisen toteutusiteraation lopullinen versio. 2.0 1.12.2003 Jouni Karppinen & Mitro Kuha Dokumentti tarkastettu ja korjattu I1-vaiheen palautusta varten. 2.1 6.2.2004 Tuomas Luttinen Dokumentti päivitetty I2-vaiheen palautusta varten. 3.0 7.2.2004 Jouni Karppinen & Mitro Kuha Dokumentti tarkastettu ja korjattu I2-vaiheen palautusta varten. 3.1 14.3.2004 Tuomas Luttinen Dokumentti päivitetty I3-vaiheen palautusta varten. 4.0 15.3.2004 Jouni Karppinen Dokumentti tarkastettu ja korjattu I3-vaiheen palautusta varten. 4.1 4.4.2004 Tuomas Luttinen Dokumentti päivitetty Delivery-vaiheen palautusta varten 5.0 5.4.2004 Jouni Karppinen Dokumentti tarkastettu ja korjattu DE-vaiheen palautusta varten.
Sisällysluettelo 1 Johdanto...1 1.1 Tarkoitus ja kattavuus...1 1.2 Tuote ja ympäristö...1 1.3 Termit ja määritelmät...1 2 Järjestelmän yleiskuvaus...3 2.1 Sovellusalueen kuvaus...3 2.2 Järjestelmän liittyminen ympäristöönsä...3 2.3 Laitteistoympäristö...3 2.4 Ohjelmistoympäristö...3 2.5 Toteutuksen keskeiset reunaehdot...3 3 Arkkitehtuurin kuvaus...4 3.1 Suunnitteluperiaatteet...4 3.2 Ohjelmistoarkkitehtuuri...4 3.3 Moduulien välinen kommunikaatio...6 3.4 Järjestelmän pakettirakenne...7 3.5 Virheenkäsittely...8 3.6 Normalisointi ja linearisointi...8 3.6.1 Normalisointi...8 3.6.2 Linearisointi...9 4 Moduulikuvaukset...10 4.1 Nodes...10 4.2 Model ja Solver...12 4.3 Formats...13 4.4 Processors...13 4.5 Server...14 4.6 Client ja Controller...15 4.7 Web...16 4.8 Muut luokat...17 5 Hylätyt ratkaisut...18 5.1 Kääntäjän tuottamistyökalut...18 5.2 Lineaarinen ratkaisija...18 5.3 Järjestelmän arkkitehtuuri päätasolla...18 5.4 Palvelinohjelmisto servlettien ajamiseksi...18 Liite A - Normalisointimalli...19 Liite B - Modeller...22 Liite C - Solver...25
1 Johdanto 1.1 Tarkoitus ja kattavuus Tämä dokumentti on Teknillisen korkeakoulun kurssille T-76.115 Tietojenkäsittelyopin ohjelmatyö harjoitustyönä tehtävän lineaaristen rajoitteiden tyydyttämistehtävän ratkaisijan tekninen määrittely. Dokumentin ensisijainen tarkoitus on määrittää ja kuvata vaatimusmäärittelyssä esitettyjen toiminnallisuuksien tekninen toteutustapa ja toisekseen täydentää toiminnallista määrittelyä teknisestä näkökulmasta. Näin ollen dokumentti on suunnattu järjestelmän toteuttajille. Tämän lisäksi sen on tarkoitus antaa asiakkaalle kuva järjestelmän teknisestä toteutuksesta jatkokehitystä varten ja toimia kurssin henkilökunnan apuna projektin arvioinnissa. 1.2 Tuote ja ympäristö Tuotteen nimi on Lmodels. Se on lineaaristen rajoitteiden tyydyttämistehtävän ratkaisija. Tuote toimii verkkoyhteyden tarjoavassa tietokoneessa, jossa on Java-virtuaalikone. 1.3 Termit ja määritelmät Seuraavassa taulukossa on selitetty lyhyesti erikoistermistö, jota käytetään tämän asiakirjan eri kohdissa. Vaatimusmäärittelyssä esitettyjen termien ja määritelmien oletetaan olevan tuttuja lukijalle. Termi Abstrakti syntaksipuu Määrittely Abstrakti syntaksipuu kuvaa lausekkeen sisäisen rakenteen kieliopin terminaaleja sisältävänä puuna. GLPK (GNU Linear Programming Kit) GNU-lisenssin alla jaettava lineaaristen ongelmien ratkaisija. Java-virtuaalikone Jetty Jäsennyspuu Käännettyä Java-koodia sisällään ajava prosessi, joka tarjoaa Javasovellukselle kielen vaatimat palvelut, kuten roskankeruun. Eri alustoille tehdyt virtuaalikoneet mahdollistavat Java-sovellusten ajamisen eri ympäristöissä. Palvelinohjelmisto, joka tarjoaa servleteille sopivan ajoympäristön. Kielen terminaaleista ja nonterminaaleista muodostuva tietorakenne, jossa nonterminaalit sisältävät toisia nonterminaaleja ja puun lehdiksi jääviä terminaaleja. Jäsentäjä Muodostaa selaajalta syötteenään saamista terminaaleista nonterminaalien muodostaman jäsennyspuun, joka kuvaa annetun syötteen rakenteen. lp_solve Javalla toteutettu lineaaristen ongelmien ratkaisija. 1
Termi LP-kieli Määrittely Lineaaristen mallien määrittelyyn käytettävä kieli, jota esim. GLPK hyväksyy syötteenään. Open Source Ohjelmistoja, joiden lähdekoodi on vapaasti saatavilla ja muokattavissa ja jotka ovat muokattuinekin lähdekoodeineen vapaasti käytettävissä ja eteenpäin levitettävissä. RMI-rajapinta (Remote Method Invocation) Tämän rajapinnan avulla yhdessä Java-virtuaalikoneessa sijaitseva olio voi kutsua toisessa virtuaalikoneessa sijaitsevan olion metodia. Virtuaalikoneet voivat sijaita vaikka fyysisesti eri koneissa. Selaaja Servlet Muodostaa tekstipohjaisesta syötteestä säännöllisten lausekkeiden avulla kielen syntaksin mukaisia terminaaleja. Tekniikka tehdä Java-sovellutuksia, jotka vastaavat HTTP-pyyntöihin interaktiivisesti muodostaen WWW-sivuja pyynnön mukana välitettyjen parametrien mukaan. UML (Universal Modelling Language) Ohjelmistojen mallintamiseen käytettäviä kaaviotyyppejä määrittelevä kieli. Taulukko 1: Termit ja määritelmät. 2
2 Järjestelmän yleiskuvaus 2.1 Sovellusalueen kuvaus Lineaaristen rajoitteiden tyydyttämistehtävän ratkaisijana Lmodels pyrkii löytämään ratkaisun malliin annettujen rajoitteiden vallitessa. Mikäli ratkaisu on olemassa, niin käyttäjälle annetaan mahdollisimman tiukat rajat, joiden sisältä kaikki mahdolliset ratkaisut löytyvät, sekä yksi yksiselitteinen ratkaisu. 2.2 Järjestelmän liittyminen ympäristöönsä Lmodels-järjestelmä koostuu palvelinohjelmasta, asiakasohjelmasta sekä komentorivityökalusta, joita ajetaan itsenäisinä kokonaisuuksina. Asiakasohjelma on riippuvainen palvelinohjelmasta, joka kuitenkaan itsenäisenä Java-ohjelmana ei ole sidottu tässä toteutuksessa tehtävään asiakasohjelmaan käyttöliittymineen, vaan sen tarjoamaa RMI-rajapintaa voivat yhtä hyvin hyödyntää ulkopuoliset ohjelmistot, jotka näin voivat käyttää sen tarjoamaa palvelua. 2.3 Laitteistoympäristö Lmodels ei aseta mitään erityisiä vaatimuksia sitä ajavan tietokoneen laitteistolle. Suorituskykyinen kone suurella muistilla on kuitenkin suositeltava, sillä ongelmakenttä, jota Lmodels:lla pyritään ratkaisemaan, on laskennallisesti kompleksinen ongelma. Ajoaika riippuu suuresti mallin koosta ja monimutkaisuudesta, koneen prosessoritehosta ja käytettävissä olevan muistin määrästä. Pienet ja yksinkertaiset mallit hoituvat nopeasti, kun taas suurten tai monimutkaisten mallien ratkaiseminen voi viedä paljon aikaa tehokkaallakin koneella. 2.4 Ohjelmistoympäristö Lmodels-järjestelmän ajoa varten tarvitaan Java-virtuaalikone ja GLPK-ratkaisija. Lmodels:n asentamiseksi tarvitaan näin ollen joko C-kääntäjä GLPK:n kääntämiseksi tai valmiiksi käännetty GLPK. GLPK ei tue perusmuodossaan säikeitä, joten tämän korjaamiseksi on tehty muutostiedosto, jolla GLPK saadaan säieturvalliseksi. Valitettavasti tätä ei ole periaatteellisista syistä hyväksytty osaksi GLPK:n päähaaraa. Haluttaessa käyttää mukana tulevaa asiakasohjelmaa käyttöliittymineen täytyy asentaa myös Java-servlettien ajon mahdollistava J2EE-standardia tukeva servletajoympäristö, koska käyttöliittymä toteutetaan Java-servletteinä. Kyseisenä palvelinohjelmistona tässä projektissa käytetään Jettyä sen ilmaisuuden vuoksi. Java-kielestä käytetään versiota 1.4.1. Ohjelmisto ei aseta rajoitteita käyttöjärjestelmän suhteen, mutta projektiryhmän tarjoama tuki toimii parhaiten Linux-alustalla, sillä kehitystyö on tehty pääasiallisesti sillä. 2.5 Toteutuksen keskeiset reunaehdot Ohjelmiston toteutuksessa käytetään vain ilmaisia, jos mahdollista Open Source, ohjelmistoja. Projektin dokumentit ovat suomenkielisiä, mutta itse ohjelmakoodi ja koodin kommentit ovat englanninkielisiä. Käyttöohje kirjoitetaan suomeksi, mutta ohjelmiston mukana on myös lyhyet englanninkieliset asennus- ja käyttöohjeet erillisissä tiedostoissa. 3
3 Arkkitehtuurin kuvaus 3.1 Suunnitteluperiaatteet Järjestelmän toteutuskieli on Java useammastakin syystä, joista ensimmäinen on asiakkaan vaatimus. Lisäksi ryhmän jäsenet ovat tottuneet työskentelemään tällä kielellä, sitä tuetaan useassa ympäristössä ja sille löytyy laajat valmiskirjastot sekä tämän projektin vaatimia kääntäjiin liittyviä työkaluja jäsentäjän automatisoituun tekemiseen. Järjestelmään liittyvä käyttöliittymä toteutetaan Java-servletteinä ja HTML-kieltä käyttäen. Vaikka järjestelmässä on mukana käyttöliittymä, niin tällä kertaa suunnittelun painopiste ja sitä eteenpäin ajava voima on teknisellä puolella. Käyttöliittymä on tarkoitettu lähinnä testaamiseen, koska pääkäyttötapa järjestelmälle jatkossa on osana integroitua suurempaa järjestelmää, jolloin Lmodels:n käyttäjiä ovat toiset ohjelmistojärjestelmät. Järjestelmä toteutetaan käyttäen oliopohjaista mallinnusta ja erilaisia UML-kaavioita eri osien mallintamiseen. Koska koodin toteutuskielenä on englanti, niin kaavioiden kielikin on näin ollen englanti. Eri komponentteihin viitataan pääsääntöisesti kuitenkin tämän dokumentin kielellä eli suomeksi, joten tätä tapaa käytettäessä on kaavioissa esiintyvä englanninkielinen nimi laitettu sulkuihin suomalaisen termin perään, mikäli sitä ei ole saatu liitettyä asiayhteyteen jouhevasti muulla tavoin. 3.2 Ohjelmistoarkkitehtuuri Koska Lmodels-järjestelmällä tulee olemaan ulkopuolinen ohjelma käyttäjänään, on se suunniteltu palvelin-asiakas -mallin mukaiseksi ohjelmistoksi. Näin Lmodelsille syntyi ydin, joka tuottaa ratkaisut sille syötettyihin malleihin ja jolla on rajapinnat ulkoisia käyttäjiä varten. Suurin osa järjestelmän sisäisistä toiminnallisuuksista on koteloitu omiksi moduleikseen, joiden nimet jo kertovat mitä moduli tekee, esimerkiksi linearisoija linearisoi sille syötetyn normaalimuotoisen mallin. Kokonaisuutta ohjaamaan kehitettiin vielä erillinen moduli, joka nimettiin kontrolleriksi tehtävänsä mukaisesti. Näin syntyneen Lmodels-järjestelmän yleistason kuva on esitetty seuraavassa kaaviossa. formats CLIClient WWW client client server controller processors model nodes solver Kaavio 1: Lmodels-järjestelmä. Ulkoisella käyttäjällä, joka tässä kehitysvaiheessa on vielä ihminen, on kaksi tapaa käyttää järjestelmää: joko paikallisesti komentorivikäyttöliittymällä tai verkon yli WWWkäyttöliittymällä. Molemmissa tapauksissa järjestelmän keskuksena toimii kontrolleri 4
(controller), joka sisältää järjestelmän toimintalogiikan ja joka tuottaa vastaukset käyttäjän tekemiin kyselyihin. Seuraavassa sekvenssikaaviossa on esitettynä esimerkki, jossa Lmodels:ia käytetään komentorivityökalun avulla lineaarisen ongelman ratkaisuun. ModelProcessor :CLIClient controller:controller Format processor:cnfnormaliser ModelProcessor solver:glpksolver main(args[]) create() parser:lmformat processor:lineariser solversolution:=solve(text, limits) create() :SolverFactory model:=parse(text) create() model:=process(model) create() model:=process(model) solver:=getsolver(glpk) create() solversolution:=solve(model, limits) Kaavio 2: Sekvenssikaavio komentorivityökalusta. Komentoriviltä käynnistetään komentorivityökalu (CLIClient), joka käynnistää itselleen uuden kontrollerin (controller), jolle annetaan metodikutsun argumentteina ongelman malli tekstimuodossa ja kiinnitetyt muuttujat arvoineen. Kontrollerin tehtävänä on nyt päätellä, mitä vaiheita tarvitaan mallin käsittelyyn, ennen kuin se voidaan toimittaa varsinaiselle ratkaisimelle ratkaistavaksi. Tässä tapauksessa malli on tekstimuodossa ilman, että sitä olisi normalisoitu tai linearisoitu. Siksi kontrolleri käy kaikki askeleet läpi käyttäen lm-muodon jäsentäjää (parser:lmformat) mallin jäsentämiseksi, CNF-muodon normalisoijaa (processor:cnfnormaliser) normalisointiin, linearisoijaa (Lineariser) linearisointiin ja lopuksi ratkaisijatehdasta (SolverFactory) tuottamaan sopivan ratkaisijainstanssin, joka etsii mahdolliset ratkaisut annettuun ongelmaan. Tekniseltä kannalta kontrollerin ohjaamien moduulien voidaan katsoa muodostavan kääntäjän alkupuolen mukaisen selkeän peräkkäisrakenteen. Siinä ensimmäinen askel on tekstimuotoisen syötteen jäsennys, minkä jälkeen seuraavat moduulit tekevät erilaisia muutoksia aikaansaatuun abstraktiin syntaksipuuhun. Linjan viimeisenä oleva moduuli tuottaa abstraktista syntaksipuusta taas tekstimuotoista tulostetta. Tämä muoto on esitetty kaaviossa 3. 5
0..* General File Format String Model ModelProcessor Model ModelProcessor Model Translator Command line tool File LMFormat CNFNormaliser String Model Model LPX command line tool File LMFormat CNFNormaliser Lineariser String Model Model Model (Un)Bind variables Result model Server mode User File String LMFormat Model CNFNormaliser Model Linearisator String Format / ModelSolver Results model File User Kaavio 3: Lmodels kääntäjänä. LMFormat File String LPXFormat File String Model GLPKSolver Vasemmalla on esitetty yleinen malli, jossa syöte tuodaan tekstimuodossa sisään jäsentäjälle, sitä käsittelee yksi tai useampi puun käsittelijä (ModelProcessor) ja lopuksi se joko kirjoitetaan taas tekstimuodossa tiedostoon tai lähetetään ratkaisijalle (ModelSolver). Puun käsittelijöitä ovat normalisoijat ja linearisoija. Mallia voidaan normalisoijilla pyöritellä mielin määrin CNF- ja DNF-muotoihin ennen linearisointia. Kaavion 3 kaksi seuraavaa mallia kuvaavat komentorivityökalujen käyttöä ja niissä on abstraktien rajapintojen sijaan käytetty realisoituvia luokkia. Viimeisin esimerkki oikealla kuvaa palvelimen sisällä käytettyä ketjua ongelman saamiseksi ratkaistavaksi. 3.3 Moduulien välinen kommunikaatio Järjestelmässä on kaksi rajapintaa, joiden kohdalla se voidaan hajauttaa useampaan fyysiseen koneeseen ja kommunikaatio toimii verkkorajapinnan yli. Nämä rajapinnat ovat käyttöliittymän käyttämä HTTP-rajapinta selaimen ja servletpalvelimen välillä sekä järjestelmän sisäinen RMI-rajapinta, joka on esitelty seuraavassa kaaviossa. 6
«Factory» ClientFactory +getclient(clienttype:int): Client creates «interface» Client ServerSolver starts RemoteClient +connect(): RMIServer +getconnector(): RemoteController returns RemoteController Controller <<RMI>> <<RMI>> «interface» RMIServer Controller RMIServerImpl +getconnector(): RMIController returns SimpleController «interface» 1 RMIController RMIControllerImpl Kaavio 4: RMI-arkkitehtuuri. Luokka ServerSolver käynnistää RMI-prosessin palvelimen puolella ja jää kuuntelemaan pyyntöjä. Asiakasohjelma käynnistyy ja pyytää itselleen asiakastehtaasta (ClientFactory) uuden asiakasrajapinnan (Client) toteutuksen ja saa itselleen RMI:tä tukevan asiakasolion (RemoteClient). Tämä ottaa yhteyden palvelimeen ja saa itselleen viitteen RMIpalvelimeen (RMIServer), jolta asiakasolio saa viitteen palvelimen kontrolleriin (RMIController), joka tallennetaan asiakaspäässä omaan olioonsa (RemoteController). Tämän jälkeen asiakas voi käyttää oman päänsä kontrolleria (RemoteController) aivan normaaliin tapaan, koska RMI:n toteutus mahdollisine ongelmatilanteineen on upotettu sen sulkeviin luokkiin. Itse työn tekee palvelimen päässä tavallinen kontrolleri (SimpleController), jolle pyynnöt ohjataan RMI-rajapinnan yli. Kuvan keskellä kulkevan jakolinjan yli menevä liikenne voi tapahtua verkon välityksellä kahden eri fyysisen koneen välillä. Tällöin Lmodels voidaan jakaa kahdelle koneelle siten, että toinen näistä koneista ratkoo ongelmia toisen toimiessa palvelimena, joka tarjoaa käyttäjän selaimelle tarpeellisen WWW-palvelun. Integroitaessa Lmodels:ia asiakkaan laajempaan järjestelmään tulee yllä kuvatusta RMI-rajapinnasta toisten ohjelmakomponenttien käyttöliittymä Lmodels-järjestelmään. 3.4 Järjestelmän pakettirakenne Järjestelmän pakettirakenne on esitetty kaaviossa 5. Pakettien riippuvuudet ketjuuntuvat alaspäin vieviksi ketjuiksi ilman silmukoita. Ylimpänä tasona ovat palvelin- (server) ja asiakas- (client) paketit, jotka kommunikoivat kontrollerin (controller) kanssa, joka puolestaan käyttää muista paketeista löytyviä luokkia ja niiden metodeita ratkaistakseen lineaarisia ongelmia. 7
lmodels client server controller model processors formats solver nodes Kaavio 5: Lmodels:in pakettikaavio. 3.5 Virheenkäsittely Virheenkäsittely Lmodels-järjestelmässä perustuu pakettikohtaisiin poikkeuksiin, joita on yksi kutakin pakettia kohden. Yleisesti kyseisen paketin rajapinta ilmoittaa heittävänsä tämän poikkeuksen ongelmatilanteissa, johon rajapinnan hyödyntäjän tulee varautua. Jokaisesta kerroksesta pyritään tekemään mahdollisimman hyvin alemman kerroksen virheitä sietävä. 3.6 Normalisointi ja linearisointi Mallin käsittelyyn käytetään kahta prosessia, jotka ovat luonteeltaan matemaattisia ja varsin monimutkaisia. Näiden tarkempi toteutus on esitettynä tämän dokumentin liitteissä, mutta tässä on satunnaiselle lukijalle tiivistetty versio näistä prosesseista. 3.6.1 Normalisointi Normalisointi tarkoittaa loogisen yhtälön muuttamista muotoon, jossa joko JA- (konjunktiivinen) tai TAI-operaattorit (disjunktiivinen) ovat yhdistämässä muiden operaattoreiden muodostamia alilausekkeita ja jonka ratkaisu on yhtäpitävä alkuperäisen yhtälön kanssa. Lmodels:ssa käytetään lineaaris-loogisia malleja, jotka muutetaan normalisoiduiksi lineaaris-loogisiksi malleiksi noudattaen samoja menetelmiä kuin loogisen mallin kanssa, sillä lineaarisissa yhtälöissä oleva vertailuoperaattori antaa koko yhtälölle loogisen arvon. 8
3.6.2 Linearisointi Määritelmän mukaan linearisoitaessa loogisia rajoitteita ja lineaarisia sekalukurajoitteita sisältävä malli muutetaan lineaariseksi sekalukumalliksi. Lmodelsin tapauksessa tämä tarkoittaa sitä, että lineaaris-loogisesta mallista muokataan lineaarinen malli korvaamalla loogiset muuttujat numeerisilla muuttujilla ja loogiset lausekkeet lineaarisilla lausekkeilla käyttäen tarvittaessa apumuuttujia. 9
4 Moduulikuvaukset Seuraavissa kappaleissa on esitelty jokaisen paketin sisältö pääkohdittain sekä mahdollinen rajapinta, jolla paketin sisältämiä luokkia voidaan käyttää. Paketit on käyty läpi periaatteella bottom-up, eli ensimmäisen on esitelty mallin sisäisen rakenteen rakennuspalikat, tämän jälkeen itse malli, mallia muokkaavat kokonaisuudet ja viimeiseksi nämä Lmodels-järjestelmäksi niputtavat osat ja käyttöliittymä näiden päälle. Lisäksi esitellään vielä erilliset luokat, jotka käyttävät koko järjestelmää. 4.1 Nodes Tämän paketin luokkien tarkoitus on muodostaa abstrakti syntaksipuu, joka kuvaa mallin sisältämien yhtälöiden rakenteen. Alla on kuvattu paketin luokkarakenne. Expr +getnew(...): Expr BooleanExpr +getnew(...): BooleanExpr FloatExpr +getnew(...): FloatExpr BinaryBooleanExpr Not Comparison BooleanVariable +left: BooleanExpr +Right: BooleanExpr +getnew(booleanexpr,booleanexpr) +leftexpr +getnew(booleanexpr) +left: FloatExpr +right: FloatExpr +getnew(floatexpr,floatexpr) +name: String +negated: Boolean BooleanConstant And Or Xor Equiv Impl EQ NEQ GT LT GE LE Sub Luokasta ei oteta instansseja, getnew palauttaa AINA toisen luokan instanssin. BinaryFloatExpr +getnew(floatexpr,floatexpr,) FloatVariable +mul: double +name: String Add Sub Mul Div UMinus +getnew(floatexpr) FloatConstant Kaavio 6: Paketin nodes luokkakaavio. 10
Erityistä huomiota kannattaa kiinnittää siihen, että läheskään kaikista operaattoreista ei luoda oman luokkansa instansseja. Niiden sijaan käytetään toisten operaattoriluokkien instansseja, joilla saadaan sama asia ilmaistua toisella samanarvoisella tavalla. Tämän ansiosta lopullisen puun käsittelyssä selvitään vähemmällä vaivalla, koska erilaisia operaattoreita on rajoitetummin. Seuraavassa taulukossa on kuvattu puun muodostamisen apuna käytetyt operaattoreiden korvaavuudet. Luokka Lause Korvattu lause Xor a xor b ( a and not b) or (not a and b) Equiv a equiv b not(a) xor b Implies a implies b not(a) or b Sub j - k j + -1*k Uminus -k -1 * k Div k/4 0.25 * k Taulukko 2: Korvattavat operaattorit korvaavuuksineen. Alla olevassa kaaviossa on vielä kuvattuna esimerkkinä eräs konjunktiivisessa normaalimuodossa oleva lauseke abstraktina syntaksipuuna. Expr Tree in CNF and or and 3.1*A >= + 0 + not K or or P NOT p and or 3*B 12 + >= 0 or K not T 3*A + K not T 3*B + -2.1*D -12 Kaavio 7: Abstrakti syntaksipuu konjunktiivisessa normaalimuodossa. 11
4.2 Model ja Solver Seuraavassa kaaviossa on esitetty pakettien model ja solver sisältö luokittain. model solver Model 1 SolverFactory «interface» ModelSolver 1 Vmap SolverSolution cputime: int modelsize: int AbstractSolver * Variable 1 1..* VariableSolution SolverEvent GLPKSolver 0..1 VariableLimits «interface» SolverListener Kaavio 8: Pakettien model ja solver luokkakaavio. Paketin model pääluokka on mallin (Model) sisältävä luokka, joka sisältää muuttujien määritelmät omassa luokassaan (Vmap). Tämän luokan sisäinen toteutus on linkitetty hajautustaulu, johon on säilötty muuttujia omassa luokassaan (Variable). Malli yhdessä kiinnitettyjen muuttujien (VariableLimits) kanssa muodostaa ongelman. Sille on olemassa ratkaisu (SolverSolution), joka puolestaan sisältää ongelman jokaiselle muuttujalle ratkaisun (VariableSolution), joka puolestaan sisältää muuttujan rajat ja käyvän ratkaisun, mikäli sellainen löydettiin. Paketissa solver on ratkaisijaan liittyviä luokkia. Seuraavassa taulukossa on esitelty paketin rajapinnat. Rajapinta Merkitys ModelSolver Ratkaisijan määrittelevä rajapinta. Sisältää metodit lineaarisen ongelman ratkaisemiseksi sekä kuuntelijan (SolverListener) lisäämiseen ja poistamiseen. SolverListener Kuuntelija, joka seuraa ratkaisijan työn edistymistä. Ratkaisija tiedottaa edistymisestään tapahtumilla (SolverEvent). Taulukko 3: Rajapinnat solver-paketissa. Erilaisten ratkaisijatyyppien tuottamiseksi paketissa on tehdasluokka (SolverFactory), joka luo ratkaisijoita annetun tekstitunnisteen mukaan. Muita paketin luokkia ovat tapahtuma (SolverEvent), jolla tiedotetaan ratkaisijan edistymisestä, sekä SolverSolution, joka 12
sisältää ongelman ratkaisun sekä tähän ratkaisuun liittyvää oheistietoa, kuten käytetyn koneajan ja mallin koon. 4.3 Formats Seuraavassa kaaviossa on esitetty tämän paketin luokkarakenne. processors «interface» ModelProcessor +process(m:model): Model Lineariser ModelNormaliser CNFNormaliser DNFNormaliser Kaavio 9: Paketin formats luokkakaavio. Tämä paketti sisältää seuraavan rajapinnan ja sen toteuttavia luokkia. Rajapinta Merkitys Format Muotoilijan (Format) määrittelevä rajapinta. Sisältää metodit lineaarisen mallin muodostamiseen tekstisyötteestä sekä lineaarisen mallin tulostamiseksi tekstimuotoon. Taulukko 4: Rajapinta formats-paketissa. Rajapinnan toteutusluokkia on kaksi kappaletta. Näistä ensimmäinen käsittelee määrittelemäämme lm-kieltä ja toinen lineaaristen mallien kuvaamiseen yleisesti käytettyä lpx-kieltä. 4.4 Processors Kaaviossa 10 on esitetty tämän paketin luokkarakenne. Paketti sisältää edellisen paketin tavoin yhden rajapinnan sekä sen toteuttavia luokkia. 13
processors «interface» ModelProcessor +process(m:model): Model Lineariser ModelNormaliser CNFNormaliser DNFNormaliser Kaavio 10: Paketin processors luokkakaavio. Rajapinta ModelProcessor Merkitys Mallin prosessoijan (ModelProcessor) määrittelevä rajapinta. Tämän rajapinnan ainoa metodi on process, joka ottaa sisäänsä argumenttina annetun mallin ja palauttaa uuden, prosessoidun mallin. Taulukko 5: Rajapinta processors-paketissa. Toteuttavia luokkia on processors-paketissa useampia, ja ne jakautuvat kahteen lajiin: mallin linearisoijaan (Lineariser) ja normalisoijiin. Jälkimmäisiä on yksi isäluokka (ModelNormaliser) ja toteutukset kahdelle eri normaalimuodolle (CNFNormaliser, DNFNormaliser). 4.5 Server Seuraavassa kaaviossa on esitetty tämän paketin luokkarakenne. server <<interface>> RMIServer <<interface>> RMIController RMIServerImpl +getconnector(): RMIController RMIControllerImpl Kaavio 11: Paketin server luokkakaavio. 14
Paketti server sisältää RMI-rajapinnan palvelinpuolen toteutuksen sekä rajapinnat näiden toteutusten viitteen toimittamiseksi RMI-yhteyden yli, jotta metodikutsut voidaan välittää toiseen koneeseen. Rajapinta Merkitys RMIServer Rajapinta RMIServer määrittelee RMI-rajapintaa kuuntelevan palvelimen ja sen metodin getconnector, jolla saadaan toimitettua viite kontrollerista RMI-rajapinnan toiselle puolelle. RMIController Taulukko 6: Rajapinnat server-paketissa. Rajapinta RMIController määrittelee samat metodit kuin rajapinta Controller mallin käsittelemiseksi RMI-rajapinnan yli. Palvelimen toteutus (RMIServerImpl) on siis konkreettinen olio, joka toimii RMIpalvelimena. Kontrollerin RMI-toteutus (RMIControllerImpl) puolestaan käyttää suoraan tavallista kontrolleria (SimpleController) toteuttaakseen mallin käsittelyn metodit. 4.6 Client ja Controller Paketti controller sisältää edellisten pakettien tavoin yhden rajapinnan sekä sen toteuttavan luokan. Tämän rajapinnan toteuttava luokka on myös paketissa client liittyen kontrollerin käyttöön RMI-rajapinnan yli. Rajapinta Merkitys Controller Rajapinta Controller määrittelee metodit, joilla mallia voidaan järjestelmän ulkopuolelta käsitellä. Taulukko 7: Rajapinta controller-paketissa. Yksinkertainen kontrolleri (SimpleController) on rajapinnan ainoa täysi toteutus, joka sisältää tarpeellisen logiikan mallin vaatiman käsittelyn selvittämiseen annettujen parametrien ja mallin itsensä avulla. Muiden saman rajapinnan toteuttavien luokkien toiminta palautuu tämän luokan metodien kutsumiseen. 15
client ClientFactory +getclient(): Client creates <<interface>> Client LocalClient +getconnector(): Controller RemoteClient +connect(address:string) +getconnector(): Controller returns returns RemoteController controller <<interface>> Controller SimpleController Kaavio 12: Pakettien client ja controller luokkakaavio. Kaaviossa 12 on esitetty pakettien client ja controller luokkarakenne. Seuraava taulukko esittelee paketin client sisältämän rajapinnan. Rajapinta Client Merkitys Rajapinta Client määrittelee asiakkaan metodit, joilla otetaan yhteys palvelimeen ja saadaan viite kontrolleriin. Taulukko 8: Rajapinta client-paketissa. Paketti sisältää tehdasluokan (ClientFactory), jolla luodaan asiakas (Client) tilanteen mukaan. Kyseisen rajapinnan toteuttavista luokista paikallinen asiakas (LocalClient) toteuttaa vain metodin getconnector, jolla se luo uuden tavallisen kontrollerin (SimpleController). Etäasiakas (RemoteClient) toteuttaa metodin connect, jolla luodaan yhteys palvelimeen. Tämän luokan metodi getconnector pyytää palvelimen puolelta viitteen RMI-kontrolleriin (RMIController), joka suljetaan etäkontrolleriluokan (RemoteController) olioon RMI-yhteyden piilottamiseksi ulkopuoliselta käyttäjältä. 4.7 Web 16
Paketin web sisältämät luokat muodostavat Lmodels-järjestelmän testikäyttöön rakennetun web-käyttöliittymän. Paketissa on rajapinta Page, jonka toteuttavat EditingPage, SolverPage ja HelpPage luokat, jotka yhdessä muodostavat käyttöliittymän. Lisäksi pakettiin kuuluu SimpleServer, joka toteuttaa yksinkertaisen käyttäjän selainta palvelevan web-palvelimen ja FrontControllerServlet, joka ohjaa sisääntulevat kutsut oikealle sivulle. 4.8 Muut luokat Yllämainittujen alipakettien lisäksi paketti lmodels sisältää kolme Java-luokkaa, jotka ovat main-metodin sisältävinä luokkina tarkoitettu käynnistämään järjestelmä eri toimintamuotoihin eli komentorivityökaluna, palvelimena ja asiakasohjelmana. 17
5 Hylätyt ratkaisut Projektissa tuli eteen tullut kohtuullinen määrä valintatilanteita, joissa on otettu kantaa teknisen toteutuksen moniin kohtiin alkaen kääntäjän tuottamiseen käytettävistä työkaluista aina kokonaistason arkkitehtuuriin. 5.1 Kääntäjän tuottamistyökalut Ensimmäisenä asiana on translaattorin luomisessa apuna käytettävät kääntäjän tuottamistyökalut, joiksi päätettiin ottaa CUP ja JLex. Näiden vaihtoehtona oli kehittyneempi, myös itsensä Sunin tukema Open Source työkalu JavaCC, joka on sekä jäsentäjän että selaimen generoiva työkalu. Emme kuitenkaan valinneet tätä mentorimmekin suosittelemaa työkalua, vaan käytämme jäsentäjän generointiin CUP:ia ja selaimen generointiin JLex:iä, koska asiakkaamme oli vanhempien työkalujen puolella ja ryhmällä itsellään on kokemusta niiden käytöstä päinvastoin kuin JavaCC:n kohdalla. 5.2 Lineaarinen ratkaisija Toinen hylkäävä ratkaisu on myös tehty lineaarisen ratkaisijan kohdalla, sillä ratkaisijaksi oli GLPK:n lisäksi tarjolla Javalla toteutettu lp_solve. Vaikka tätä ratkaisua olisi voinut puolustaa toteutuskielen yhtenäisyydellä, niin hylkäämiseen johtaneet seikat veivät voiton. Nimittäin vaikka lp_solve on toteutettu Javalla, niin se vaikutti tehdyn automaattisesti aikaisemmasta C-toteutuksesta. Myöskään sen ylläpidosta ei ollut minkäänlaisia takeita, sillä sen toteuttamiseen käytetty Java-versiokin oli jo aika vanha. 5.3 Järjestelmän arkkitehtuuri päätasolla Suunnitteluvaiheessa oli esillä suuremmista kokonaisuuksista koostuva arkkitehtuuri järjestelmän toteuttamiseksi. Tästä kuitenkin luovuttiin, koska nämä suuremmat kokonaisuudet koettiin liian raskaiksi ja kömpelöiksi, joten lopullisen arkkitehtuurin kohdalla päädyttiin käyttämään pienemmistä osista koostuvaa ketjua, jonka lisäksi järjestelmässä on erillinen logiikka, joka ohjaa ketjun käyttäytymistä. Tällöin tämä logiikka voi jättää vaikka osan ketjusta pois, mikäli sisään syötetään jo osin käsiteltyä syötettä, kuten esimerkiksi normalisoitu malli. 5.4 Palvelinohjelmisto servlettien ajamiseksi Ryhmä päätti luopua Tomcatista sen suuren koon ja raskauden vuoksi. Sen sijaan servlettejä ajetaan Jettyllä, joka on toinen vapaan ohjelmakehityksen aikaansaama servleteille kirjoitettu palvelinohjelmisto. 18
Liite A - Normalisointimalli Yleistä Tämän dokumentin tarkoitus on kuvata algoritmia, jolla normalisointi tapahtuu. Tässä dokumentissa on pyritty ymmärrettävyyteen matemaattisen eksaktiuden sijasta. (Ei siis TKK-tyyliä, jossa väännetään kaavaa ja ymmärtäminen on kuulijan ongelma.) Tätä dokumenttia ei kannata käyttää virheiden etsimiseen mallista, koska ohjelmakoodia on testattu aika paljon toisin kuin tätä dokumenttia, joten todennäköisesti virhe on tässä dokumentissa eikä ohjelmakoodissa. Tätä dokumenttia sen sijaan kannattaa käyttää mallin ymmärtämisen tukena tai apuna sen määrittelemiseen mitä voisi tehdä tehokkaammin. Algoritmin toiminta Normalisointi jakaantuu 3 vaiheeseen. Ensimmäisessä vaiheessa luetaan muuttujat typpeineen ja rajoineen. Seuraavassa luetaan itse lausekkeet käyttäen apuna muuttujien tyyppejä ja rajoja. Muuttujia, joita ei ole määritelty, ei hyväksytä, vaan heitetään poikkeus, jos niitä ilmenee. Näistä rakennetaan puu alkaen lehdistä. Jokainen puun alkio luodaan nodes-paketin getnew-metodilla, jolle annetaan parametreinä sen alipuut. Puussa jokaisella alkiolla on 0-2 alialkiota, joten se on eräänlainen binääripuu. Kaikki operaattorit siis yksi- tai kaksioperandisia ts. kaava a+b+c+d on meidän kannaltamme (a+(b+(c+d))) (voi olla muutakin, mutta se muu supistetaan tuohon muotoon edempänä tulevilla kaavoilla.) Edellä mainitut getnew-metodit hoitavat yleiset supistukset, eivätkä aina palauta sen luokan instanssia, joille ne on kutsuttu vaan voivat supistaa lauseketta, niin että tuloksena on toisen luokan instanssi. Tässä on kuvattu yksinkertaistetusti säännöt, joiden avulla alkiot muutetaan. Säännöt käydään järjestyksessä päättyen ensimmäiseen sääntöön, joka sopii. Sääntö johtaa usein uuden lausekkeen osan luontiin, joka johtaa taas uusien sääntöjen soveltamiseen sen osille joko samasta tai toisesta operaattorista. Lauseke käsitellään siis aina alkaen lehdistä päättyen juureen. Säännöt eri lausekkeen osille: And: false and a _korvataan_ false a and false _korvataan_ false a and true _korvataan_ a, true and b _korvataan_ b a and (a and xx) _korvataan_ (a and xx) a and (not a and b) _korvataan_ false K and K _korvataan_ K K and not K _korvataan_ false a and (a and xx) _korvataan_ (a and xx) a and (... a and (xx)...) _korvataan_ (... a and (xx)...) a and (... and (a and..)) _korvataan_ (... and (a and...)) 19
a and (not a and xx) _korvataan_ false a and (... and (not a and xx)) _korvataan_ false (a and b) and xxx _korvataan_ (a and (b and xxx)) E and C _korvataan_ C and E (järjestäminen, vain muuttujille) E and (C and xxx) _korvataan_ C and (E and xxx) (järjestäminen, vain muuttujille) Muutoin: a and b Or: true or a _korvataan_ true a or true _korvataan_ true false or K _korvataan_ K K or K _korvataan_ K K or not K _korvataan_ true a or (a or xx) _korvataan_ (a or xx) a or (... or (a or xx)) _korvataan_ (... (a or xx)) a or (not a or xx) _korvataan_ true a or (not a or xx) _korvataan_ true a or (... not a or...) _korvataan_ true (a or b) or xxx _korvataan_ (a or(b or xxx)) E or C _korvataan_ C or E (järjestäminen,vain muuttujille) E or (C or xxx) _korvataan_ C or (E or xxx) (järjestäminen,vain muuttujille) Not: not(not(a)) _korvataan_ a not(xx and yy) _korvataan_ not(xx) or not(yy) not(xx or yy) _korvataan_ not(xx) and not(yy) not( a) _korvataan_ not a (vain muuttujille) not( not a) _korvataan_ a (vain muuttujille) muutoin: (ei tapahdu) not ( a) "not a" tarkoitaa tässä boolean muuttujan a instanssia, joka on invertoitu. not ( a) tarkoittaa not operaattoria operandilla a. Xor: a xor b _korvataan_ ((a or b) and ((not a) and (not b)) Implies: a implies b _korvataan_ (not a) or b Equiv: a equiv b _korvataan_ (not a) xor b Mul: (kertolasku) jos a * b, missä a tai b ei ole vakio, heitetään poikkeus. 3 * 2 _korvataan_ 6 3 * a _korvataan_ 3a a * 3 _korvataan_ 3a 3 * ((x) + (y)) _korvataan_ 3 * (x) + 3 * (y) 20
((x) + (y)) * 3 _korvataan_ 3 * (x) + 3 * (y) muutoin (ei tapahdu) a * b Mikäli kahden muuttujan kertolaskua tavataan, niin heitetään poikkeus epälineaarisesta mallista, ellei sen salliva parametri ole asetettu. Parametrin asettamisesta ei kuitenkaan ole hyötyä, sillä Lmodels ei osaa käsitellä epälineaarisia malleja. Tämä on vain tulevaisuutta varten. 3a tarkoittaa muuttujaa a, johon on sisällytetty kerroin 3. Kaikilla numeeristen muuttujien instansseilla on kertoimet. Add: (yhteenlasku) 2+3 _korvataan_ 5 3a+5a _korvataan_ 8a (b+c)+d _korvataan_ b+(c+d) E + C _korvataan_ C + E 3+(4+xxx) _korvataan_ 7+xxx 2A + (3A + xxx) _korvataan_ 5a+xxx E + (C + xxx) _korvataan_ C + (E + xxx) muutoin a + b Div: (jakolasku) a/4 _korvataan_ 0.25a 1/4 _korvataan_ 0.25 Muuttujalla jakamista ei tueta, koska se ei ole lineaarista, ellei epälineaarisuden sallivaa parametria ole asetettu. Kolmas vaihe on että tehdään itse normalisointi. Se tehdään vain muutaman säännön pohjalta. Täytyy huomata, että aina kun luodaan uusia edellä mainittuja olioita, niin aiempinen supistussäntöjen mukaiset operaatiot tehdään myös siinä. Normalisointi konjuktiiviseen muotoon (CNF): (al and ar) or b _korvataan_ (al or b) and (ar or b) PAITSI jos al == b, niin _korvataan_ ar or b tai jos ar == b, niin _korvataan_ al or b a or (bl and br) _korvataan_ (br or a) and (bl or a) PAITSI jos a == bl _korvataan_ (a or br) tai jos a == br _korvataan_ (a or bl) Normalisointi disjunktiivisen muotoon (DNF): (al and ar) or b _korvataan_ (al or b) and (ar or b) paitsi jos b == al tai b == ar, niin _korvataan_ b a or (bl and br) _korvataan_ (br or a) and (bl or a) paitsi jos a == bl tai a == br, niin _korvatan_ a 21
Liite B - Modeller Muodostetaan rajoitteet disjunktioille tai konjunktioille sekä rajat muuttujille, kun X on kaikkien boolean-muuttujien joukko, X on niiden boolean-muuttujien joukko, jotka ovat kiinnitettyjä johonkin arvoon x, Y on kaikkien kokonaislukuja liukulukumuuttujien joukko ja Y on niiden kokonaisluku- ja liukulukumuuttujien joukko, jotka ovat kiinnitettyjä johonkin arvoon y. Tavoitefunktio ja kokonaislukumääritykset annetaan ylemmällä tasolla. Muuttujat x, z ja w ovat 0-1-muuttujia, kun taas muuttujat y ovat osin kokonaislukumuuttujia ja osin liukulukumuuttujia. K = 0, Z =, W = Jokaiselle lausekkeelle E i, joka on joko disjunktio D i tai konjunktio C i X + =, X - =, Z + =, Z - = Jokaiselle lausekkeelle B ij lausekkeessa E i Jos B ij on x h X + = X + {h} Muutoin jos B ij on x h X - = X - {h} Muutoin c l ij = h aijh > 0 a ijh * y l h + h aijh < 0 a ijh * y u h c u ij = h aijh > 0 a ijh * y u h + h aijh < 0 a ijh * y l h. K = K + 1 Z = Z {K} Jos B ij on ( h a ijh * y h c ij ) Muodosta { h a ijh * y h (c ij c l ij) * z K c l ij} Z + = Z + {K} Muutoin jos B ij on ( h a ijh * y h c ij ) ja Muodosta { h a ijh * y h + (c ij c l ij) * z K c ij } Z - = Z - {K} Muutoin jos B ij on ( h a ijh * y h c ij ) Muodosta { h a ijh * y h (c ij c u ij) * z K c u ij} Z + = Z + {K} Muutoin jos B ij on ( h a ijh * y h c ij ) Muodosta { h a ijh * y h + (c ij c u ij) * z K c ij } Z - = Z - {K} Seuraava lauseke B ij Jos E i on disjunktio
Muodosta { h X+ x h h X- x h + k Z+ z k k Z- z k 1 X - Z - } Muutoin jos E i on konjunktio W = W {i} Muodosta { h X+ x h h X- x h + k Z+ z k k Z- z k X + Z + X - Z - * w i X - Z - } Seuraava lauseke E i Jos W Muodosta { i W w i 1} Jokaiselle muuttujalle x h X Seuraava x h Jos x h X Muodosta {x h x h x h } Muutoin Muodosta {0 x h 1} Jokaiselle muuttujalle z k Z Seuraava z k Muodosta {0 z k 1} Jokaiselle muuttujalle w i W Seuraava w i Muodosta {0 w i 1} Jokaiselle muuttujalle y h Y Jos y h Y Muodosta {y h y h y h } Seuraava y h Muutoin Muodosta {y l h y h y u h} Esimerkki Olkoon esimerkkitehtävä seuraavaa muotoa: Y 1 [0,3] Y 2 [1,4] X (Y 1 Y 2 < 2) ja Y 1 kiinnitetty arvoon 1. Konjunktiivinen normaalimuoto: ( X (Y 1 Y 2 2)) (X (Y 1 Y 2 2)) Etsitään X:lle alaraja: min x
y 1 y 2 + (2 (0 4)) * z 1 2 x z 1 1 2 y 1 y 2 (2 (0 4)) * z 2 0 4 x + z 2 1 0 x 1 0 z 1 1 0 z 2 1 1 y 1 1 1 y 2 4 Disjunktiivinen normaalimuoto: X (Y 1 Y 2 2)) ( X (Y 1 Y 2 2)) Etsitään Y 1 :lle yläraja: max y 1 y 1 y 2 + (2 (0 4)) * z 1 2 x z 1 2 * w 1 1 y 1 y 2 (2 (0 4)) * z 2 0 4 x + z 2 2 * w 2 1 w 1 + w 2 1 0 x 1 0 z 1 1 0 z 2 1 0 w 1 1 0 w 2 1 0 y 1 3 1 y 2 4
Liite C - Solver Olkoon X kaikkien, X kiinnitettyjen (x h = x h ) boolean-muuttujien, Y I kaikkien kokonaislukumuuttujien, Y F kaikkien liukulukumuuttujien sekä kiinnitettyjen Y (y h = y h ) kokonais- ja liukulukumuuttujien joukko. Lisäksi olemassa voi olla kaikkien apumuuttujien Z ja W joukot. Muuttujien X ja Y = Y I Y F ala- ja ylärajat x l h ja x u h sekä y l h ja y u h ratkaistaan annetulla tarkkuustasolla, joka on joko mikään muuttuja X, Y, Z ja W ei ole integer tai X, Z ja W ovat vain integer tai X, Y I, Z ja W ovat integer. Syöte x h jokaiselle X ja y h jokaiselle Y (Jos x h null se kuuluu joukkoon X Jos y h null se kuuluu joukkoon Y ) Tee Modellerilla malli M, jossa kiinnitettyjä X ja Y Jokaiselle x h X \ X x u h = x l h = null Ratkaise x h tavoitteella {min x h } mallin M suhteen Jos x h = null LopetusIlmanRajoja x l h = [x h ] + Ratkaise x h tavoitteella {max x h } mallin M suhteen x u h = [x h ] - Jos x l h > x u h LopetusIlmanRajoja Seuraava x h Jokaiselle y h Y I \ Y y u h = y l h = null Ratkaise y h tavoitteella {min y h } mallin M suhteen Jos y h = null LopetusIlmanRajoja y l h = [y h ] + Ratkaise y h tavoitteella {max y h } mallin M suhteen y u h = [y h ] - Jos y l h > y u h LopetusIlmanRajoja Seuraava y h Jokaiselle y h Y F \ Y y u h = y l h = null Ratkaise y h tavoitteella {min y h } mallin M suhteen Jos y h = null LopetusIlmanRajoja y l h = y h Ratkaise y h tavoitteella {max y h } mallin M suhteen y u h = y h- Seuraava y h Jokaiselle x h X Tee Modellerilla malli M, jossa kiinnitettyjä X \ {x h } ja Y x u h = x l h = null Ratkaise x h tavoitteella {min x h } mallin M suhteen Jos x h = null LopetusIlmanRajoja x l h = [x h ] + Ratkaise x h tavoitteella {max x h } mallin M suhteen x u h = [x h ] - Jos x l h > x u h LopetusIlmanRajoja Seuraava x h
Jokaiselle y h Y Y I Tee Modellerilla malli M, jossa kiinnitettyjä X ja Y \ {y h } y u h = y l h = null Ratkaise y h tavoitteella {min y h } mallin M suhteen Jos y h = null LopetusIlmanRajoja y l h = [y h ] + Ratkaise y h tavoitteella {max y h } mallin M suhteen y u h = [y h ] - Jos y l h > y u h LopetusIlmanRajoja Seuraava y h Jokaiselle y h Y Y F Tee Modellerilla malli M, jossa kiinnitettyjä X ja Y \ {y h } y u h = y l h = null Ratkaise y h tavoitteella {min y h } mallin M suhteen Jos y h = null LopetusIlmanRajoja y l h = y h Ratkaise y h tavoitteella {max y h } mallin M suhteen y u h = y h- Seuraava y h Tee malli M, jossa kiinnitettyjä X ja Y, käytössä rajat x l h ja x u h muuttujille X \ X sekä y l h ja y u h muuttujille Y \ Y, kun X, Y I, Z ja W ovat integer. Ratkaise x * h kaikille joukossa X ja y * h kaikille joukossa Y tavoitteella {min 0} mallin M suhteen Jos ratkaisu löytyi Tuloste x * h, x l h ja x u h jokaiselle X sekä y * h, y l h ja y u h jokaiselle Y Tuloste x * h = null, x l h ja x u h jokaiselle X sekä y * h = null, y l h ja y u h jokaiselle Y LopetusIlmanRajoja: Tuloste x * h = x l h = x u h = null jokaiselle X sekä y * h = y l h = y u h = null jokaiselle Y Huom!!! [a] + pyöristää a:n yhtä suureen tai lähimpään suurempaan kokonaislukuun [a] - pyöristää a:n yhtä suureen tai lähimpään pienempään kokonaislukuun