 Now, hello everyone. Welcome to the next session of this session room. And the next talk will be about Plakop-Taplunar AI on Quarkus for Skoll-Tantel tabling. And it will be presented by Geoffrey Besmet. Also, I would like to encourage you if you have any questions, you can use Q&A tab here on Hoplion. And Geoffrey, we'll ask the question either during the presentation or in the end. So, stay cheers. Thanks. Thanks, Libomir. And if there are questions, just ask them in the chat. I'm happy. I won't be monitoring chat myself, but Libomir, if you see one, it would be great if you could help bring them on screen. Yes, sir. If I see that, I'll try to answer, of course. So, here we go. Optaplunar AI on Quarkus, right? So, this talk is going to talk about artificial intelligence, but it's not going to talk about machine learning. There's much more in AI than machine learning. It's going to talk about constraint solving, about solving planning and scheduling problems. And, of course, specifically, we'll do that with Optaplunar, right? So, about 15 years ago, 16 years this year, I started an open source project, nothing serious. And through the years, it became very serious. Now, it's all used across the globe. And I'm working on it with a team. So, let me take you through that if you want to implement a use case with that. And I'll be focusing specifically today on the school time table problem. So, what we're going to build with Optaplunar and with Quarkus is basically this application where you need to, when you push the solve button, the green big button over there, that we're going to assign these lessons, such as English, chemistry, math, biology, and so forth, to rooms and to time slots. Now, you might be thinking, okay, that doesn't seem so hard. And why is this artificial intelligence? Let me explain you the problem, how difficult it is. So, we have a number of lessons, like math, chemistry, French history, taught by teachers, for example, Alan Turing, Marie Curie, and so forth, and to a certain group of students, like the ninth grade, the 10th grade, right? And then we have a number of rooms, room A and B, and we have a number of time slots, such as 830 to 930, 930 to 1030. And we need to decide which of these lessons go into which room at which time. So, we can see here, we have four options to put them in. Will we put a math lesson in room A or in room B? And will we do that at 830 or at 930? Now, there's a number of constraints. First constraint is that some of these lessons have the same students. So, for example, math and chemistry, they both are taught to the ninth grade. So, that means that those two lessons cannot happen at the same time. They can't be in the same time slot. Chemistry and French are taught by Marie Curie. So, that means that they have the same teacher. So, those two cannot also not occur in the same time. And then French and history are also, again, taught to the same students, the 10th grade. So, what are we going to do? We're going to give this to OptoPlan, a constraint solver, and OptoPlan will give us a solution. And this is how a solution looks like. As you can see here, first of all, there's never two lessons in the same room, right? But also, math and chemistry have the same student group, but they're actually not at the same time. French history, same student group, not at the same time. Chemistry and French have the same teacher, Marie Curie, and Marie Curie can actually go to both of our, teach both of our lessons, because those two lessons are not at the same time. And that is the challenge, of course, with planning problems, with scheduling problems. There's a number of constraints that you need to take into account, and you want to solve. You might be thinking, how hard can it be? You might think, I can just write a couple of four loops, and that will probably just fix this. Why would I need anything beyond that? Well, how long would it take? How many possibilities are there to assign those four lessons into those four rooms? So, we have, we could, first of all, this is the math lesson, let's first assign that one. We could take four different spots for that. We could assign it in room A at 830, or in room B at 830, room A at 930, or room B at 930. So, four different options. Now, for all of these four options, let's say we could then assign the next lesson into any of these four slots again. So, for example, if math was assigned to room A at 830, we could assign the history lesson to the same room at the same time, to room B at 830, room A at 930, and so forth. Now, obviously, this is not that an interesting thing to investigate further, because we already have two lessons in the same room, but this is basically where this problem starts branching, the number of combinations starts growing. And then, of course, to assign the chemistry lesson, we can, for example, continue from the second case where history is assigned to room B and at 830, and then we could assign chemistry to the first slot, second slot, third slot, fourth slot, right? Or we could go into, in this case, where history is actually at a different time slot, but in the same room, and then start looking into, again, we could assign chemistry to those four places, to those four slots. And the same we can do with the French lesson. And so, we get a lot of combinations, because we could do the same for any of these branches on here. So, each of these little dots here at the bottom, that's a full combination, so we're assigning those four lessons into four slots. So, there's a problem with this. If you look at the solutions we got off here, here's the only one where there's no two lessons in the same room, but we still have this problem, because if you remember from the previous slides, chemistry and French actually are both taught by Marie Carie, they have the same teacher. And these two lessons history and French have the same students. Actually, the feasible solution, the one where everybody could go to their lesson, and no two lessons were in the same room at the same time, is somewhere in these branches here, in one of these branches, right? So, how, okay, but yeah, why not brute forces, forces this, why not just go across all of these possible, okay, possible combinations, right? Well, if you have only four lessons assigned to, one lesson to sign to force, four slots, that's four states, right? Two lessons assigned to four slots, four slots, that's 16 states. For three lessons that become 64 states, for four lessons that becomes 256 states. And if you're assigning something like 400 lessons, which is far more realistic for a small school, right? Because any, any group of students will have 40 lessons a week. So that means there's only 10 groups of less, 10 groups of students there, then you already have the number of combinations is already 400 to the power 400, right? And that's about the same as 1000, as 10 to the power, to the power 1040. So you get a lot of, if you want to do this brute force, you have to go through a lot of states. Now, you could argue that maybe you don't want to investigate all of these branches, but that really doesn't matter much. That will just, you will only throw away 99% of your solution states. And that's, that's not going to make a difference because 10 to the power 40, if you throw away 99% of your solution states, that's still 10 to the power 1038 states, right? So it's, it only reduces the, that 1040 power to the power 1038. That's not really making a big of a difference, right? But anyway, and how long would it take to solve this, right? So, so how big is a search base? It's n to the power n, it's 400 lessons, that's 10 to the power 1000 and some more. And just to give you an idea of how big this search base is, the number of atoms in the observable universe, right? Anything you know, anything you can see, every breath of air, every grain of salt, the sand, every atom in there, there's millions of millions of atoms in there and all of those summed up together, that's still, that's about 10 to the power 80, right? That's what that's the, that's your, that's the general guess on that. So that number is far, far less than signing 400 lessons to 400 slots. So clearly brute force won't work. Even with the fastest computers or all of the computing power on this planet, it would still take you millions of millions of millions of millions of millions of years. So we need a better way, right? And there's many. So, and that's of course, where a constraint solver like optoplanar comes into play, where we're using other algorithms to actually find that solution. Now, are there other planning problems? So for example, it's not just lesson scheduling. A good example is employee rostering. So in the employee rostering case, we need to assign shifts to employees. So for example, we have a morning shift from 6 till 8am till 2pm, right? And we need to figure out which nurse will do that shift. Will it be, you know, nurse one, nurse two, or maybe the engineer or maybe the designer, right? And that's, that's the choices we need to make. Now, there's a number of constraints in here. It's that every employee can only have one shift per day. Certain shifts require certain skills. For example, in a hospital, there might be a lot of regular nurses, but there could also be a nurse who has special skills like to work in the maternity ward. So any shifts that are in the maternity ward would need specifically a nurse who has that particular skill, right? And so forth. And there's also contracts. So for example, the designer in this case, he works five days in a row. He should not have any weekend work. And these are hard constraints. There's also soft constraints. So soft constraints are less important than hard constraints. If you break them, your schedule is still feasible, but you want to avoid them as much as possible. In this particular case, it's, for example, forward rotation. When you want to make sure there's enough time between two shifts for the nurses to go home, sleep and come back, right? Or if you want to avoid the offer, if you want to give people, when they ask for particular day off, you want to actually give that to them. And that's the off request. So for example, if you would be signing this nurse on this Friday to a particular shift, we would violate that they offer request constraints. And we would like to avoid that, right? We can't always avoid that. For example, on Christmas, nobody wants to work on Christmas, you will have to break some soft constraints. But in general, you can try to avoid it as much as possible. Another typical case is vehicle routing. So in the vehicle routing case, we need to pick up a number of items across the country, right? And we need to decide which vehicle does that and also in which order do they do that. And we want to minimize the travel time. Now, that's not just for picking up or delivering items. It's also, for example, for technicians that come to your home and install cable, internet and things like that, or any other service you need to do across the entire country, such as repair of electricity lines, et cetera. Now, what are the constraints in this? Well, if you're actually delivering items, you have a capacity per vehicle, the amount of volume, the amount of tonnage they can actually carry, right? And so you want to make sure that if you sum up all of the capacity you need for all of those stops, it is less than the entire capacity of the vehicle. They might also deal with time windows where you say, okay, I need to be at that customer between 8 and 10 a.m. because we promised to be there between that time window. They're staying specifically at home for us for that. And of course, in general, you want to reduce the entire travel time. And that's something we can do a lot by optimizing it. So just to give you an idea, how does this work in the real work when you do a vehicle routing case with, for example, what we did with Optoptan, right? Well, they expected by automating this to creation of these schedules that they would reduce their driving time by 1%. We had a case like that, right? The result was 25% less driving time. And this was about a lot of vehicles, tens of thousands of vehicles. So the result was that they actually reduced their CO2 emissions by more than 10 million kilograms a year because they were simply driving less to reach all of those locations with their fleet of vehicles. So it's important to understand that what people are using today to solve these kinds of problems, either humans who just do the schedule, smart humans who do these schedules as best as they can, or relatively greedy algorithms, the homegrown implementations of constraint solving, let's put it like that. There's typically a lot of room to improve those. And even today, we're still improving results. And then there's still state of the art research that is improving results further. And what's the probably the most interesting part for some audiences on this is, well, I think the CO2 emissions reduction per year is the most interesting part. But they also, by reducing their driving time by that much, they also reduced their costs as a company by literally in nine figures. So vehicle routing is an interesting case. Employee rostering will not deliver that kind of numbers, of course, but it will make the employees happier and increase retention. Now, there's many more planning cases like maintenance scheduling, grips, grids, equipments, airplanes, and that kind of things. Agenda scheduling, court hearings, TV ads, job shop scheduling for when you're building things in a factory and task assignments in general. Now, to the world is full of planning problems. And I'm proposing you to use opto planner and open source AI constraint solver to solve those. And I'm going to show you how we do that now today in this meeting. So how do we build this application for school time table? Right? How do we get to this result? Well, if you remember what we're going to do is we're going to use Quarkus for that. So what is Quarkus? Quarkus is a Java application platform. And its tagline is that it's supersonic supatomic Java, right? And the interesting thing is it is extremely fast. And I'm going to show you that in a minute. So what are we going to build? We're going to build an application where starting with Quarkus, we're going to use REST easy to expose a REST service. You don't actually know that it's REST easy in below. It's just we're going to expose a REST service. And then we're going to have a browser that goes to that service. And then we are going to store our data in a relational database. Now, this part of the application I've already built, I'll take you through the code in a second. And then there is no AI in what I've built so far yet. And I will live code to actually add those pieces in a few minutes. So first of all, let's say you want to build this application from scratch. What would you do? But you would go to code.quarkus.io. So for example, this is code.quarkus.io. You would say, okay, I want to have, let's say, hibernate, right? And then you can say, okay, I want, I know this is with REST services, I want hibernate, editor of these, right? And then I want to, for example, use opt-up planner, right? And you add opt-up planner. And then when you're ready, you press the blue button and you get a zip with including your POM file if you're using Maven or if your driver is Gradle, I believe that's option, that's possible too, right? Now, I've done that already. And I want to show you what I have here. So I have this set up already, and I've added the code already for the non AI parts. So as you can see here, we have a POM file. It has an artifact ID. It imports the cork as a bomb. It also already imports opt-up planner, but it doesn't use any of that code yet. And you were using hibernate, panache to go to the database, and we're using REST easy to expose the REST interfaces. And a few other things like that makes testing easier and expose a few more things. I'll explain those as we go through those. And we can see we have a couple of domain objects here, like the lesson, the room, the time, the time table, right? So here we go. Back to the presentation for a second. So let's talk about the domain, right? So we need to implement a school time tabling app. So what do we need? Well, first, so this is what we need to need to implement these lessons, these rooms, we need to be able to capture that kind of data. So what are we going to do is we're going to create a few Java classes. The first class we have already is a time shift class, right? Which has a day of week, which is of the type day of week. So Monday, Tuesday, Wednesday, and so forth. It has a start time, like 830, 930, and an end time, 930, or 1030. It has a room, like, for example, room A, room B, room C, and so forth. And then we have lessons, which have a subject like math or chemistry or something like that. A teacher, like, which is like Marie Curie or so forth. Now, in a real full blown application, you would probably make a teacher its own class, which a couple of properties, you know, they like to work on Monday mornings or not, right? But in this case, I've kept it simple and it's just a string. And of course, the student group, which is a group of students, and again, in a real application, this might be more complex where you have multiple students, group that might actually share students and so forth. But, and it's all possible, but in this case, I've kept it simple, a simple string where it says like 9th grade or 10th grade or something like that. Now, these lessons get assigned to a time slot, right? And get assigned to a room. And this is, of course, the part that we will want Optoplanar to do for us. So we will input the number of time slots, the number of rooms, right? Where our school has available, the number of lessons that we want to teach, and then we'll let Optoplanar figure out which lesson goes to which time slot and which room. So let's take a look at that in code, right? So if we go here to the time slot class, it's a pretty simple class. It's a time slot. It has a day of week, right, which is this is coming from Java dot time for those who are not familiar with this yet. And then the start time in end time, which is also coming from Java dot time, the local time, sort of 830 and so forth. These classes have an entity annotation. This is from JPA from Hibernate. It basically says that I want to store this in the database. They also have a database ID where we basically say this is the ID and we want it generated by the database. We don't want to mess with it ourselves. And anything beyond this, all of these classes have some constructors and some getters and setters and the two string method to make them visible on screen. But most of those, these are needed because we want to push them into JSON. And so through JSON, we push them into JSON to the front and to the clients, right? And that's why we have those things there, most of those. So we have the room also. The room class, we put it in a database. It has a database ID. And the only other field it has is a name field, right? And so that's, for example, room A or room B or room C. And we have our lesson class as explained earlier. Our lesson class, again, we put it in a database, has a database ID, subject, like math, French, and so forth. The teacher, like Marie Curie, student group, like ninth grade. And then we have basically a reference to a time slot and to a room. And both of these are many to one relationships. So JPA needs to know that, that how the form keys in the database are mapped and so forth. It all does it automatically. But we need to tell them basically one lesson can be in, is in a time slot. But one time slot can have actually multiple lessons. And it will just not in the same room. And the same story for the room side. Okay, we have one more class. That's the timetable class. So what's the timetable class? It's basically a list of all of our time slots, a list of all of our rooms, and a list of all of our lessons. It's basically our entire data set. Why do we need this? Because we need to ship it to the client. And so we just, when, when we load the class, let me just show you that when we load the class here, what we do is, when we send this to the client, there is this get methods here. And when the user asks for the, when we go to a certain URL, we go for the timetable URL, we get it. That's when this method is called, which actually says I'm going to create a timetable from all of the time slots in the database, all of the rooms in the database and all of the lessons in the database. And I'll go through that in a second. Right. So let's see how this ends up. Let's see if this actually works. So what I'm going to do is I am going to start Maven, Quarkus Dev, of course, is available in Gradle 2. And this basically starts my application in development mode. That means when I make a change, I can immediately see the results of those changes. Right. It's complaining here with a small warning that I don't have any optoplanar code in there, but I do have a dependency on optoplanar. And of course, we'll fix that in a minute. So if we go back here and we go to our local host, now actually this thing is rolling. You can see it's running, right? And you can see that we have a number of rooms, room A, room B, room C. We have a number of time slots, 839, 30, time 30, and so forth. You have a number of unassigned lessons, all of these lessons like biology, chemistry, and so forth. They don't, they're not assigned to a lesson yet. And now we want to see the magic of optoplanar that assigns us to this lesson. So let's click the solve button. But of course, we get a big fat error. Why? Because that code is not implemented yet. And that's exactly what we will go, which we'll do right now. Right. So if you go to the code here, you can see there's an error here. And that's pretty much coming from here. Right. When we press the solve, when we call the solve button, that green button calls this this method, it actually throws in unsupported operation exception to do so that's something we will need to implement right now. You can see that here too. Okay. So let's start making some changes. But before we do, I need to explain about the data. There's some data in here, as you've probably seen, room A, room B, room C. Where does that come from? What I've done is, first of all, I've created repositories. So what is a repository? It's a class that says, I want to put that this lessons, of course, it's already outdated within entity annotation, I want to put them in the database. And this is a class that allows us to actually say, give me a list of all of the lessons or find me particular lesson, or I created a lesson, I want to store in database. So if actually, this extends the Panache repository, that does that for us. So basically, if we can call any of those methods on those. So what I do have created is for the lesson repository, for the room repository, and of course, for the time slots. So in all three cases, I've said I want to be able to store and read these entries from the database. And then I've created a demo generator. And what the demo generator does is, when the application starts up, so it listens to a startup event, it's going to create some test data. And at the end of that, it's going to persist that test data into, for example, this case into the time slots repository. So this demo generator listens to when the Quarkus container starts up. It says, okay, in that case, it will create, for example, a time slot here for Monday at 8.30 for and another one at Monday for 9.30 and so forth. And we'll store those in the database through this method. Same thing, it would create a number of rooms, ABCD, ABC here, and put those in the database. Now, those repositories will automatically be injected, as you can see. We'll inject them here so we can use them. Now, one thing I want to show you with Quarkus, why Quarkus is very developing in Quarkus is so much fun, why they call it supersonic atomic Java and so forth, is if you, for example, change this into the DEVCONF room, and I now switch to over here and I refresh on the top left, what you will see is that it immediately changes to DEVCONF, room DEVCONF. So let's see that again. Let's change that to something else. Let's say DEVCONF2, switch over there, click the refresh button, and it's immediately updated here. So how does that work? First of all, how fast is that? It's actually, you can actually look in the console how long that took. And that took, in this case, over one second, usually it's half a second, but clearly sharing my screen and all of the other stuff that's running for around that is taking quite some CPU. This is a computer from 2015, so it's definitely not a recent one. Now, okay, what happened there? Well, it restarted the entire application, the entire application. So let's look at that in case. So at Maven, Quarkus, DEV, what does that Quarkus, DEV restart do? Well, when it normally starts, what you do is when you run Maven, Quarkus, DEV, it compiles all of the sources. It goes to the relational database, which is in memory H2 database that it also starts up for us. It drops and creates the entire schema, which means that if we add a field to the lesson class, it automatically, the database schema would be adjusted accordingly. It inserts the test data. That's that demo test generator class that we have just gone to. That's of course, custom code for our domain here that says I'm going to run A, B, C, and so forth. So it actually does that for us. And now, if a little bit later, we go to the application and we click on the get method, or we just browse to that local host 8080 URL. What we get is it does some SQL queries to this database to get all of the time slots, all of the rooms and all of the lessons as we've seen, and then sends that back as a timetable object. That takes a few milliseconds. Where it really gets interesting is when we go back into our sources, and in those sources, we change room C into room devconf. So we change some source files in our IDE is what happens when we then ask for another, when we do another get of that index. What actually happens is when we do a get of that index file, it actually triggers a restart because Quarka sees, okay, you want to call a REST method on me, but I actually know that some of your files, I'm also monitoring your source files in your IDE, some of your Java files, they're changed. So what that point, what it does, it compiles those change sources, those Java files. It restarts the whole server, drop creates to get the schema of the relational database up to date. It inserts that test data again, including, you know, my room devconf this time instead of room C. And then of course, it actually does the whole thing that it needed to do, namely do servers the request and actually does the SQL queries for that request. So just calls the REST code behind that, sends us back as JSON. And the whole thing, well, should be less than a second, but on this computer with this streaming audio on, it was actually 1.7 seconds. Still something I find acceptable during development. So that means I make a change and in less than two seconds in this case, I can see the results of that change. So let's move this back to devcon, show this one more time in action. So we move this back to room C, so move this room back to room C, and I go here and I refresh here. I see there's a question, so let me ask you, was that what has been the biggest planning challenge that you or others solved with optoptar so far? Oh, vehicle routing cases with tens of thousands of vehicles, this is a lot of fun. Employee rostering cases for where there's a big diversity of constraints that they want and not just a few dozens, but dozens and dozens of constraints, that was fun. Let me think about that for until the end of the presentation to maybe there's probably more. Okay, so here we go. Let's continue. So we have a running now. What else do we have here? So I went through all of these classes. I think it's time to add a little bit of AI into this story. So again, that solve button still doesn't work and we still want that to work. So what are we going to do? We're going to add AI planning optimization with optoptar. And so we're basically adding optoptar to the mix. And in our timetable class, optoptar needs to know what it can change, right? This lesson class has a subject, the teacher has a time slot. Can optoptar decide to give this lesson a different teacher? No, it cannot. Can it decide to give it a different student group or different subject? Now everybody who wanted to math gets French instead, no, it can't. So instead, we need to tell optoptar what it can change. And those are actually those time slots and those room things. So what we do is we add, just like you can add JPA annotations, you can also add optoptar annotations on fields. What they specifically do is we say, okay, that time slot, that's a planning variable. That's something that changes during planning, right? The room same principle. Any class that has one or more planning variables is called the planning entity and needs a planning entity annotation. So that's basically how we tell optoptar, okay, start looking into this class or something there that you're going to need to change during planning. And so basically before planning, the time slot and room fields are null, right? And after, so before solving and after solving, they are non-null. So optoptar will assign them for us. Okay, so back to the coding side, let's start implementing that. So that was that, again, that undo and support operation exception here at the bottom. So in a few, we'll be fixing that right now. So here we go, we go to the lesson, we say, okay, this is something that actually changes during planning. So what we're going to do is we're going to say this, some of the fields in this class change during planning, we're going to give that a planning entity annotation. And what is going to change is the time slot. So we're going to say, okay, this is the, this is a planning variable. This is something that changes during planning. So for those 20 lessons that we're assigning to tens of time slots and then to three rooms, for each of those instances, it will pick a time slot and it will also pick a room. So we're going to make that also a planning variable, the room, right? Now opto planner needs to know where can I find the time slots to pick from. And so what you need to also say is I'm going to give it a value range ref, value range means a range of values to pick from. And for now, I'm just going to call this time slot range. And where we actually have a list of those time slots that we're going to use the same ID. And that's how they're going to be coupled together. Similarly, I need to opto planner cannot just invent rooms for me. Can I say, I'll make room D and E. And then, you know, I'll start assigning things to that. No, it needs to pick from room A, B or C, that are the options. So somehow we need to tell them, okay, this is room A, B and C that you can pick from. So again, we have this, we make an ID room range and somewhere else we're going to take this, we're going to define it. So where is a list of times and a list of rooms? But if you remember, we had the times timetable object, right? And that timetable object is actually not just ideal to send to the client with a list of years all of our data, but also to send to opto planner, we can just say, okay, here opto planner, here's the timetable, please solve that for me. So what we need to do is we need to say, okay, this is a value range, value range. This, this is the, sorry, first of all, this is a planning solution, right? This means that this is something that's, this is something that we give to opto planner, it solves it and then it gives it back to us. So when it gives it back to us, it is a solution. That's why the planning solution annotation is on that. And then this time slot list is actually will give us the list of time slots for opto planner to choose from. So we make that a value range provider and we say, okay, we put it, we give it the same ID as we did earlier. This is our time slot range. Similarly, for our rooms, we're going to say, this is our range of rooms. So now opto planner knows when it says, okay, when I need to assign math, right, where, which, which time slots in which rooms can I pick from? It also says, okay, I need to look in the time slot range. And basically is between these lists of time slots for the time slots and between these lists of rooms for the room. We need to also tell opto planner, you know, where are the lessons you want to you to optimize. It cannot just plug those lessons out of the error. It needs to get those 20 lessons some I need to get access to those those somehow. So what we do here is we say, okay, this is a planning entity collection property. Basically means a list is a collection, right? So it basically means that this is the list that we want you to assign. There's one more thing we need to do here is when opto planner solves this and then gives this this planning solution instance, an instance of this planning solution back to us, we this will get a score opto planner will give a score to it. That's how it figures out if this is a good or bad solution. So we're going to add a score here, specifically a hard soft score, right? Because we have hard and soft constraints. And let's import that. Okay, let's import that. And that come as you can see there. And we're going to also tell opto planner, right? This is where our score field is. So we need to give it a planning score annotation. For JXB and so forth, I will also add a getter for that score. Here we go. So our times table class is is ready. This is we can now give this to opto planner. And when opto planner starts solving it, there's a number of hard and soft constraints as we talked about. But where is that list of hard and soft constraints? Well, we don't have one yet. So what I'm going to do is I'm going to create a new package called solver. I'm going to put there one class in there. Yeah, maybe I make a little bit too many packages if I'm only creating one class in there. And so this is the time table constraint provider. And that will give us the list of constraints, because this one will implement the constraint provider interface, provider interface. And if I write that correctly, I get code health. And this has actually just one method, which is define constraints. So this is where we say, okay, these are the constraints we want to apply the hard and soft constraints to apply. For example, we don't want two lessons in the same room at the same time. So what are we going to do here? For now, we're just going to return an empty array. And later we'll add some constraints. But for now, we don't need any constraints. Everything is fine, right? No interface expected here. This is of course implements, not extents. Here we go. Okay. One more thing that we need, we need to actually use this, right? So how can we, how can when we call this solve methods, we throw this unsupported operation exception, we actually need to do something here. So to be able to do something there, what we do is we inject a solver manager. This is something that comes from opto planner. And that allows us to solve problems. So for example, this will, we want to have a solver manager for a timetable, right? And so I'm going to create a solver manager, I'm going to inject it. It also besides that it solves time tables, it also needs to know if we give it a job, it will, it wants to do a job ID, and we can choose whether that's a long string or UUID or anything else. So we need to give that type to so because it's typed on it. Okay. So I'm injecting the solver manager. So now I can, I can actually solve a data set. So now I can actually say, okay, when, when we click that green button in the UI, what do we do? We still the solver manager, okay, solver manager, please solve and listen, listen means that it will also send the events of new improved solutions back to the UI. And then we get to say, okay, it says, okay, you want to, you want to do me a job, you need to tell me what is the problem ID. I'm just going to hard code it to one, one right now. And then we need to give him two functions. The first function is to load the problem. The second function is to save the problem. So what I'm going to do is I'm going to first given, given a problem ID, I'm going to say, load the timetable. If you remember, we had that lone timetable class here, methods here, which go basically goes to the repository lists all of the lessons, sorts them by day of week in the query. And the same thing we do for the rooms and for the lessons. And that's how we create the timetable class. So we're actually going to load that incident, you know, a timetable class from the database by loading all of the time slots, all of the rooms and all of the lessons. And then every time we find a new better solution, what we're going to do is given a solution, which is actually timetable. What we're going to do is we're going to save it. And save is another method down here. It's a pretty simple method. What it does is it goes through all of the lessons of that timetable and stores the time slot and the room into the database. So okay, so let's try that out. Let's hope this works. It's a live coding session. I could go see how well that works. First of all, we're going to click the refresh button. I clearly did something wrong. So multiple classes, timetable constraint provider and my constraint provider found that implement interface. Okay, but I don't have it here. And I know what I did. I started Maven Corcus Dev without doing a clean. And in this repository, I was playing sometimes. So I did have my constraint timetable class there. So that will go away now. Normally, I don't have to restart Maven Corcus Dev. But this is clearly an exception when I was running just plain Maven versus Corcus. And so normally, when you develop Corcus, you don't have to do this. Let's take a look what's going on. And Corcus Dev is ready. So here we go. No errors. So that's good. Yeah, let me just show you that if I make an error in here, for example, let's say put this here, right, and we do refresh, you will see that that actually crashes, right? Corcus, that's not a statement. So if we go back here, fix that again, Corcus Dev, you can immediately see the results of that. Okay, let's see if it can solve our problem. We click the solve button, it's going to assign these lessons to those slots. But there's a problem. There are no constraints. It assigns everything to room A at 830. And clearly, this is not a good schedule for lessons, because everybody is now in the same room at the same time. So what we need to do is we need to go back to our constraint provider and actually add a constraint for that. Now, you could do that in a few different ways. You could, for example, say, okay, I'm going to create what we call an easy score calculator. And where you go through with a loop through all of the lessons, lesson A, lesson B, and C, are they in the same time slot? Are they in the same room? And if that's the case, you actually have two rooms, two lessons in the same time slots at the same time, right? This works, you can implement this. There's nothing wrong with that, except for the fact that it's not that scalable. And you really want to, you know, there's a lot of potential solutions to look at. So the faster this code is, the more scalable this code is, the better. So it's not incremental, right? What does it mean? When the room of the math lesson changes, it checks again if French and chemistry use the same room. So every time we make a small change where, for example, we change the math lesson, it actually checks also if, you know, French and chemistry are still in the same room. But that hasn't changed. Either they were or they weren't. But changing math won't actually affect that. And this is a big scalability difference. So instead of that, what we're going to do is we're going to use constraints, constraint streams here. And this is actually a constraint provider, which will do that in a much, in incremental way for us. So what are we going to do is we're going to say, okay, I want a room conflict constraint. So let's make a method for that. The constraint factory is the thing that will create constraints for us. So we're going to pass that along. Right. So in this one, in this method, we're going to actually create that that that constraint that says don't put two lessons in the same room at the same time. We're going to say, okay, constraint factory, please select me a lesson. So so here we go. Lesson class. Okay. And then, please join that with another lesson. Top class. So now we have selected two lessons. It's very much like SQL. So select me one lesson and then for join that with any other lesson, right? Okay. And in the end, we'll actually do a penalize on that to say, okay, we don't want this to happen every time we have two lessons in the same room at the same time. It's bad. But we of course need to specify that they're in the same room at the same time. So what are we else we're going to do here? We're going to say, okay, I want to make sure that these two lessons are using the same room. So we say, we if they have these two lessons that I just selected have an equal room, right, then we can continue here. And if they also have an equal time slot ever, they're actually at the same time. Alright, good time slot. Then we definitely want to penalize that that's bad, right? So this is the then we have an actual room conflict. And that's an act and that's very bad because it's a hard constraint broken. So what are we going to do is we're going to say that breaks one heart constraint, right? Now, you can see this is a method reference. So that means for people who are not familiar with that, that's basically a lambda. And so that means you can call call any code in here on your lesson to figure out, to merely make this dynamic. And that's quite useful. Yes, Lupamir. I'm sorry for interrupting you. You have just five minutes left. Yes. Thank you. So let's see how this works out. Do we get a better schedule? So let's go back to our UI. And let's refresh refresh. So Quarkis is now rebooting the entire application from scratch. You can see that the test is assigned again. And we click the solve button, we get our first schedule out. This looks better, right? Because every lesson is in we never have two lessons in the same room at the same time. There's still a few problems with this because this would be easy to solve, right? Any human can figure this out and find the schedule. The problem is if only we look for teacher, right? Now we have here, you can see Marie Curie, two lessons at the same time, right? And that's impossible because one person cannot be in two places at the same time. And when we look at the student group, we see similar issues, right? Here you can see it. Two lessons at the same time for student group 10A. And that's what makes it hard. Also for us humans, when you want to create a schedule like this, it's actually quite hard to, because when you make changes here, you then affect the rooms again. And it's a lot of wires that, it may, it's difficult to change, right? So what are we going to do is we're going to actually create two more constraints in here. We're going to create a teacher conflict constraint that we'll check if two lessons for the same teacher are happening at the same time. And the same idea for student group, if we have two, if you have a student group that has two lessons at the same time, it's bad too. For the sake of time, I will just copy, paste this room conflict constraint, because it's very similar. So the first one is a teacher conflict. And the second one is this student group conflict, right? This one is the, so when we have a lesson for a teacher conflict, right? And we have another lessons on those two lessons, don't, we don't care if they have the same room or not, we care if they have the same teacher. So if they have the same teacher, and they're happening at the same time. So if we have two lessons, same teacher, same time, then of course, we have a teacher conflict, right? For a student group, when we have two lessons, and they are for the same student group, so it gets, the student group is the same. And again, they're happening at the same time. Then of course, we have a student group conflict. So here we go. Let's try that out. We go back here, we class requires a refresh button. Let's see how long it took for corpus to actually refresh this. Oh, it's getting worse. I don't know what's going on with my computer. Usually when I do this locally, it's really it's half a second, but still three seconds or 2.5 seconds. That's acceptable to me. When it gets to three seconds, I'm going to start complaining though. So here we go. Let's click the solve button. Let's see what happens. We get a schedule here. You can see every room has its own, has their own. So never two lessons in the same room at the same time. When you look at it per teacher, we can see there's no never a teacher that has two lessons at the same time. When you look at student group, we can see the same thing. This is a feasible schedule. So feasible means no hard constraints broken. And you can actually put this in production. This is the perfect schedule far from it. If we actually look at it from a student, a former teacher group perspective, for example, Marie Currier. Currier in this case, she's actually has pauses between the lessons, right? She needs to come two days. The teachers really prefer a compact schedule, right? And you can do that. What you can do is you can just add another constraint that says when there are gaps between two lessons, penalize that. And that's exactly what we have implemented in the Quick Start. So we can take a look at in the Quick Start if you want to know how to implement that. And that is a soft constraint because you will always have some violations of that, but you still want to minimize the violations of that. That's the difference between a hard and a soft constraint. Hard constraints. If you don't fulfill them, your schedule is not feasible. Your soft constraints, you are willing to break those, but as least as possible. Now, if you want to get started with all this, if you say, okay, this looks cool. I think I have an interesting use case to solve with Opto Planner. What you want to do is you want to go to, you want to check out the Opto Planner Quick Start repository. So if you go to OptoPlanner.org, there's a link on the front page directly to this repository. And basically, you just clone it, the Quick Start repository. You go to, for example, the school time tabling use case. We have many more maintenance scheduling, vehicle routing, and so forth. And in any of those, you just do Maven cork as dev, and you go to local host, and you'll see the results there. And you can start changing the code, add some constraints, change some of the data for your needs as you see fit. Now, if there's questions, I'll happily answer those. And if you want more information, these are the websites to look at. Okay, thank you very much for your presentation, Joffrey. We have only one question in Q&A, but you already answered it. I'm not sure whether you want to get back to it. Yeah, it's a good question. So what has been the biggest challenge you or others solved at Opto Planner so far? I had a few, there was on Kaggle, that's a yearly Santa competition. And there was an interesting one once year where we had to figure out how to do volume packing of the sleigh. So basically, there's supposed to be Santa's gifts, and you need to figure out how to order them, and in which ordering to put them in the sleigh, so you minimize the amount of lost capacity into a truck. So in the real world, trucks have this problem too. That was really out of our normal comfort zone for what kind of problems we solve with Opto Planner. That was a toy example, of course. It was just a fun Kaggle competition. In the real world, fairness is always fun. First, you need to define what a fairness constraint is when there's multiple versions of that. We have those, we support those, of course. I know Opto Planner has been used across the globe. For example, in Belgium, the pharmacies are actually, their own duty is scheduled with Opto Planner. All cases are interesting. The biggest is definitely the vehicle routing in the U.S., where we're tens of thousands of vehicles, hundreds of thousands of stops per day are actually scheduled every day with Opto Planner. So that's arguably the biggest one. Or maybe there's a case where we do in a country all megastat to hearing assignments. It depends on how you measure what is big or small. Okay, great. Thank you very much for your answer. We don't have any time. So if you would like to continue, feel free to go to Discord or WorkInvention. It's a virtual platform where you can interact with each other. So feel free to go there and you can talk to them about it. I'll go to Discord right now. Thanks. Thank you very much again. Thank you. Bye.