Vodič za OptaPlanner

1. Uvod u OptaPlanner

U ovom uputstvu pogledamo rješivač zadovoljstva ograničenja Java nazvan OptaPlanner.

OptaPlanner rješava probleme planiranja pomoću paketa algoritama s minimalnim postavljanjem.

Iako razumijevanje algoritama može pružiti korisne detalje, s tim da okvir za nas obavlja težak posao.

2. Ovisnost Mavena

Prvo ćemo dodati ovisnost Mavena za OptaPlanner:

 org.optaplanner optaplanner-core 7.9.0.Finalni 

Pronašli smo najnoviju verziju OptaPlannera iz spremišta Maven Central.

3. Klasa problema / rješenja

Da bismo riješili problem, zasigurno nam je potreban specifičan kao primjer.

Raspored predavanja prikladan je primjer zbog poteškoća u uravnoteženju resursa kao što su sobe, vrijeme i nastavnici.

3.1. Raspored tečajeva

Raspored tečajeva sadrži kombinaciju naših varijabli problema i cjelina planiranja, stoga je to klasa rješenja. Kao rezultat, koristimo više napomena za njegovo konfiguriranje.

Pogledajmo pobliže svaku odvojeno:

@PlanningSolution javna klasa CourseSchedule {privatni popis roomList; privatni Popis periodList; privatni popis predavačka lista; privatni rezultat HardSoftScore;

The Rješenje za planiranje napomena govori OptaPlanneru da ova klasa sadrži podatke koji obuhvaćaju rješenje.

OptaPlanner očekuje sljedeće minimalne komponente: cjelina planiranja, činjenice problema i rezultat.

3.2. Predavanje

Predavanje, POJO, izgleda ovako:

@PlanningEntity javni razred Predavanje {public Integer roomNumber; javno Integer razdoblje; javni učitelj gudača; @PlanningVariable (valueRangeProviderRefs = {"availablePeriods"}) javni Integer getPeriod () {period povrata; } @PlanningVariable (valueRangeProviderRefs = {"availableRooms"}) javni cijeli broj getRoomNumber () {return roomNumber; }}

Koristimo Predavanje class kao cjelina za planiranje, pa dodajemo još jednu napomenu na getter-u Raspored tečajeva:

@PlanningEntityCollectionProperty javni popis getLectureList () {povratak predavanja; }

Naš entitet za planiranje sadrži ograničenja koja se postavljaju.

The PlanningVariable bilješka i valueRangeProviderRef napomene povezuju ograničenja s problemima.

Te će se vrijednosti ograničenja naknadno bodovati za sve jedinice planiranja.

3.3. Činjenice problema

The broj sobe i razdoblje varijable djeluju kao ograničenja slično jedna drugoj.

OptaPlanner ocjenjuje rješenja kao rezultat logike pomoću ovih varijabli. U oba dodajemo napomene getter metode:

@ValueRangeProvider (id = "availableRooms") @ProblemFactCollectionProperty javni popis getRoomList () {return roomList; } @ValueRangeProvider (id = "availablePeriods") @ProblemFactCollectionProperty javni popis getPeriodList () {return periodList; } 

Ovi su popisi sve moguće vrijednosti korištene u Predavanje polja.

OptaPlanner ih postavlja u sva rješenja u čitavom prostoru pretraživanja.

Konačno, zatim postavlja rezultat za svako rješenje, pa nam je potrebno polje za pohranu rezultata:

@PlanningScore javni HardSoftScore getScore () {povratni rezultat; }

Bez rezultata, OptaPlanner ne može pronaći optimalno rješenje, stoga je ranije naglasio važnost.

4. Bodovanje

Za razliku od onoga što smo do sada gledali, klasa bodovanja zahtijeva više prilagođenog koda.

To je zato što je kalkulator rezultata specifičan za problem i model domene.

4.1. Prilagođena Java

Za rješavanje ovog problema koristimo jednostavan izračun bodova (iako se to možda ne čini):

javna klasa ScoreCalculator implementira EasyScoreCalculator {@Napravite javni rezultat scoreScore (CourseSchedule courseSchedule) {int hardScore = 0; int softScore = 0; Postavi busyRooms = novi HashSet (); za (Predavanje predavanja: courseSchedule.getLectureList ()) {String roomInUse = predavanje.getPeriod () .toString () + ":" + predavanje.getRoomNumber (). toString (); if (busyRooms.contens (roomInUse)) {hardScore + = -1; } else {busyRooms.add (roomInUse); }} return HardSoftScore.valueOf (hardScore, softScore); }}

Ako pažljivije pogledamo gornji kod, važni dijelovi postaju jasniji. Rezultat izračunavamo u petlji jer Popis sadrži specifične nejedinstvene kombinacije soba i razdoblja.

The HashSet koristi se za spremanje jedinstvenog ključa (niza) kako bismo mogli kazniti duplikate predavanja u istoj sobi i terminu.

Kao rezultat, dobivamo jedinstveni set soba i razdoblja.

4.2. Drools

Drools datoteke daju nam brz način da izmijenimo pravila za primjenu na datoteke. Iako sintaksa ponekad može zbuniti, datoteka Drools može biti način upravljanja logikom izvan kompajliranih klasa.

Naše pravilo za sprečavanje null unosa izgleda ovako:

globalni HardSoftScoreHolder scoreHolder; pravilo "noNullRoomPeriod" kada je predavanje (broj sobe == null); Predavanje (točka == null); zatim scoreHolder.addHardConstraintMatch (kcontext, -1); kraj

5. Konfiguracija rješavača

Još jedna potrebna konfiguracijska datoteka, potrebna nam je XML datoteka za konfiguriranje rješavača.

5.1. XML konfiguracijska datoteka

    org.baeldung.optaplanner.ScoreCalculator 10 

Zbog naših bilješki u Raspored tečajeva klase, koristimo scanAnnotatedClasses element ovdje za skeniranje datoteka na stazi.

The scoreDirectorFactory sadržaj elementa postavi naš ScoreCalculator klasa koja sadrži našu logiku bodovanja.

Kada želimo koristiti Drools datoteku, zamjenjujemo sadržaj elementa sa:

courseScheduleScoreRules.drl

Naša konačna postavka je završni element. Umjesto da beskrajno traži optimizirano rješenje koje možda nikada neće postojati, ova će postavka zaustaviti pretraživanje nakon vremenskog ograničenja.

Deset sekundi više je nego dovoljno za većinu problema.

6. Ispitivanje

Konfigurirali smo klase rješenja, rješavanja i problema. Isprobajmo!

6.1. Postavljanje našeg testa

Prvo napravimo neke postavke:

SolverFactory solverFactory = SolverFactory .createFromXmlResource ("courseScheduleSolverConfiguration.xml"); solver = solverFactory.buildSolver (); unsolvedCourseSchedule = novi CourseSchedule ();

Drugo, podatke popunjavamo u zbirku entiteta planiranja i činjenice problema Popis predmeta.

6.2. Izvršenje i provjera testa

Napokon, testiramo pozivom riješiti.

CourseSchedule rješenCourseSchedule = solver.solve (unsolvedCourseSchedule); assertNotNull (rješenCourseSchedule.getScore ()); assertEquals (-4, riješenCourseSchedule.getScore (). getHardScore ());

Provjeravamo je li rješeniCurs Schedule ima ocjenu koja nam govori da imamo "optimalno" rješenje.

Za bonus stvaramo metodu ispisa koja će prikazati naše optimizirano rješenje:

public void printCourseSchedule () {predavanjeList.stream () .map (c -> "Predavanje u sobi" + c.getRoomNumber (). toString () + "tijekom razdoblja" + c.getPeriod (). toString ()) .forEach (k -> logger.info (k)); }

Ova metoda prikazuje:

Predavanje u sobi 1 tijekom razdoblja 1 Predavanje u sobi 2 tijekom razdoblja 1 Predavanje u sobi 1 tijekom razdoblja 2 Predavanje u sobi 2 tijekom razdoblja 2 Predavanje u sobi 1 tijekom razdoblja 3 Predavanje u sobi 2 tijekom razdoblja 3 Predavanje u sobi 1 tijekom razdoblja 1 Predavanje u sobi 1 tijekom razdoblja 1 Predavanje u sobi 1 tijekom razdoblja 1 Predavanje u sobi 1 tijekom razdoblja 1

Primijetite kako se posljednja tri unosa ponavljaju. To se događa jer ne postoji optimalno rješenje za naš problem. Odabrali smo tri razdoblja, dvije učionice i deset predavanja.

Zbog ovih fiksnih resursa postoji samo šest mogućih predavanja. Ovaj odgovor u najmanju ruku pokazuje korisniku da nema dovoljno soba ili termina za sadržavanje svih predavanja.

7. Dodatne značajke

Naš primjer za OptaPlanner koji smo stvorili bio je jednostavan, međutim, okvir je dodao značajke za raznovrsnije slučajeve upotrebe. Možda ćemo htjeti implementirati ili izmijeniti naš algoritam za optimizaciju, a zatim odrediti okvir za njegovu upotrebu.

Zahvaljujući nedavnim poboljšanjima u Java-inim mogućnostima višestrukog navoja, OptaPlanner također pruža programerima mogućnost korištenja višestrukih implementacija višestrukih navoja kao što su račvanje i spajanje, postupno rješavanje i multitenancy.

Dodatne informacije potražite u dokumentaciji.

8. Zaključak

Okvir OptaPlanner pruža programerima moćan alat za rješavanje problema zadovoljstva ograničenja poput rasporeda i raspodjele resursa.

OptaPlanner nudi minimalno korištenje JVM resursa, kao i integraciju s Jakarta EE. Autor nastavlja podržavati okvir, a Red Hat ga je dodao kao dio svog paketa za upravljanje poslovnim pravilima.

Kao i uvijek kod se može naći na Githubu.


$config[zx-auto] not found$config[zx-overlay] not found