 So, welcome back everyone. So, I'm gonna sit down for a moment because it's easier for me to type. Actually, maybe that's it and then let me walk a little bit and then I'll get back to this. So first, we're gonna do cardinality constraints and we're gonna do the CDCLP that I've shown you before where we have the SAT solver on one end. So this is the SAT solver running CDCL and then on the other end, we'll have the T-resolver and here we're gonna do cardinality constraints. So cardinality constraints are quite easy. It's something like A plus B plus not C is smaller equal to one, for example. So this means that out of these three literals at most one of them must be true. Okay, and basically what will happen is that you will have a set of cardinality constraints. So this is the cardinality constraint input and you have the SAT solver obviously has the CNF input because that's what it understands. And basically the SAT solver will be running on its own without any cardinality stuff going on but it will be calling your cardinality solver, theory solver and asking you, is this assignment okay? Is this assignment okay? For example, it will set A to one and B to one and then you're like, no, this is not okay. And the reason why it's not okay is because both of them are set to one. So you tell them, hey, no, it's not okay. One of them must be zero, right? So this is the reason. This is wrong. I flip everything and I say that's the reason why. So I give this back as a reason. This is my reason. This is a reason for the conflict. Okay, this is my conflict closed. And the reason, and of course this means that the current assignment of both of them being one is wrong. So this is the kind of stuff you'll have to implement. And I'll explain, I'll show you how and where. So I have implemented this into crypto mini SAT and it's basically running a Python file. I'll show you it in a second. Here we go. So if you have done that Docker pool, whatever, then soon you will be able to do the following in a second. I'll explain what you need to do. I just want to show this for a moment. So this is the common line you'll have to run but it's very, like you just copy paste it obviously. Nobody types this thing in. You run it. Oh, it's a little, it's unsatisfiable. All right. So what happened here? So this was the set of variables that the current assignment that the T resolver was given. Okay. And it said, well, I'm gonna examine all the constraints that I have. So these are the four constraints that I have. Variable 10 plus variable 11 must be less than equal to one. Not variable 10 plus variable 11 must be less than equal to one, et cetera. Okay. So these are the four current and the constraints that I have. And examine all of it and says, nothing to do, I return zero. And then it's gonna say, okay, well, you know, like the solver did something. It's at 11 to minus one. What's gonna happen now? Says, well, I'm gonna examine this thing. Nothing happens. I'm gonna examine this thing. Nothing happens. I'm gonna examine this thing. Like, oops, something is weird. This is a constraint that basically says, it says that v10 plus v11 not is smaller than equal to one. But this is one already because you see that 11 is set to false. Minus one means false. Zero means it's unset. So it's minus one means false. 11 is false, which means that v11 is one. So what we have is v10 plus one is smaller than equal to one. So I'm just gonna cancel the two things out, which means that v10 is smaller than equal to zero. But of course it's not less than zero because there's no such thing. So that means that v10 must be zero, right? There's no other way. So that's a propagation. That's a new fact that we know. And so we're gonna say, okay, that's good. So we're gonna propagate 10 to be zero, right? Minus 10 is 10 negated. So 10 negated must be one, which means that 10 is equal to zero. And the reason for this is that 11 has been set to false. So the reason closed that it is gonna be is that I'm just gonna read this thing out. I'm gonna say minus v11 or v10. Or not v10. So how does this work? Yeah, sorry, the other way around, right? And that's it. So now we propagate it and we give this back to the solver. So we actually return this value to the solver, which means that one means it's a propagation and here is a list of things that we propagate. And the list contains exactly one thing that we propagate. And this is actually the kind of hard thing I want to maybe instead of propagation, which is always much more complicated, what I will want you to do is conflicts. And you will see that there are some conflicts here. For example, here, 10 and leave, 11 are both zero. And it's going to examine all the constraints. So this constraint is fine, this constraint is fine, everything is fine, but here, we have a problem. Because if both of them are zero, that means that the value here is two. You see that it's two, but the right-hand side is one. It actually prints the value. You see that it's going on. This thing, if I add it together, because both of them are inverted, both of them are false, the two together add up to two, but this constraint says it's less than equal to one. So there's a problem, so it says here is a conflict. So I'm just gonna add everything that is part of this conflict into the conflict. And that is these two variables cannot be at the same time, true, because otherwise this will not work. And this is what you have to implement. And then all I'm gonna return is two, which means that I derived a conflict, comma, basically an empty list. It doesn't really matter at this point, easiest for you to return an empty list, because this could be a set of propagations, because you can propagate and conflict at the same time. But we're just gonna say an empty list of propagations and the conflict that you derived, right? So only thing you really have to deal with is this. All the rest, let's not deal for it for a moment. So there's propagations and conflicts, but let's just concentrate on the conflict. It's good enough if you concentrate on the conflict. And these four constraints, of course, cannot possibly be satisfied, so eventually it will find unsatisfiable. So that's what we're sort of aiming for. I can show you some interesting things based on top of this, but let's just go for this. And let me show you the code that I have written up to do this so that you can sort of follow. So this is the set of coordinate constraints that were active last time. You see this is the coordinate constraints. So it's quite an easy Python, oh, maybe it's not that large, sorry about that. So this is the set of coordinate constraints. Okay, I'm sorry, I mistyped. So this is the set of coordinate constraints that was being run. I don't know if you remember. So this is the left-hand side and this is the right-hand side. And at the top you see the explanation of what it does. So this coordinate constraint says one times V10, plus one times V11 is smaller than equal to one, et cetera, et cetera. And here it's like the same thing, but it's not. And what you do, we say, okay, well the active set of coordinate constraints is this. If this one, you can see there are some other things that you can do if you want. And for debugging or whatever. And here we're gonna implement this Python function called propagate. And every time it's being called, this thing says a propagation is called and this is the variable assignments and it prints all the variable assignments like you saw in the previous example. And I'm going to, obviously this is not implementing all the things you're supposed to implement because all it's going to do is return zero. So that basically says nothing to do. Theory solver is happy. Of course you need to add your lines of code here. And in case you want to do a conflict, for example, then this is what you need to return, this kind of stuff. Where you return two, indicating it's a conflict, you put this bracket in there because most likely it's not interesting to you. And then you put the reason. So this reason needs to be a list of literals that are all falsified under the current assignment, right? So this needs to be a conflict. It needs to be a reason to explain this conflict. And this needs to be a list of literals that are falsified. For example, you can return this. And if you turn this then obviously the assignment for one and two must be minus one, minus one, and for three must be one. Because it means that this close is now falsified because this is zero, this is zero, and this is zero. So everything is zero, everything is falsified. This is a reason. It cannot be that one of them is, for example, this cannot be because then it's not a conflict, right? Because then it's not falsified. And so let me run this thing just for a moment with, because I already have of course the solution, but here is one without the solution and it finds a satisfying assignment, which is of course impossible because that means that you didn't do the job, right? But anyway, let's not get into details. This is what we were interested in. This is the one that we have already seen and it finds an unsatisfiable. And don't forget that this actually has a CNF input as well, you see this CNF input? So if you have a look at the CNF input, it's got some closes inside, it's got some stuff inside. And so it both eats, this system will both use CNF, you know, just like a regular SAT solver and it will use the CDCLT as well. So it will run your, your cognitive constraints as well. And here's your, and here's your cognitive constraints and here is the place that you're supposed to implement returning a conflict like this when there is a conflict. So you're supposed to return, basically you're supposed to do something along the lines of four card in cards, and then say, well, I'm going to examine this, right? So you have to examine this cognitive constraint if it's okay, and if it's not okay, then return, you know, two comma, this thing comma reason, right? So that's what you're supposed to do. That's it, that's what you're supposed to do. Effectively examining all the carding constraints. Now, just let me explain to you how you do this. So what you need to do, so here, you go to Cryptomaniacetone GitHub and then if you go into the branch, then at the bottom of it, you'll see Winter School. So you have to go to github.com msos.cryptomaniacetone, you can also just search for it. So if you search Cryptomaniacetone GitHub, then the first thing, the first result is this, you click on it, and then here on the branch, you have to select Winter School. I have to go to Winter School. So this is Winter School. You know that it's a Winter School because you see at the top it says Winter School. And then here in the readme, if you look down at the bottom of the readme, you will see there is CDCLP. And what you have to do is do this. So you create this file, it says, create this file called a.cnf. So I'm gonna do that. Here's my file, that's good. Then it tells you to create a CDCLP.py file. So I'm gonna do that. I'm going to take all of this. You're supposed to do the same, basically. Just copy-paste this into the file, like that. So now we're good. It's all there. So this is the thing, right? It's all there. And then it tells you that run this thing. You just copy-paste it. And if you have installed Docker and you're on Linux, then this should work. If not, you just remove this part, then it will work. All right, sorry. And then, here it is. And you see that it's actually telling me that it called all the things, but of course it didn't examine anything. So this Python file is missing what you want, basically. It's missing the CDCLT part because it's not examining any of the cardinality constraints. So if you want to examine all the cardinality constraints, then you have to do something. For example, we can go here and we say, and we're gonna say, right-hand side, and we're supposed to examine these constraints if I understand correctly. And you see that it's supposed to now examine this set of cardinality constraints. And it's your job to basically implement the checking and then returning something along the lines of what's in the file. So you're supposed to return something like this when the cardinality constraint fails. When the cardinality constraint is falsified, when it's not being satisfied with the current assignment. And you always get the current assignment here. So the current assignment is always printed, as you can see. So here's the current assignment here. And the current assignment just says one is set to two. And the next current assignment says one is set to two and 11 is set to minus one. And the next one it says 11 is set to minus one and 10 is set to minus one. At this point, obviously, this cardinality constraint is being falsified. This cardinality constraint is no longer valid. Because it says not 10 plus not 11 is less than one. And that's not the case because not 10 plus not 11 is two here, actually. So you have to do something about it. And basically that's your job. So I will be obviously supporting you. And if you have any questions, you can come to me. But you need to navigate to this to CryptoMinisat. You need to navigate to CryptoMinisat. And then check on branch. You can find here winter school, winter school. You click on that branch. You get taken to that branch. And then at the bottom of it, you can search for CDCL. And you'll see that this is the one that you need to copy paste into a file called ACNF. You have to copy paste this thing here into a file called CDCLT. And then you just need to run this command here. And every time you change your Python file, you just run this command again and something will happen. As you could see, I mean, I could just edit the CDCL Python file and I don't know, say mat is, I mean an easy one would be saying mat is init finish. I save it, I run it again. And suddenly it will say mat is init finish. So you see here. So you can change it, run it again and run it again and keep on running it until you get what you want. And hopefully the Satsuo will give you all the errors that if you do something wrong, of course, the Satsuo should be detecting it. Because if you return something illegal, then the Satsuo will be like, what are you doing? You're not supposed to do that. But I mean, error checking is always very difficult. People tend to push the limits of error checking. But if you return the right thing, it will do the right thing. If you return the wrong thing, hopefully it will give you a meaningful message. Why? Why there's an error? So for example, if I do the CDCL Tpy and I don't adhere to the regulations and I return something like four, which I'm not supposed to, then hopefully it will tell you don't do that. Like, something is wrong. So you're supposed to return here zero, for example. And then it will not complain. But of course the solution is wrong because this is not satisfiable. This is an unsatisfiable problem. So that's it. Download Docker and then run this, go to this link, and then you can find some description of what you're supposed to do and how you're supposed to do it. Good luck. And I'll be sort of obviously going around and try to help you. And then at the end, I'll show you the correct solution. Hopefully I can like walk you through it. It's quite a lot of fun, I think. And also, like obviously you can implement anything into this, not just cardinated constraints. If you want to, you could actually do Gauss-Georgian relation if you are into that sort of thing. But let's stick to cardinated constraints for a moment and then obviously this can be used for anything. Yeah, so good luck. And then let me know if you need any help. Hi everyone. Yes, so I think I just gonna take the time to explain a little bit, like the kind of solution that, one solution that is possible to do this. Actually, I didn't also implement all the way everything that is possible. You will see my solution being partially incomplete. I hope you had a good time. Hands up if you actually managed to run it. Like I'm not in the sense of like doing the conflict or anything like that, but you actually managed to do the Python and you know, run the Docker and it actually ran. Like you didn't have to solve the problem, but you actually managed to like play with it. That's actually quite a lot of people. So you all played with all this, yeah, I saw quite a lot of you playing with it. So I mean, I think that's, I would consider that already a success actually, because usually it's very difficult to get everything right and especially with C, C++ code, it would have been, it would have taken you two, three hours just to get the compilation right. And you would have not had any chance of, so who actually managed to get an unsatisfiability at the end? I'm just curious. Oh, actually quite a lot of people. Wow, okay. And I know that some people have attempted doing propagation as well, right? So who has managed to like attempt to do propagation? Whoa, whoa, whoa. Okay, that's very good. I think that's very good because propagation I think is very hard actually. The thing is very hard. So I'm gonna present one solution because there are multiple solutions to this problem and obviously some are faster and slower and whatnot. Just take into account, by the way, I don't know if you noticed, but this is like when you run the Python program, you actually get a full set of assignments, right? So you all work the full set of assignments. And so you didn't have this thing that I was talking about with the state that you have to keep and the delta that you keep on getting, right? So you didn't get this delta like, hey, we assign a new variable, hey, we assign unassigned some variable. So you didn't do this delta every time you checked the whole thing. So it's relatively slow, but I mean, of course this is significantly faster still than if you had to do, for example, Gaussian relation inside any SAT solver would be extremely slow, like it would never work. And with this, it would be kind of slow, like compared to something like crypto-minisad that has it in C++ or the delta and all the bells and whistles. And you always return a reason for every propagation, for example. You remember that crypto-minisad does lazy propagation where you don't always return it, you just return a placeholder and then you compute it if you need to. But now you got to understand how this reason close works and how propagation, maybe you talked about how propagation could work as well. So I'm gonna show you just one solution. I thought actually that it would wanna be harder, but I'm surprised how many people cracked it. It's very satisfying to see, I have to say. So I'm just gonna quickly go through a solution. So here's one solution to the problem. Maybe it's gonna be interesting to you, maybe it won't be. So the beginning is obviously the same as before. And I print all the things that I just reprinted together. And now I'm gonna see, go through every single card in the constraint, in the left-hand side, right-hand side. I'm gonna, obviously, I do quite a lot of printing. So I print like, hey, I'm examining this constraint that whatever is less than whatever else. And then I say, well, if the variable is assigned, then I'm going to find out if it's negated or not. And I'm going to put only the falsified values into the reason. So I'm creating this reason here, okay? With all the falsified literals in there. And now I'm going to check, okay, if it's unassigned, then potentially could propagate this literal, right? So it's potential that there's a potential for us to propagate this literal. Not sure, but there's a potential for us to propagate it. And now we're gonna calculate the current value of this cardinality constraint. So you remember that while the current value is, sorry, the current value is set to zero, and we're gonna keep on incrementing it. So if it is, then, like if it's positive, then we add that. If we're negative, we add that. So we update the current value. And now we know what is the value and what is the right-hand side, right? And we have the reason, the list of reason literals, right? So we have the reason literals here, and we have the potential things that we propagate. Notice that I only go through the literals once, right? And I calculate immediately the reason and the possibly propagating this. Actually I've seen that in some advanced implementations that some, I think that I have seen, but so this is one way of doing it. And then if it's larger than the right-hand side, then obviously something is off, and I'm gonna say, okay, this is a conflict, and I'm just gonna return the reason, right? So this is the reason, and I return the reason, that's it. And if it is equal, right? Now we're in this place, right? So the propagation is the following. I didn't explain this because I didn't even think anybody would get there, to be honest. I mean, I should have had higher hopes for all of you. It took me longer than all of you to do it, so I think that should tell you quite a lot. Let's say that it's something like A plus B plus C plus D is smaller than equal to one, okay? Actually we can do something like smaller than equal to two, okay? And we say A is equal to one and B is equal to one. Well, what does this tell me? Well, it tells me that C and D must be zero. There's no way that they can be any other value, right? If C is one, then this is not gonna hold because then it's gonna be three, right? So this implies that C is zero. And furthermore, it also means that D must be zero, right? So now I need to return two propagating clauses. One that says not C or not A or not B and not D or not A or not B, right? And then the solver will take care of the rest. We say, okay, well, these two are falsified and each of them imply these literals and things will move on. So this is what we want to do and this is exactly what we will do. So here, if it's equal, then I'm gonna create, here the propagating clauses, the propagating reasons. And I'm just gonna say it well, the propagating reason is the potential literal that needs to be propagated plus the reason, right? So I mean, plus in this case is just appending or extending the Pythonism to extend this list with the reason list. And then that's it. And we add this to the list of propagations and then we return it. So here, we're good. And that's it, done. So it's, I mean, it's relatively compact, of course. I had obviously more time and less pressure than for you to write it. But actually if you think about it, it's super easy. Like it's what, 40 lines of code with like probably 15 lines of comments. So not that difficult. And I think if anything you take away from here, if you take anything away from here, is that these theory systems are actually quite compact and quite easy to write. And I think quite a lot of fun. As you can see, you can express relatively complex constraints. Like at most K, at most K cognitive constraints, there are entire books written about how to do this thing. And you basically did it in for like 10, 15 lines of code or maybe 20. So what I'm trying to say is that of course, those books are written for a good reason that these people are not wasting their time writing books for no good reason. But this is one way of doing it. And if you have very complicated constraints, then this can actually help you solve a problem that is made up of a large chunk of CNF and a small chunk of your complicated constraint. But you would need to do this more efficiently because currently as you saw, you get the full assignment stack and normally what you would need to do is have a state and you keep on updating this state with the delta updates that you get from the solver. So instead of getting a full set of assignments, you had this propagate assignments, right? So that was the trick. You had this full set of assignments here. And that's not the case normally. What you would normally have is have a state and just set updates. Basically you get a list of updates. And then you have to deal with it. And then you're back to the place where I was and when I was talking where you have to have this relatively complicated state updates on your internal data structures to keep on making sure that you are consistent and you can always propagate and you can always conflict and you can do it fast. Because linearly going through all the constraints may be a little tricky, right? But I mean here we only have four constraints so it's not a big deal. But if you have like 10,000 constraints then this is gonna be very, very expensive as you might imagine. But sometimes all you need is one. So there are some special cases where there's exactly one constraint that is really, really hard to express in CNF and you're like, okay, I'm gonna express it in Python, in a few lines of code. And then write everything else, all the other 10,000 or million constraints in CNF and then make the two work together in this sandwich or back and forth, ping pong, whatever you wanna call it. And I mean that sort of concludes it. I have, Kudip wanted to show me some practical example of how this kind of stuff works. I can do something but give me a minute and then I'll show you this thing. So what this is going to do is basically run our tool that Kudip and I have developed. And the trick about this is that it's going to keep on adding tons and tons of X source and it will still work. So we run this thing, right. So this thing finished in 0.05 seconds and it gave me the number of solutions and we do this by adding X source constraints over the CNF in a repeated fashion. And running this without proper X or reasoning, let me try, I'll have to hack the hell out of this, but let's see if I can do this online. Not sure but we'll get there. I'm not horrible at it but I'm always a bit afraid when it comes to hacking in front of everyone. But maybe it will work. Basically I just showed you how it works when Gaussian relation is inside and now I'm building without Gaussian relation. And obviously this is supposed to be a ton slower. Actually I don't think it will ever terminate so my guess it will never actually finish. It would be very strange if it did but we'll see. It's fine, it'll run, let's see what happens. So I actually don't need this. All right, so this is obviously the error that is like the idiot proof error because people will run this thing and will realize that nothing is working and then they will be very confused about it. And it turns out that if you don't have that thing inside then people are, they still want to use it and okay, so that still work but it's twice the time. Now, let's see if we get something nicer. Okay, this is a good one. So you see that it's struggling to do what it's supposed to be doing. I mean now it's just there. Actually let me see something a little more interesting maybe. Okay, slight issue. So now it's like super slow. You see that you have 32 X-ORs in there and now it's dying. And now if I build this with gaussian relation inside, so just remember this is how far it went and it was just struggling. So now if I run it with gaussian relation inside, you get this. Okay, we're at 128 at this point. In one sixth the time. So I mean this will actually finish I believe but I don't really need to deal with it. Point is that the difference is quite big. I would like to see actually one that solves one way and doesn't solve the other way. So I'm just gonna quickly do that. I want a good example that is kind of interesting one way or the other way. Okay, so now it's like 358 hashes active. You see that it took us zero to three seconds and without it just one moment and I'll let you go. So I know I'm keeping you longer than I should be. Right, so we went to 358 in zero to three seconds and now we're at 16 and we're stuck. Okay, 32 at three seconds I think we're done. So it doesn't go any further which is, I mean the difference is, yeah, I'm not gonna explain. Like this is, the other one is 10 times, like 10 times more in one sixth of time and this is completely stuck at this point. It will never get anywhere. It's exponential so of course with 64, I don't think it will ever get to 64. So that's, like that's the divide. Once you have the CDS CLT in there, you get this thing in milliseconds and if you don't, this thing is just stuck trying to do something that the other thing do then. I mean, we got to 32. So here we are at 32 in zero to zero seconds, right? And this thing is at three seconds at this point and I mean it's stuck, right? So it will never get any further because 64 is exponentially larger and this is twice, so it will never get any further. That's it. So it's completely stuck. And if you actually implemented this thing that we did in Python, into the Gaussian relation, just the same stuff that you did, it would actually continue. Like it would actually run. Like it wouldn't be very, very fast. Of course, because Python isn't that fast but it would be much faster than this. Yeah, so that's it. Thanks for participating. It was quite a lot of fun actually. Okay. So I always think I'm giving a, their long tutorial about a tool that you work on is inviting someone to your house. And if you invited someone, you know that that requires a lot of work in cleaning up your house and making sure it's presentable. Mate has been working on this I'm aware for last few weeks. So we should really thank Mate for a really interesting five hour long tutorial about teaching a lot about the CDCL, CDCLT and all. Mate is going to be around for tomorrow also. So I hope you'll get, you'll find time to ask questions the rest of the time. So let's thank Mate once again.