So welcome to the reference tutorial on Option Types. So what are option types? Well, many models involve decision that are only meaningful if other decisions are made in a particular way. So for example, [INAUDIBLE] configuration problem, I decided to buy rack-205e, and if that's the case, I need to decide the number of internal slots,. Which are between two and five If I buy a different kind of rack I might need to, I may have no internal slots. There's no decision about internal slots. So this decision about the number of individual slots that I need, that only makes sense if I actually choose a configuration with a rack-205e. So what we ought to be able to do is represent these optional decisions so this decision about the number of internal slots is optional. It only makes sense In the case that I make another decision. And in particular we want to make sure that if these optional decisions aren't meaningful, if they don't have any meaning. Then they can't constrain any other part of the problem and that's for what Minizinc uses option types. And you may have met option types in your error messages, wondering where are these option types coming from. We'll talk about how option types are also used to make music more expressive. Here's an example of where we might want to use option types. We've got N workers and two M tasks designed in two rows. One is M and M+1 to two M and we need to assign workers to task to maximize profits, this is just a straight assignment problem as a visual. And the only constraint is that workers assigned to two adjacent tasks have to be compatible. So here we have our profit array, our compatibility between pairs of workers, decisions we need to make for each worker, what task does he work on. We obviously constraint that every worker works on a different task and here's our objective which is just summing up the [INAUDIBLE]. But how do we model the compatibility constraint? So the obvious way to do it is use an implication, if two workers are adjacent then they must be compatible. So basically, we look over all pairs of workers, and we If the task that worker two works on is one more than the task that worker one works on. And the task worker one works on is not the nth task because remember task m and task m plus one are not adjacent because they're in different rows. Then we have to ensure the two workers are compatible, so that is perfectly fine, that is a great model for the problem. But it does generate a large number of very weak constraints. Basically we have a number for every pair of workers we have one called constraints to make sure that the constraint holds. So what we'd rather do is basically invert the task function. If we had our worker function which told us for each task what worker works on it, then it'd be very easy to write down that constraint. But the problem is it's not so we can't inverse the task function, the inverse is actually a partial function. So we need to map each task to a worker or to the possibility that there's no worker working on that task because we don't have a projection. And what option types do is add this extra value which I'll call opt, which is the less than, greater than sign to a type. And now that's going to allow us to invert the task functions, so we're going to have a decision. So for each task which is the worker that works on the task or it might be this function value, which meaning no worker works on that task. And then, we can invert this task array to get this worker right. Note, this is not exactly the same inverse we've seen before, which only worked for bijections. Now, with the option values we need to make sure that either the task worked on, by worker w is the work that he works on tasks. The same task, or there's no such work. Right [INAUDIBLE] construct, so if we had that, we can model compatibility much more direct. So now we can just say, for every task in 1 to 2 times n- 1, except for the one where t is n. The worker who works on that task and the worker who works on the task which is one further along have to be comparable all right? And the important point about how this structure work is if one of these workers doesn't exist they opt. Then we want to let the constraint hold because that's saying this is a meaningless variable. Worker on task T is a meaningless variable, doesn't make any sense, so we don't want to cause failure. We can't constrain something which doesn't exist. So option types basically extend the base types by adding this extra value opt, so you've got optional integers and floats and bools. And the way we can think of them is optional type variables act like the normal variable if they take a value different from opt. And they act as if they weren't part of a constraint if they take the value opt, so an example of that is we look at this. All different, well, it's all different constraints. Clearly, false because as 2 varies which take the value so that it's same value. But that's not how we want to consider it, we want to consider that this constraint holds because if we ignore the values, we'd see all different. 3, 6, 1, 8, 7, 5, and that would actually hold, so we want to think about these opt phases not actually existing. And we have to be careful about how they act in expressions, are they just constraints? So when I have opt + 3, I want to consider that the same as 3 because 0 is that left identity for plus so is left identity [INAUDIBLE] three. Similarly, 2 minus is going to give me 2 because 0 is a right identity for. And often times be 1 because 1 is a left and right, so if there's no identity for that position, then the, the opt value property just goes upwards. So opt minus two gives you opt because there's no left identity for a subtraction and opt divided by four gives you opt, similarly. If you end up option types in user-defined groups and functions, then you are going to need to define their behavior. So, why it's important to learn about option types, because you're already using them. So, I'm going to show you where they're hidden and how you can avoid them. So, any time you iterate over variable sets, you're actually implicitly using option types. So this expression here, the sum(i in 1..n) so this x is a variable set. Is actually for this. It says we're going to iterate all the possible ways this variable set could take. All the fixed possible ways, right? And if i is in x, then we're going to add up the size. Otherwise, we're going to get returned by the. So we're going to add the size, or we're going to add And of course adding up acts like zero so this ends up just summing up the sizes for the things which are in set x. Similarly, the same thing happens if I have a variable where clause. So here the where clause, since x is a variable, I don't know if this holds or not. In fact, this is exactly the same expression as before just [INAUDIBLE] is identical to what we saw before. All right, we want to sum up only the cases where this constraint holds, so if it holds then we get size y otherwise we get this ub value. So you can avoid option types by avoiding iterating over variable sets. So just think about whenever you're iterating over a variable set we're going to replace So typically, rather than iterate out of this variable set. We're going to find its upper bound over that, so it's going to go over all the possibly ways it could be in x. We only want to add the ones where i is in x. So this expression here will evaluate to one if i is in x, and zero if it's not, which means the size will be [INAUDIBLE] won't be summed up Same way if we have a forall, so forall i [INAUDIBLE] we want this constraint to hold. Well, actually it's the same, for any i which could be an x if i is an x we want the constraint to hold. [INAUDIBLE] to do the same thing and similarly exists i in x where this constraint holds. We want to find some i in the other so this is a fixed set. We have both i is is actually an x and this constraint holds. The same thing happens when using your clauses, so here, we're summing up all the sizes where i is greater than x. We can just use this alternate expression to calculate the ones where i is greater than x and then we have this i where it's not. Then we're going to get zero so the sum won't include. And simply for the forall we just make this i greater to x in here and in quotation which is [INAUDIBLE] constrained to hold only in i is greater than x. And it similarly, here exists we want for when i is [INAUDIBLE] for x so x is a variable again. We want to find an x in the set where i is [INAUDIBLE] than x and the size of i is [INAUDIBLE] which is exactly the same statement with no optional types. So let's look at some more complicated cases. So we can do the same for max and min but it's a bit more complicated. So here we're trying to calculate a minimum for some i in a variable of the size of Pi and the sizes themselves may be variables. So what we need to build this is, first of all, find some value which is larger than any possible legitimate value that this expression can take. So we can do that by saying, well let's take the maximum of any i which could be an upper value a of the upper bound of that expression, and then we'll add 1. So this number is larger than any possible value that could be in this sector. So we know that n will always take a value less than that if it takes a value at all. Once we've done that, we need to write over all values in the upper bound of x so that's a fixed set If i isin x then we get its size. Otherwise, we get this larger value and that means that the mean will never pick this larger value. So if there is some legitimate value of size, some i in x and this size of i will be smaller and it'll be the mean chosen for m. So this would work all the time except for the one case where actually x is empty. In which case the min actually fails and where as this will return m with a value of larger. But you can test for that in in your if m takes a value which is larger, which is equal to larger or greater than, is clearly not a correct mean, and you should maybe do the same thing as this fail. But normally, when we're taking these min expression we dont expect them to fail. Another more complicated case is for this we're doing an alldifferent(y(i)) for all is in this variable set x. So we can just have an all different build on option types in our library, it's not likely to be native. Most constraint folders won't be handling that, but we can avoid hidden option types by written code another way. So here, we're encoding exactly the same thing, except been using this bool2int expression here to convert all the y i values into 0s, all right? Now since all the for y take which are one to m, we know that any 0 value which we get in this list actually doesn't represent anything, it's option value. It's I was not i was not in x and so we can use all to get 0 to get the same [INAUDIBLE], right? All the they won't be 0. They have to all be different and for all the ways where i is not [INAUDIBLE] will get a 0 and then that's fine because [INAUDIBLE] 0. So in summarizing, there are many problems that involve decisions that only make sense of are first and option types provide a concise way of expressing that. And the reason why you definitely want to learn about them, at least to avoid them, is that whenever you arrive the creation of a variable or that includes have a variable clause. And option types are used and normally, it will silently perform as intended. But if you're getting confused by error messages, then we suggest that you replace those iterations to avoid option types all together that brings us to the end of the section.