מדריך ל- OptaPlanner

1. מבוא ל- OptaPlanner

במדריך זה אנו מסתכלים על פותר שביעות רצון מאילוצי Java המכונה OptaPlanner.

OptaPlanner פותר בעיות תכנון באמצעות חבילת אלגוריתמים עם הגדרה מינימלית.

אמנם הבנת האלגוריתמים עשויה לספק פרטים מועילים, אך המסגרת מבצעת את העבודה הקשה עבורנו.

2. תלות של Maven

ראשית, נוסיף תלות ב- Maven עבור OptaPlanner:

 org.optaplanner optaplanner-core 7.9.0.Final 

אנו מאתרים את הגרסה האחרונה של OptaPlanner ממאגר Maven Central.

3. מעמד הבעיה / פיתרון

כדי לפתור בעיה אנו בהחלט צריכים דוגמה ספציפית.

לוח הזמנים להרצאות הוא דוגמה מתאימה בשל הקושי באיזון משאבים כמו חדרים, זמן ומורים.

3.1. CourseSchedule

CourseSchedule מכיל שילוב של המשתנים הבעייתיים שלנו וגופי התכנון ולכן הוא סוג הפתרון. כתוצאה מכך אנו משתמשים בהערות מרובות כדי להגדיר אותה.

בואו נסתכל מקרוב על כל אחד בנפרד:

@PlanningSolution כיתה ציבורית CourseSchedule {רשימת חדרים רשימת פרטי; periodList פרטי רשימה; הרצאת רשימה פרטית רשימה; ציון HardSoftScore פרטי;

ה PlanningSolution ביאור אומר ל- OptaPlanner כי מחלקה זו מכילה את הנתונים להקיף פתרון.

OptaPlanner מצפה לרכיבים המינימליים הללו: הישות המתכננת, עובדות בעייתיות וציון.

3.2. הַרצָאָה

הַרצָאָה, POJO, נראה כמו:

@PlanningEntity בכיתה ציבורית הרצאה {public Integer roomNumber; תקופת השלמים הציבורית; מורה ציבורי למחרוזת; @PlanningVariable (valueRangeProviderRefs = {"availablePeriods"}) getteperiod () תקופה חזרה שלמה שלמה; } @PlanningVariable (valueRangeProviderRefs = {"availableRooms"}) שלם ציבורי getRoomNumber () {return roomNumber; }}

אנו משתמשים הַרצָאָה בכיתה כישות התכנון, לכן אנו מוסיפים הערה נוספת על ה getter CourseSchedule:

@PlanningEntityCollectionProperty רשימה ציבורית getLectureList () {return lectureList; }

ישות התכנון שלנו מכילה את האילוצים שנקבעים.

ה תכנון משתנה ביאור ו valueRangeProviderRef ביאורים מקשרים את האילוצים לעובדות הבעיות.

ערכי אילוץ אלה יוקלטו בהמשך בכל גופי התכנון.

3.3. עובדות בעייתיות

ה מספר חדר ו פרק זמן משתנים פועלים כמגבלות הדומות זו לזו.

OptaPlanner ציון הפתרונות כתוצאה מההיגיון באמצעות משתנים אלה. אנו מוסיפים הערות לשניהם גטר שיטות:

@ValueRangeProvider (id = "availableRooms") @ProblemFactCollectionProperty רשימה רשימת getRoomList () {return roomList; } @ValueRangeProvider (id = "availablePeriods") @ProblemFactCollectionProperty רשימה רשימת getPeriodList () {period periodList; } 

רשימות אלה הן כל הערכים האפשריים המשמשים ב- הַרצָאָה שדות.

OptaPlanner מאכלס אותם בכל הפתרונות ברחבי מרחב החיפוש.

לבסוף, היא קובעת ציון לכל אחד מהפתרונות, לכן אנו זקוקים לשדה לאחסון הציון:

@PlanningScore ציבורי HardSoftScore getScore () {ציון תמורה; }

ללא ציון, OptaPlanner לא יכול למצוא את הפיתרון האופטימלי ומכאן החשיבות המודגשת קודם לכן.

4. ניקוד

בניגוד למה שבחנו עד כה, מחלקת הניקוד דורשת יותר קוד מותאם אישית.

הסיבה לכך היא שמחשבון הציונים הוא ספציפי לבעיה ולמודל התחום.

4.1. Java מותאם אישית

אנו משתמשים בחישוב ציונים פשוט כדי לפתור בעיה זו (אם כי אולי זה לא נראה כמו זה):

מעמד ציבורי ScoreCalculator מיישם EasyScoreCalculator {@Override ציון ציבורי calcScoreScore (CourseSchedule courseSchedule) {int hardScore = 0; int softScore = 0; הגדר כבוש חדרים = חדש HashSet (); עבור (הרצאת הרצאה: courseSchedule.getLectureList ()) {String roomInUse = lecture.getPeriod () .toString () + ":" + lecture.getRoomNumber (). toString (); אם (occupRooms.contains (roomInUse)) {hardScore + = -1; } אחר {occupRooms.add (roomInUse); }} להחזיר את HardSoftScore.valueOf (hardScore, softScore); }}

אם נסתכל מקרוב על הקוד שלעיל, החלקים החשובים מתבהרים יותר. אנו מחשבים ציון בלולאה כי רשימה מכיל שילובים ספציפיים שאינם ייחודיים של חדרים ותקופות.

ה HashSet משמש לשמירת מפתח (מחרוזת) ייחודי, כך שנוכל להעניש הרצאות כפולות באותו חדר ותקופה.

