 Welcome. I'm Jeffrey de Smit and I'm going to show you how to use artificial intelligence in Kotlin. More particularly, I'm going to show you how to use planning optimization AI, which is one of the most profitable areas of artificial intelligence, I would argue. So let's take a look at how we're going to do that. Let's get started. And so I'm going to build you an application from scratch and more particularly I'm going to build you this application from scratch, where as we press the solve button over here, it's going to assign these lessons, such as English, chemistry and math, to time slots and to rooms A, B and C and so forth. And we're going to make sure that no student has two lessons at the same time, no teacher has two lessons at the same time and so forth. So we're going to build some constraints into that and we're going to use an AI algorithm to scale that for us to do the hard work for us. So you might wonder why is this a difficult problem? Well, imagine we have four lessons here, math, chemistry, French and history. We need to assign these to these four slots, room A, room B and those two time slots. And we need to make sure that math and chemistry, which are being taught to the same student group in the ninth grade, are not happening at the same time, of course, because those students cannot be in two places at the same time. Same thing applies for French and history, two different lessons, but again the same student group. And also chemistry and French are both taught by Marie Curie, so they have the same teacher, different student group, but the same teacher, which should also not be happening at the same time, of course. And so we're going to write a Kotlin application and this Kotlin application will give this problem to Optoplanar and Optoplanar will solve this. So Optoplanar is a constraint optimization engine, which I'll be explaining a bit more about later. And so this is the solution. Now we can see that the ninth grade can follow both the math and chemistry lesson, the tenth grade can follow both lessons, and of course Marie can actually teach both lessons to first French and then chemistry. So that's the challenge, that's the AI algorithm, and we're going to use an AI algorithm to solve this for us. Now these kinds of planning problems are all across the world, and so we're going to use Optoplanar to use it, and you might, and there's more of these kind of planning problems. For example, when you're scheduling equipment such as hospital beds, rental cars, cat scanners and all kinds of other things, the more you can optimize those kinds of schedules under the constraints when people need to use those things, and under constraints in which combinations you might have them, you can actually improve the utilization of those things. So basically save a lot of money and also ecological footprint. Same thing for job shop scheduling, when you might manufacturing things, for example cars, furniture or books or things like that. Some of the jobs you can do in parallel, others you cannot. For some of the jobs you need particular resources available such as machines or people, and with particular skills or abilities, and you need to make sure that that all fits into a plan that actually is executable, a feasible plan, and you want to reduce the mixpan, again, to improve efficiency. In other cases, the vehicle routing problem, a very famous problem, where we need to assign a number of vehicles to drive across the country to a number of locations. And we decide which vehicles goes to which location and in which order they do that. Now we have this in production for tens of thousands of vehicles, for example for technician scaling, and what we saw is we could actually, over the old system, over the non-AI systems, or more immature AI systems, we could actually reduce the drive-all time year over year by 25%, 25% less driving time. That resulted in massive financial savings, of course, as you can imagine, as well as massive fuel consumption reductions, which saves over 10 millions of kilograms of CO2 a year actually in that case. So vehicle routing is definitely one of the most profitable AI cases you can solve. Then there's bin packing where we are assigned process to machines or other kinds of bin packing, and there's also employee rostering. This is one of my favorites. It's basically assigning people to shifts and we need to take into account the wishes of those people as well as their skill sets and their affinities. The goal basically is to make them as happy as possible, given of course the constraints that our hospital or organizations or whatever the case may be still needs to keep rolling. This is actually applies for any employees that are not working 9 to 5, not just nurses and doctors, also guards and any kind of standby technicians as well as and so forth, right? So without further ado, let's get coding. So how are we going to code this today? Well, what we're going to do is we're going to build this application, so a browser interface, connects Trajacin to REST service, it will be a Quarkus application, and it's going to connect to relational database to store the information of those lessons and so forth, and OptaPlanter will optimize those. Now, just to know, we're going to use Kotlin to implement this, but you could do this in Java too. So the original requirement, you can choose whatever you like most. And also, if you are going to use Quarkus today, but you can also use Spring Boot to do this of course too, but we really like Quarkus and I'm going to show you some of the advantages of Quarkus during this presentation too. Okay, let's get started, the project setup. So we're going to set up Quarkus and with the REST service. So we're going to go to code.quarkus.io and generate our application. So I've got this opened up here already, this is code.quarkus.io and let me just increase the font a bit, not too much. Okay, and let's see what do we want. First of all, we're going to give our application a name. We're going to call it the timetabling application. I like building tool Maven, so I'm going to stick with that. And I'm going to use a REST application, yes, and I'm going to use REST-E and I'm going to expose the information through JSON to our UI and so we'll use Jackson to do that for us. So REST-EJ Jackson. On top of that, what else do we need? We're going to use Kotlin. So let's get Kotlin involved. Here we go. And let's get, I'm going to use Hibernate with Kotlin. So let's get a Hibernate with Kotlin and Panache involved too. Panache is basically some improvements on top of Hibernate to make it easier to use. So what else do we need? If you use a database, well, if you use Hibernate, we want to go to a database. So we need a database. I'm going to use the H2 database here. Why that is an in-memory database, so that's going to make it very easy. I don't need to run any other processes. I don't need to have anything, any demon running on my machine. So I'm just going to go for that. And of course, we need some Kotlin for the AI part. So we use the Kotlin AI constraint solver and the Jackson bindings as we'll send some of the information back to the UI also. I think this is my shopping list. It's time to get started. So let's generate the application. This will download a zip for us. Here it is. Time-tabling zip. Let's open it. Here we go. I'm going to extract this into my demo directory. Here we go. I'm going to show the files. Let me close up this one. All right. And this one goes too. And here we go. Here we have it set up. Well, here we have the in-blend thing. So this is the time-tabling zip we just got. There's the POM file. You can see. I'm not sure why this says yesterday. Okay. Weird. Anyway. And we're going to open this POM file with IntelliJ. So let's take a look. I'm going to open IntelliJ. I'm going to say IntelliJ, please open me a project. And we're going to use this one over here. I'm going to open this project. There we go. It's opening it up. It's loading a bit. This is, of course, in presentation mode. So you can follow up earlier. It's resolving the dependencies while it's doing this. Let's open this POM file it has over here. So this is the one generated from code.quarkus.io. It's a bit stuck. So it's probably just downloading the sources. Here we go. Yep. There it is. And so we're going to use Java 11, as you can see here. We're going to use this Kotlin version. We're going to use Quarkus 181. That's the latest version. So that's, of course, what code Quarkus.io gives us. And then here's our shopping list we had a moment earlier, which is the rest easy stuff for the rest stuff, which we put together with checks and stuff. The order is a bit strange here, though. We do have Optoplanar in there, as you can see. Optoplanar itself. And then the Quarkus integration, the H2 thing we asked for. So maybe it's basically it's all there. What do we get on top of that? We get some Kotlin sources, an example resource, not really what it was looking for. And we get some tests. I'm going to throw away the tests for today, as I don't want this video to run too late. But of course, you should be doing tests. And of course, here's how you can see how you can do it. And if you look at the source codes of this example, of the full example behind this, after you finish this video, you'll see that there's tests in there too. So please do that. Anyway, today no tests. Okay, so let's continue. We have our thing run. Let's first see if we can actually get this rolling. So I'm going to open up the console. And I'm going to do Maven Quarkus Dev. Maven Quarkus Dev. Right. And this will actually start up the Quarkus development mode for us. And during the rest of this video, I will no longer, I will not touch Maven again, right? I will not touch the command line again. I will just make changes, including changes in the POM follow any of the classes. And you will see that Quarkus will pick those up in less than a second, actually, in less than a second. So let's show that I'm here and I'm going to go to local host, right? Here we go. This is, of course, this is still set on the high resolution. Let's bring it normal. So this is our standard Quarkus thing. And if you actually look into that, we see that's in the resources, that's this resource over here. Let me just throw that away for a second, right? And refresh this. And then we get a 404, right? Nothing in there. We do say that these are the rest services available. This is the Hello World rest service that they gave us already. Let's take a look at that example resource. That's this one, a path of Hello World, right? So I'm going to rename that a bit. I want something that returns me a timetable. So let's rename this to a timetable. All right, here we go. And change the URL timetable. And we're going to say that this is not media type JSON, but not media type strings, but application JSON. We're going to do that for the entire rest resources. And similarly, I'm going to make sure that what it consumes is also JSON. So we're only going to communicate in JSON anymore. So I'm just going to specify all that here. And let's take a look now. Here we have our function Hello. And basically, it's going to, you know, we will want, and this is the getter of that, right? So we all want this to return a timetable. We're just going to do it like this. Timetable and open this up. Remove that. So we don't have a timetable class yet. So I'm just going to make a quick domain for that. Let me create a package, domain package. I'm just going to create a domain object called timetable for now. I'm another Java. This is a Kotlin thing, of course. Kotlin in the class called timetable. And we're just going to put in a name here for now. I know the name string, which is Hello, or maybe something else like High Kotlin, right? Of course, this is a bar. And we're going to use this in the timetable over here. And we're just going to have this return timetable. Here we go. Now we go back. We don't touch the terminal here. We just go back here to the browser, click refresh. And we get now, of course, look, there's this timetable thing. So let's actually go there. Let's actually go to slash timetable. And what you see is we get our JSON version of this High Kotlin thing, right? Okay. Now, okay, we have Quarkus set up. Let's do something domain specific, right? So we're going to create the timetable class diagram, the domain model, right? So in our domain model, what do we need? We need time slots and rooms. That's where we're going to assign our lessons to. And so our time slots will be for a particular day of the week, Monday, Tuesday, Friday. There's no date there. It's purely Monday, Tuesday, Friday, or so forth. And it will have a certain start time and an end time. So for example, from 830 to 930 is the first class, first time slots. And then the second one is 930 to 1030 and so forth, right? We'll also have a room object, which is like room A or B. And then of course, we're going to have our lessons, which will have a subject such as math or chemistry, a teacher, such as Marie Curie, and a student group, such as 9th grade or 10th grade. And the interesting thing is these lessons, we will need to assign them to a time slot and to a room. But that's the AI part. That's the object part who will actually assign us to those things. So we will start those out as NULL. So let's code these things in Kotlin. So here we go. We are, we will create a Kotlin class here for our time slot. That was the first class, time slot. And so our time slot has a late-init var of day of week. Now why late-init is because if it comes from the database, then Hibernate will fill it in for us. And if we create it for test data creation, we'll actually create a constructor for it. So late-init is actually a good approach here. And we're going to do the same for the start time, which is a local time. And here we go. And we're going to do this, and we're also going to create an end-time right-back as we saw a minute ago. So I'm going to create an explicit constructor for those three things. You might imagine that we could add these here on the top, but I actually want two constructors. So I'm just going to add an empty constructor too. So we now have two constructors, one to fill in these three things and one which is just empty. This is the one used by Hibernate as well as, yeah, Hibernate just for this case actually. And this is the one we'll use when we want to create, start creating test data. Okay. So let's create the room class. Here we go. We have a room class. And we're going to do very similar things here. So we're going to say a late-init var of the name of the room. And we're going to add a constructor for that, which just has that name as a constructor. The name could be room A, room B and stuff like that. And of course we're going to create a non-empty constructor again for Hibernate. Both of these things will later actually also end up in the database. But I'll worry about that. And so we'll need an ID too, but I'll worry about that in a minute. Let me just start. Let me just continue like this first. So I made a lesson class. What is our lesson? Our lesson has a late-init var of the actual subject, which is going to be string. We have the teacher. And we have the student group, which is also a string. Okay. Here we go. Now, interestingly enough, we need to assign these lessons to a time slot and to a room. So let's start by assigning them to a time slot. And so this is of the time slot type. Now, these actually start out as a URL. So while we, when we create a test data, they will not be assigned yet. And yet they will go into the database. So we're going to actually have to use a question mark here in, right? Because they can't be null. Same thing for room. This variable will be null in the beginning. It will be stored with any of those in the database. It will exist for a while until the plan comes around and actually assigns them. For test data generation, I will want to have a constructor later on, which just has these three fields here. And of course, because this is going to go in hibernate, we need an empty constructor. And in fact, we also need this one for optoptar, because optoptar will need to be able to create lessons too. We'll get back to that in a minute. Okay. Now let's hook these. So we now have a lesson room and a time slot class, but we will actually have multiple lesson instances that will need to be assigned. Matt, chemistry is a fourth, for example, multiple rooms and multiple time slots. And so we will want to keep all of that together somewhere. And that's where I'm going to make that timetable. Timetable is one data set, one school's problem, right? And your application might be handled in multiple schools, but each school has one timetable. And that's one thing that needs to be solved in a whole. It's unbreakable to be solved, actually. Well, you could partition it, but it's not a good idea. Anyway, so let's take a look what we want to do here. We want to hear in the timetable we want to have a list of all the possible time slots. So here we go. Time slot list. All right. We make a time slot list. We're going to make a room list too, which is a list of all the rooms in this school. And we're going to make a lesson as to which is a list of all the lessons in this school. Okay. Now, let's make a constructor for that. All right. For test data thing later on. Here we go. And let's also do an empty one. Actually, this is the one that opt-in really needs. This thing will not go into the database. So for them, it's not really needed. Let's go back to our timetable resource. As you can see, I made a spelling mistake. So let me fix that. Our timetable resource. In fact, if we are consistent, this T should be capital because the time table there has a capital. Okay. And here we're just going to add three empty lists for now. Not list of list, but list of, of course. I always get this wrong. We're just going to add three empty lists in there. And if we now jump back to our UI over here, to our UI, we ask for this resource. Let's take a look what we get. We get three empty lists. So far, so good. All right. Okay. So what's the next thing? The next thing is we need to add this stuff into the database. All of this needs to be database aware, right? So let's start with the time slot again. What I'm going to do is I'm going to add an entity annotation on this, you know, for hibernate, which will immediately complain because there is no ID. So we're going to add an ID. Let's let me first add the ID. The ID is var ID, the long question mark null. Why it will start out as null and then hibernate once it goes into the database will fill it up for us, but it will live a while until it actually hits the database. So this for hibernate is its ID. And we're going to have the value generated automatically. So we don't need to worry about that. I'm going to copy paste this ID approach for all for all three things that go into the database. So that's what goes into the database, the room goes into the database. So we need to add the annotation on this, right? And the lesson needs to go into the database. And the lesson into the database too. Okay, great. So now, oh, and of course, hibernate says our at least intelligent helps us here says, okay, the entity has an ID that that's the ID here, these fields I can figure out on my own because they're your strings. So that will go into var charge into database. But what about this these because you know, what's time slot, right? So you will need to tell them that this is a many to one relationship might we need to tell hibernate JPA that same for the room. It's a made to one relationship one lesson. And multiple lessons can be in the same time. So it's multiple lessons can be in the same room. As long as they're not in the same time slot in the same room at the same time, it's all fine. Okay. And if they are, we still need to be able to represent it in the database, just not a feasible schedule anymore. So so far so good. We will not put time table in the database, but we will want to fetch it from the database. So what I'm going to do is I'm going to create a persistence part and domain package. And in this, I am going to create a repository for these things. So let's start with Java force of habit, I guess. And I'm going to create a time slot repository here. All right. Here we go. We have a times of repository. And this is going to be a panache repository. So panache, as you as you probably noticed when I selected things for hibernate, that's actually the helper things on top of hibernate to make this much easier. And so if you just say that this is for a time slot, all right, then let me just show you what we get for free out of this. If you actually didn't just say, okay, what are the methods? So all kinds of methods we get out of this, we get a whole bunch of stuff like deleting, counting, finding, and so forth, and so forth, and so forth. Anyway, let's get back to our code. So this is basically for those of you familiar with a DAO pattern, an automatic DAO force, right? We will do the same for the room and the lesson. So let me just create those two. Let me just say, okay, here we go. We're going to create one for the room repository. All right, that's again a panache repository for room this time. Here we go. And we're going to create one for the lesson, the lesson repository. Here we go. Okay, forgot to click the right thing there. So here we go. And that's one for the lesson, right? So now we have those, we can actually ask if we have an instance of these, we can actually just ask, you know, give me your find methods, give me your delete methods, your add methods and stuff like that. We still need to expose them to be able to use in dependency, inject them into other bits of our like in the table time table resource. So we're going to have to add that these are application scopes, right? And so the lesson repository, the room repository, all of them are application scope, which basically means there's one instance of them. And we can just, and then we can reuse can inject them and things. So we will, for example, inject them in the timetable resource over here. So here we're going to say I'm going to inject the late any bar of the timetable repository time slots repository. Here we go. All right, which basically means that this time slots repository, which we created here, which is application scoped will be injected in here, and we will then be able to use that over here. So here we will be able to say, here we need to give a list of time slots, right? So we can just say that repository and just list all of them, right? We should probably also sort them, but I'm not going to do that right now. So now we actually create me, we actually give back the timetable with all the time slots from the database and not just an empty list. Similarly, we will do, of course, an inject of the room repository, which is a room repository. Here we go. All right. And over there we will again do a list, list all of. All right. So still no compilation error. So that's good. And we will inject the late any bar for the lesson repository, not sure why it's again proposing the other one, but anyway, please give me a lesson repository. And we're going to list all of that too, right? Okay, so let's see if that still works. We go over here, we crash the refresh button, the refresh button, internal server error. No pointer exception. That doesn't sound quite good, right? So why is that? Um, the null point reason. Interesting. Because we don't have our database setup yet, of course not. So we need to go into the application properties and actually make sure that our database is set up. So we need to tell Corkus, okay, Corkus, I would really like to have a data source of the DB kind of for H2. And I would really like that data source. So I need to give it a gdbc url and the gdbc url. All right, it's going to be gdbc h2 because we're using that type of database man because we're going to use it in memory. And I'll give it a school time tabling name that matters less. And the problem is that we need to also make sure that hibernate generates the timetable for us, right? And the schedule, the DLL schedule in the database for us. So what we're going to do is no, we're going to say, okay, database, database, um, generation is drop and create. So let's take a look now. Let me go back to over here with fresh refresh. And that looks much better, right? So now it actually goes to the H2 database, fetches all of the types of the rooms and lessons in there, which are none brings those back and gives us this resting. So we're actually now already touching the database. That's that's a good thing. Now, let's throw some stuff into the database to actually get some test data in there. So what I'm going to do is I'm going to add a package called bootstrap, right? And in here, I'm going to add a demo generator. I'm going to call them class. Demo data generator has a good name. Here we go. And now my demo data generator, it will, we're going to make it application scoped, just like repositories, which means we'll only need one of them, right? And what we're going to do is just like the timetable resource, I'm going to inject all of these repositories because we'll need them to actually add those testing, those test data in there. So I'm injecting the time slot of the room and lesson repository in here. So now I'm going to create a function here to generate the demo data. And a bit like this, but I should spell better generate. Okay. And we're going to have this of doing observes of the startup events. It's actually going to listen like, okay, is the is the score is starting up. And if it scores starting up, then please execute this code. And so, and when it starts up, we can actually now add some, some test data in there, right? Now, so what we can do is we can say, okay, time slot repository, persist. And here we can add a list of the time slots to persist and so forth, right? So instead, but as it will take a while to write all this, what I'm said, I'm going to do is I'm going to, I have some help profiles here. And one of them is for the demo data generation. I am this is, this is the one I'm going to just copy paste this stuff in there. And you can see also should make it also transactional. So let's let's do that in a second. So I'm going to just copy this in there. I'm going to cheat a little bit because writing all this is not interesting for you to follow up. So I'll just throw it in here. All right. And I'm going to make this transactional. Here we go. So let me add, we'll fix some of the import statements, right? And let me walk you through the code I've just added, which is going to look very familiar, I hope. So what, what did I just add? I said, okay, create me a time slot list, a mutable list, please. Shouldn't actually, doesn't actually have to be mutable. But anyway, yeah. And here's a list of all the time slots. So we're going to create for time slots for two days, Monday and Tuesday. And we're going to have five hours on a day, the first time open 83930 and so forth. I'm also going to create a room list. So in the end that persisted of course with the persist method I just shown you. We're going to add a room list with rooms A, B and C. And we're going to add a lesson list where we add a bunch of lessons for the ninth grade, 10 of them, and a bunch of lessons for the tenth grade. This is why I actually used the mutable list, but you can argue you can just throw it in one list, it would be more efficient. And at this part, let's not do that. That's already signed some of the lessons to give an idea what will happen if you do that. So let's just persist these. Okay, let's see how that works out. If you go back to our UI and we just click the refresh button. Again, I haven't touched. I think then it actually turns out. So yes, we have all our time slots lists. You have Monday, you know, all 10 of those. We have our rooms, rooms A, rooms B and room C, and we have our lessons. Now this is pretty ugly to actually look at, which is Jason of course. It's not really meant for humans to read. So let's see if we can make this a little bit more pretty. Let's see if we can make it solve them. So what we did, so now we need UI. So basically, we need to add to add this part to our REST application. The problem is our UI, well, we could write in Kotlin of course, but then we need to generate JavaScript out of that and so forth. I'm just going to use a static JavaScript file. That's the easiest approach because, but the thing is, I'm not really a fan of Java writing JavaScript. It's not type safe. So when I write JavaScript, this happens, right? I start, you know, saying a couple of things that are really not suited. And this video would become R rated if I actually would code this JavaScript part for your life. So instead, I'm not going to do that in public. So what I'm going to do instead is I'm going to take a little shortcut there. Here's my helper files. I have 40 UI, I have a couple of helper files here, which is really just an application. A client UI already, just a client side, right? So a JavaScript file, an HTML file, and an opt-up planner logo to show in there just to make it a bit more interesting. So where am I going to drop this? Well, I'm going to go to source main resources, meta in resources. And if I drop it in here, then they will automatically show up, right? Now let's take a look here. So we have our, this is the JavaScript file. You can see it's a typical JavaScript. I think I've shown enough. Otherwise, for, otherwise people might run away. And then here the HTML file. Now in the HTML file, I am using a bit of Twitter bootstrap in there. And so I want to use some font web jars in there. So we need to add these web jars to our .xml here. So I'm going to go into the .xml. I'm going to add some dependencies there. And once I do, let me scroll to the bottom here, you'll see that I will still not restart Quarkus Dev, because I will, I intended never to do that. So in, let me just add the dependency I want to add. So these are the ones I want to add. I'll copy them and explain them to you. So these are the ones I want to add. First of all, I'm going to add an extra Quarkus one that I didn't check on the beginning, but I could have, which is the web jars locator, which allows us to use these web jars and automatically expose them to be used from HTML. And then these are the actual web jars that I'm adding. That's Twitter bootstrap, jQuery, font awesome, and moment.js. Moment.js is something to do with time on the client side, which is important when you're doing scheduling like tasks, right? Fair enough. Let's see what happens if we now go back to our local hosting, and we go to the root of that and we do refresh. Here we go. Why is it? Okay. So a bit takes a second longer now. And here it is. Right. And I still have it on 100%. So here it is. Right. So what do we see here? We have our rooms, which are coming from the database A, B, and C. We have our time slots. We have our own assigned lessons. This is actually quite perfect, right? Let me just prove you that this is coming from the database. You might not believe this, right? So let me change this room A into room something else, right? Let's go to bootstrap here. Let's change this room into room K from Kotlin, right? And again, I just go here, I just click refresh. And now he doesn't have to do the POM stuff anymore. So it goes a bit faster. And this is now room K, as you can see, right? So it's that easy. I think it's time to add a little bit of artificial intelligence in this, because what we want to do now is we want to click the solve button. And when we do, we get a 404 because of course that stuff doesn't exist yet. All right. So we want to make sure that when we click the solve button, these undersigned lessons, math, physics, chemistry, and so forth, get assigned to these three rooms and to these time slots. So let's get back and let's see what we can do to make that happen. Well, we're going to go to the timetable resource here. And we're going to add a post for that for that solver to do for that solve. So we're going to add a solve function. And in here, we're going to do the magic, but actually do the solving rate. So what do we need for this? We need optoplanar for that. So let's go a bit further in our presentations. So we've just added the database. Let's do some AI planning optimization. So what we do that, we're going to add optoplanar. And optoplanar needs to know what it can optimize. So this is our domain mode. Optoplanar needs to know that it can actually change the lesson class instances. So those 20 lessons we have there in our test data set. And it can, in particular, it cannot change the subject or teaches or cannot decide who's going to teach which lesson, but not in this case at least. But it can decide for each of those lessons when and where those lessons will happen. So the time slot and the room. So what we're going to do is we're going to add a planning annotation on the lesson class because there's something in there that will change. And more particularly, is the planning variables that matter. That's the time slot and room fields. Those two fields will change. So those are the two we were going to add to the planning and a variable annotation. And any class that has a field that has a planning variable annotation must have a planning entity annotation. So these start out as NULL. And after solving, they will be non-NULL, right? Not NULL. So let's do that in the code. We go to our lesson here and we're going to say, okay, it's not just an entity, but also a planning entity. So this is for the database, for Hibernate. And this is for Optoplanar planning entity. And we're going to tell them, okay, so this one is a planning variable. You have to figure out in which room this goes into. And also for the room. Now the problem is that Optoplanar needs to know which time slots can I choose from. It cannot just create new time slots. It has to actually have a list to select time slots from. Same thing with the rooms. It needs to know that the rooms are room K, B and C there, right? So what we're going to do is we're going to give this a value ref. And I'm going to call this the time slots range. And this will map somewhere else to list of time slots. And what we're also going to, what I'm also going to do is, and of course this is actually multiple fields. So I'll have to like this. And the same thing for the rooms. Somewhere we'll need to get the room range. Okay, fair enough. Where are those? Where will we get those things from? Well, we'll get those from the timetable class, because this actually had a list of all of the time slots, the list of all of the rooms, and so on. And so this is the ideal place to get these from. So here we're going to tell, we're going to say, okay, this is the data set. This is the problem we're going to give to Optoplanar. It's a timetable problem. So that basically means that once the lessons are assigned, it's also a solution. It's not just a problem, it's also a solution once these lessons are assigned. So we're going to give it the planning solution annotation. And so it needs to pick from these lists of time slots. So this is a value range provider, which actually provides all of the time slots that Optoplanar can choose from. And we need to give that a name. And the name is of course the time slot range. All right. And let me take a look here. This is the ID. So, and similarly, we are going to do the same for the room list. Here is a list of rooms to pick from. Optoplanar also needs to know where the lessons I need to assign, right? You can't just say any kind of lesson that's in memory. Actually, you need to get the reference to those. So we need to tell them that this is the planning entity collection. So that's actually a list or a collection or an area of all possible playing entities that it needs to assign, right, in the time table. One more thing we need to do here. Once Optoplanar goes through these lessons and by one and one by one starts assigning these lessons to a time slot and to a room, picked from these time slot ranges and room ranges, which are over here. All those lessons will be assigned. And that will actually, it will need to somehow score that solution. Tell how good that solution is. Tell if that solution is feasible or not. And if that solution, when the solution is better or worse. And we will represent that by a score, right? Let's call the score. And particularly by a hard soft score, which means hard constraints need to be fulfilled and soft constraints should be fulfilled as much as possible. So, and we're going to start that score out and URL because in the beginning nothing is assigned and we don't know the score. And Optoplanar will actually for us assign them and also tell us what the score is of how good he done his job. So it's like a student who actually grades himself. Okay, interesting. So that's the model side. Besides having the domain, we need some constraints too. So I'm going to add a package here for the constraints. And the constraints, well, I'm just going to add a single constraint provider. So that's something where we will define our constraints in constraints. There are like no to teacher, no teacher should have two lessons at the same time. No student groups, which have two lessons at the same time, things like that, right? So we're going to call the Scotland class the time table constraints provider. And that one will implement constraints provider. Here we go. Provider. And of course, I will complain because there are certain methods that are implemented. And we're just going to create an empty one for now, right? I think it's like this. Let me just check for a second. That's, that's, that's this. So we're going to create an area of just going to create an empty area for now. In a few minutes, I'm going to add constraints in here and we'll see how the solution actually behaves. The artificial intelligence actually changes its output based upon the constraints we will add. We'll do that in a few minutes. Because first of all, we need to make sure that all of this is actually hooked into our solving thing. So when we press the solve button, this is called still nothing happens. So we need to make sure at that moment in time, we're actually solving. So what I'm going to do is I'm going to do an injection of something called a solver manager. And that's what uses to, that's what you used to actually solve a problem. So that's for a timetable. And we're going to, and it also has a, you can give it multiple problems. So it has two generic types. One is the type of problem we're solving. That's our timetable problem. That's the one that has a planning solution annotation. And then the other thing is if you want to give it multiple problems, this is the, then we can differentiate them by some sort of idea. And this is the type of the idea. So I'm just going to put along here. Okay. So fair enough. Here we have our solve methods. So what are we going to do when we have our solve methods? We're going to say, please solve this problem. But we want to see as optimal finds better and better solutions, we immediately want to see those in the UI. We don't want to wait until it's finished. We want to see the intermediate results. So I'm going to actually use solve and listen, which means give me the intermediate solutions too. Now this has three parameters, at least the overload method I'm going to use. One is give me the idea of that. So I'm just going to hard code that to that problem ID one, because we're only going to solve one one school at a time right now. If you have a multi-tenancy approach, then we would, you know, each tenant would have their own idea. And we would give that to there. And then I need two functions. The first function is to actually find the timetable. So what I can just do is I can say, okay, this method, if it's transactional, let's do that right now. Then I can just say, okay, this get timetable. That's the first method. And then this will add. So the first method is to load the problem. The second method is to save the problem. So this is the one that I'm going to create a function for, function save of a timetable. Now it's important to understand that, well, this won't work to find the get timetable, because it needs to find by ID. So instead what I'm going to do is I'm going to find by ID here, I get an ID, a job ID, which is that long, this is that one lot one out there. And so I can just return, get timetable. That's actually good enough for me. And this will one will return a timetable. So now I can use this one. So this is just to wrap around that function, which transforms it from actually having to knowing the ID, just getting the one timetable that we have. Okay. And maybe solar manager should support such a function to just make it easier. So we don't need to write this boilerplate code if, if you don't do multi-tenant solving. That's interesting to think about. Anyway, once we have our timetable available here, then this will be called every time optomor finds a new best solution, in which case we will want to restore those lessons as particularly those assignments of time shop and so forth. So what I'm going to do here is I'm going to use a for loop in of the timetable lesson list. All right. So for each lesson in that lesson list, I'm going to look for the attached lesson. If you're familiar with JPA, that basically means that we're going to go into the lesson repository. So these lessons are not attached anymore in JPA terminology, which means that any change we do to them do not get stored into the database. So what I'm going to do is I'm going to find by ID the, the lesson that is, you know, the lesson that's assigned, right? And then it's a typist match, of course, I need to make sure that it is, it's not safe. The ID itself can also be known. So, but I know that one optomor gives us a lesson list that each of those lessons in that lesson list will come from the database, from the find by ID method, and therefore will have an ID, right? So it's safe to do this check. I also know that I know that these lessons are in the database right now. So I'm just going to for now just, just, you know, make, do the if, skip the if check, which is dangerous, of course, in real life environment, especially second one, you might want to do an extra check on that and, and be able to deal with that condition if that's the case. And luckily, Kotlin warms us for that. So then we're going to take our attached lesson, we're going to take the time slot. We're going to sign that to the time slot of our lesson. We just, you know, we're saving, right? We're going through all the lessons to save them. Similarly, we're doing the same for the room. All right. Okay, here we go. And now we're finished. So now what happens is when we click the solve button, it will call solve and listen, which will first load the problem by our find ID, find method, we'll just get the time table from the database. And then when we're finished, it will put it, it will save the database in, it will save each of the lessons of that time table in the database by basically just saving the time slot and room assignments. Let's take a look at how that works out. Okay, it didn't crash. That's a good thing. Well, it actually probably did crash because where is my test data? Let's take a look. Okay, we're getting an error here. So that happens. And the nice thing about this is that when this happens, you are getting a nice thing. So here is it's a good warning, good error message that which helps you. And here it says that the solution class must have one member with the planning score annotation, because I forgot something. Opto planner needs to know that this core is actually the score for this thing. And it needs to know it needs to have an annotation for that. And I forgot to tell him that. So let me just tell him that. All right, here we go, planning score. Let's go back here. And let's hope this time it's better. Yes. So it starts up at least, let's click the solve button. What will happen? Not found. Okay, that's not good. Of course, we need to make sure that this post method over here actually has a path. So that's a path there called solve. Because if you look at the solve button, it's actually going to go to that dash solving. So let's see. Now it's actually solving good. And again, another error. No worries. Let's take a look at what the problem is. Okay, the problem is that the context is not active. That's because it's not a transaction. So the save method should of course also be transactional. Right? So third time's a charm. I'm sure it is. Let's try again. Okay, let's take the solve button. Does it actually assign these things to a lesson? And it does. It's just assigned every single lesson to the first room, room K, and to the first time slots. So it actually did solve it. But there are no constraints yet. So opto plan is going to do whatever it wants. And of course, it basically was the worst possible schedule. So it's time to start adding a few constraints into this. So when we go back, we go back to the constraint provider here. And what we're going to do is we're going to say, okay, I want the room conflict constraint. And I'm just going to give back the constraint factory in that. And I'm going to create this method, right? So this will create a constraint for us. So you can do this in a simpler form, but this is actually a form that will give you incremental score calculation, which is going to be a huge performance gain, right? And opto plan will look at many, many combinations. So any combinations of the solution, it will look at any combinations of lessons being assigned to rooms and times. So it will look at, you will need to score those. And then it will try to find the best one out of those in a very, very smart way. It will not look at 1% of the solutions, not even 1% of the solutions, because the search piece is so high. But it will look in a very intelligent way into lots of solutions to come up with in as little time as possible, the best possible solution. And this API will actually help drive up the speed for that so it can look at more solutions, which is always better, of course, more solutions per second. So what are we going to do? It's very much like SQL. We're going to say, I'm going to look for a lesson. So I'm going to look for a lesson. And let's just say we have a simple version. Okay, this is a bit to correct syntax, of course. And then what we're going to say is, okay, let's just say if we have a lesson, we're going to penalize that. And then we can say what kind, what is it? It's a room conflict. And we just say, okay, it's a hard, soft score, one hard, for example, right? We don't want this to happen. This won't give much effect. And by the way, this constraint factory is empty. This won't give much effect because it will basically select every lesson. And for each lesson, we will use a point. But no matter how we design those lessons, that will actually not make any difference. So that's not what we want. What we want to check is when we have a lesson, and we join that with another lesson, just like in SQL, right? Now we have two lessons. And then for those two lessons, they actually have the same, the same time slot, right? And also the equal, the same room for there in the same room at the same time, right? Then we have a problem, right? So then we have a conflict. So every time optoplanar assigns two lessons in the same room at the same time, it's going to get hit on the head. It's going to this penalized method will will hit it on the head and it will get a hard constraint, right? So let's say look what happens if we now go back to the application. Again, just a second later we can test this out. We press the solve button and this looks a lot better, right? Because now every lesson is assigned to, I mean, there's no two lessons in the same room at the same time. Is this a feasible schedule? It's not. Why not? Well, okay, let's take a look at Alan Turing. So let's look at the teachers here. Alan Turing over here has to has to teach two lessons at the same time on Monday morning. This is not a feasible schedule. So let's go back to the code here. And let's actually also check for teacher conflicts. So I'm just going to duplicate this code now for so it's a bit faster. So we're going to call this teacher conflict, right? Same principle. When we have a lesson and another lesson which are in the same time slot, but now for the same teacher, then we're going to penalize this. Then we have a teacher conflict. Notice how these two constraints are isolated from each other. That's a good thing. So you can turn them off and on individually. And also you can, you know, work on one in isolation, which is a really, really good thing because otherwise it gets quite complex quite fast. Anyway, we've had this now. Let's take a look as if we press the refresh button and we press the solve button. All right. And we now see that room wise, this looks good. No two lessons in the same room at the same time. It's a bit strange. We have three lessons at the same time. We'll take a look at it in a minute. Teacher wise, this looks good. No teacher has two lessons at the same time. But the student group wise, that's why we had three lessons at the same time. The 10th grade has to do physics in Spanish at the same time. So again, same solution. We now also not just tech for teacher conflicts, but also for student group conflicts. So this is now a student group. And then we can simply add this constraint in there. And if we jump back to the UI here, we should now have our first feasible schedule. So feasible means no hard constraints are broken. Means that we can actually execute this plan. So room wise, this looks good. Teacher wise, this looks feasible. I'm not saying it looks good. It looks feasible. And the student wise, this looks also feasible and good. So teacher wise, it actually doesn't look good. Why not? Matt Alan Thuring, the poor guy, has to have a teacher lesson, then has an hour break and twiddle his thumbs, teacher lesson, twiddle his thumbs, teacher lesson, twiddle his thumbs. It's really, really, really a terrible schedule for him. So we can actually fix that. We can actually go back into the constraints, add soft constraints, and then Optopan will take this into account. And if you want to see that, please take a look at the source code of this. We add a bunch more soft constraints to actually improve the lives of the teachers and the student groups to improve the quality of education by basically scheduling them better. You can easily add your own. For example, no gym class after lunch, or at least try to avoid it. No three hours of math after each other on Monday morning. No student will survive that, or at least like that. So it's pretty easy to do all this. The code of this is available. Just go to the Optopan Quick Starts repository. The link is below in this video. And then you can run this yourself, or you can see how we've written it from scratch. So I would like to say thank you for listening. So this is the URL if you want to try out this code right now. You can also even build a native image of this with main quark is minus the native. That takes a bit longer. You need to have grow install and stuff like that. But that means you get a native executable. So instead of a bytecode that you need to run on a JVM. And here's the links to the projects, optopan.org, Quark is OTO, and of course Scotland, where we've written all of this thing into. If you have any questions or have data post a comment or to ask on the optopan.gov mailing list or stack overflow or something like that. So thank you for listening.