כתוצאה מכך אנו מקבלים סטים ייחודיים של חדרים ותקופות.

4.2. רירונים

קבצי דרולים נותנים לנו דרך מהירה לשנות כללים להחלת קבצים. אמנם התחביר עלול לפעמים לבלבל אך קובץ ה- Drools יכול להיות דרך לניהול לוגיקה מחוץ לשיעורים המהוללים.

הכלל שלנו למנוע כניסות אפס נראה כך:

HardSoftScoreHolder score העולמי; כלל "noNullRoomPeriod" כאשר הרצאה (roomNumber == null); הרצאה (נקודה == null); ואז scoreHolder.addHardConstraintMatch (kcontext, -1); סוֹף

5. תצורת פותר

עוד קובץ תצורה הכרחי, אנו זקוקים לקובץ XML כדי להגדיר את הפותר.

5.1. קובץ תצורת XML

    org.baeldung.optaplanner.ScoreCalculator 10 

בשל ההערות שלנו ב CourseSchedule בכיתה, אנו משתמשים ב- scanAnnotatedClasses אלמנט כאן כדי לסרוק קבצים בשביל הכיתה.

ה scoreDirectorFactory תוכן האלמנטים מגדיר את שלנו ציון מחשבון בכיתה להכיל את הגיון הניקוד שלנו.

כשאנחנו רוצים להשתמש בקובץ דרולים, אנו מחליפים את תוכן האלמנט ב:

courseScheduleScoreRules.drl

ההגדרה הסופית שלנו היא מרכיב הסיום. במקום לחפש בלי סוף פיתרון מותאם שאולי לא יהיה קיים לעולם, הגדרה זו תפסיק את החיפוש לאחר הגבלת זמן.

עשר שניות זה די והותר עבור רוב הבעיות.

6. בדיקות

הגדרנו את שיעורי הפיתרון, הפותר והבעיות שלנו. בואו לבדוק את זה!

6.1. הגדרת המבחן שלנו

ראשית, אנו מבצעים הגדרה מסוימת:

SolverFactory solverFactory = SolverFactory .createFromXmlResource ("courseScheduleSolverConfiguration.xml"); solver = solverFactory.buildSolver (); unsolvedCourseSchedule = CourseSchedule חדש ();

שנית, אנו מאכלסים נתונים לאוסף הגופים המתכננים ולעובדה הבעייתית רשימה חפצים.

6.2. בדיקת ביצוע ואימות

לבסוף, אנו בודקים זאת על ידי התקשרות לִפְתוֹר.

CourseSchedule solvedCourseSchedule = solver.solve (unsolvedCourseSchedule); assertNotNull (solvedCourseSchedule.getScore ()); assertEquals (-4, solvedCourseSchedule.getScore (). getHardScore ());

אנו בודקים כי solvedCourseSchedule יש ציון שאומר לנו שיש לנו את הפיתרון "האופטימלי".

לקבלת בונוס, אנו יוצרים שיטת הדפסה שתציג את הפתרון המותאם שלנו:

בטל ציבורי printCourseSchedule () {lectureList.stream () .map (c -> "הרצאה בחדר" + c.getRoomNumber (). toString () + "במהלך תקופה" + c.getPeriod (). toString ()) .forEach (k -> logger.info (k)); }

שיטה זו מציגה:

הרצאה בחדר 1 בתקופה 1 הרצאה בחדר 2 בתקופה 1 הרצאה בחדר 1 בתקופה 2 הרצאה בחדר 2 בתקופה 2 הרצאה בחדר 1 בתקופה 3 הרצאה בחדר 2 בתקופה 3 הרצאה בחדר 1 במהלך תקופה 1 הרצאה בחדר 1 במהלך תקופה 1 הרצאה בחדר 1 במהלך תקופה 1 הרצאה בחדר 1 בתקופה 1

שימו לב כיצד שלושת הערכים האחרונים חוזרים על עצמם. זה קורה מכיוון שאין פיתרון אופטימלי לבעיה שלנו. בחרנו שלוש תקופות, שתי כיתות ועשר הרצאות.

ישנן רק שש הרצאות אפשריות בשל המשאבים הקבועים הללו. לכל הפחות תשובה זו מראה למשתמש שאין מספיק חדרים או תקופות להכיל את כל ההרצאות.

7. תכונות נוספות

הדוגמה שלנו ל- OptaPlanner שיצרנו הייתה פשוטה, אולם המסגרת הוסיפה תכונות למקרי שימוש מגוונים יותר. אולי נרצה ליישם או לשנות את האלגוריתם שלנו לאופטימיזציה ואז לציין את המסגרת לשימוש בו.

בשל שיפורים אחרונים ביכולות ריבוי ההשחלות של Java, OptaPlanner גם נותן למפתחים את היכולת להשתמש בכמה יישומים של ריבוי השחלות כגון מזלג והצטרפות, פתרון מצטבר ורב-מידות.

עיין בתיעוד למידע נוסף.

8. מסקנה

מסגרת OptaPlanner מספקת למפתחים כלי רב עוצמה לפתרון בעיות שביעות רצון מאילוצים כגון תזמון והקצאת משאבים.

OptaPlanner מציע שימוש מינימלי במשאבי JVM וכן שילוב עם ג'קרטה EE. המחבר ממשיך לתמוך במסגרת, ורד האט הוסיפה אותה כחלק מחבילת ניהול הכללים העסקיים שלה.

כמו תמיד ניתן למצוא את הקוד ב- Github.


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