Minizinc basic understanding of arrays and booleans - constraints

After running through the tutorials, thinking I got the concepts, I set about creating my own model and immediately ran into problems. Better to get stuck in asap to realise just how little you actually know, imo.
In this example I would simply like to get an output where classes consist of students that want them, i.e. true, as represented by my array (not every student is able to attend on every day).
There could be all sorts of badness in the way the model was written...
Needless to say, I get the error WARNING: model inconsistency detected
enum Students = { Mark, Bart, Mary, Anne, Sue };
enum Classes = { Mon, Tue, Wed};
array[Students, Classes] of bool: pref =
[| true, true, false,
| false, true, true,
| true, false, true,
| true, false, false,
| false, false, true |];
constraint forall (i in Students, j in Classes)(pref[i,j]=true);
solve satisfy;
output [ " \(pref[Students,Classes]);\n" ]
Bonus would be limiting it so each Student only appears once...
Perfect outcome would be something like a list of all the combinations where students preferences are satisfied and they are in 1 class.
[Mark, Anne | Bart | Mary, Sue]
Thank you for helping me along my way!

The vital part that you might not understand is that MiniZinc is a declarative language. You do not tell it how to solve a problem, but merely specify the problem and let the language do the rest.
A MiniZinc model is specified in terms of
variables: decisions that need to be made / things you want to know
parameters: things you already know
constraints: the rules that are enforced between any or all variables and parameters.
In your model you didn't specify any variables, merely parameters and constraints. It is said to be inconsistent because you give it an array pref that contains both true and false, but then your constraint enforces that every element in the array must be true.
Likely you meant to make pref your set of variables and meant that your constraint should force one preference for every student:
enum Students = { Mark, Bart, Mary, Anne, Sue };
enum Classes = { Mon, Tue, Wed};
array[Students, Classes] of var bool: pref;
constraint forall (i in Students)(
count(j in Classes) (pref[i, j]) = 1
);
solve satisfy;
output [ "pref = ", show2d(pref), ";" ];
If you only want each student to have at least one preference you can use exists instead:
enum Students = { Mark, Bart, Mary, Anne, Sue };
enum Classes = { Mon, Tue, Wed};
array[Students, Classes] of var bool: pref;
constraint forall (i in Students)(
exists(j in Classes) (pref[i, j])
);
solve satisfy;
output [ "pref = ", show2d(pref), ";" ];
This would work, but if you know, as is the case in the first solution, that the students only make one preference, then it is better to just enforce this as part of the variable type:
enum Students = { Mark, Bart, Mary, Anne, Sue };
enum Classes = { Mon, Tue, Wed};
array[Students] of var Classes: pref;
solve satisfy;
output [ "pref = ", show(pref), ";" ];
Then no constraint is required to ensure a student has exactly one preference.

Related

Declare two fields of a struct as mutually exclusive in CueLang?

I want to ensure that my users only set one of two fields:
rotations:
- type: weekly
time_restrictions:
# Allow only ONE of the following fields:
weekday_time_of_day: {...}
time_of_day: [...]
I came across the OneOf pattern on Cuetorials, but this does only seem to help when wanting to enforce a schema while writing cue files.
#OneOfTimeRestrictions: {time_of_day: [...string]} | { weekday_time_of_day: {...string} }
rotations: [{
type: *"weekly" | "daily"
restrictions: #oneOf_timerestrictions | {} # won't work, naturally, because nothing is "chosen"
}]
(the the values of the mutually exclusive fields are actually additional, more complex structs, not strings, in case that might matter - but for the sake of a shorter example I've omitted them).
However, I'm trying to vet YAML instead.
The problem is that when defining this:
#OneOfTimeRestrictions:
rotations: [{
type: *"weekly" | "daily"
restrictions: {time_of_day: [...string]} | { weekday_time_of_day: {...string} }
}]
Both fields are acceptable, including when giving them at the same time.
Pointers?

"exponentially large number of cases" errors in latest Flow with common spread pattern

I frequently use the following pattern to create objects with null/undefined properties omitted:
const whatever = {
something: true,
...(a ? { a } : null),
...(b ? { b } : null),
};
As of flow release v0.112, this leads to the error message:
Computing object literal [1] may lead to an exponentially large number of cases to reason about because conditional [2] and conditional [3] are both unions. Please use at most one union type per spread to simplify reasoning about the spread result. You may be able to get rid of a union by specifying a more general type that captures all of the branches of the union.
It sounds to me like this isn't really a type error, just that Flow is trying to avoid some heavier computation. This has led to dozens of flow errors in my project that I need to address somehow. Is there some elegant way to provide better type information for these? I'd prefer not to modify the logic of the code, I believe that it works the way that I need it to (unless someone has a more elegant solution here as well). Asking here before I resort to // $FlowFixMe for all of these.
Complete example on Try Flow
It's not as elegant to write, and I think Flow should handle the case that you've shown, but if you still want Flow to type check it you could try rewriting it like this:
/* #flow */
type A = {
cat: number,
};
type B = {
dog: string,
}
type Built = {
something: boolean,
a?: A,
b?: B,
};
function buildObj(a?: ?A, b?: ?B): Built {
const ret: Built = {
something: true
};
if(a) ret.a = a
if(b) ret.b = b
return ret;
}
Try Flow

Recursive type definition in flow

I'm trying to use flow 0.53.1. Could you please help me explain this weird behavior?
This code sample:
/* #flow */
type AnySupportedType =
| AnySupportedPrimitive
| AnySupportedObject
| AnySupportedArray;
type AnySupportedArray = Array<AnySupportedType>;
type AnySupportedObject = { [string]: AnySupportedType };
type AnySupportedPrimitive = boolean | number | string | void;
type DataID = string
type Data = {
id: DataID
}
const y: Data = { id: "123" }
const x: AnySupportedType = y;
Renders this error:
17: const x: AnySupportedType = y;
^ object type. This type is incompatible with
17: const x: AnySupportedType = y;
^ union: AnySupportedPrimitive | AnySupportedObject | AnySupportedArray
Link to flow.org web-based example to play with.
Actually, this has to do with mutability. Flow cannot allow this code, since you could write x.id = 5 (after the appropriate type refinements), since the AnySupportedType type allows you to set any supported type, including a number as a property.
To solve this, you need to make the object properties covariant, effectively making them read-only:
type AnySupportedObject = { +[string]: AnySupportedType };
Note the addition of the +.
Once you do this, Flow allows the original assignment but prevents you from setting properties on x.
Check out the complete example on try.
See https://flow.org/blog/2016/10/04/Property-Variance/
The answer is that Flow has two ways to type Objects. One, your AnySupportedObject, treats the object as as dictionary where you can find an item by any key (similar to Map<string, whatever>.
The other way is as a record, where there are a specific set of known keys and each key can point to its own type of value (for example, {a: number, b: string}.
Those two types have very different meanings, though often either one can apply to a specific object. The type system keeps them distinct and forces you to treat an object in one way or the other to avoid generating type errors.

Mapping a given value to an action depending on certain characteristics

Suppose I have a certain value, and I want to do something with it depending on certain characteristics it might have.
For example, suppose the value is a string, and I want to print it to the screen if it starts with the letter L, save it to a file if it's length is less than 20 characters, and play a sound if the last character is the same as the first one.
One option of course is a simple if else if construct:
if (value[0] == 'L')
....
else if (value.Length < 20)
....
else if (value[0] == value.Last())
....
However with a lot of conditions, this can get ugly really fast. So the other option is a Dictionary. However I'm not sure how I can use a Dictionary to achieve this.
How can this be done?
You can construct a dictionary that contains conditions and actions that should be performed if a condition is met. In general, if you need to work with type T, this dictionary will have a type Dictionary<Predicate<T>, Action<T>>. For a string it can be:
var conditions = new Dictionary<Predicate<string>, Action<string>>
{
{s => s.StartsWith("L"), s => Console.WriteLine("Starts with L")},
{s => s.Length < 20, s => Console.WriteLine("Has fewer that 20 symbols")},
};
string input = "some input";
foreach (var condition in conditions)
{
if (condition.Key(input)) condition.Value(input);
}
In fact, you don't even need a Dictionary here - you can use List<Tuple<Predicate<string>, Action<string>>>, or, even better - to introduce a simple small class that contains a predicate and an action.

Recursive records in F#

A friend and I are reading up on F# and are messing around with records at the moment.
We have made the following record for representing a person:
type Person =
{name: string;
father: Person;
mother: Person;}
F# Interactive accepts it, and in some way, the type makes sense, except we can't see how to use it. When we try to declare a person, we have to declare the parents at the point of declaration, and in turn declare their parents and so on. Is there any way to actually use this type? And if not, how come we are even able create it?
PS: We are well aware that since parents are intended to be optional, we should have encapsulated them with the option (Some x | None) type.
EDIT
My question is not how to fix the above, a solution is already written in the PS.
My question is, can I actually use the above type, e.g. declare a Person record of the above form? If not, I must have made an unusable type. Why can I make such a type?
Lee shows a more useful definition, but you can create an instance of your Person type:
let rec loopy = { name = "loopy"; father = loopy; mother = loopy }
or
let rec male = { name = "male"; father = male; mother = female }
and female = { name = "female"; father = male; mother = female}
Of course, these aren't at all helpful if you're modeling real people, but the compiler doesn't know that. A similar recursive type could be useful if you're trying to define a cycle, for instance.
If you declare father and mother as Parent option then you can use it like:
let f = { name = "Father"; father = None; mother = None }
let m = { name = "Mother"; father = None; mother = None }
let c = { name = "Child"; father = Some(f); mother = Some(m) }
without using Parent option for father and mother you would have to create a "null parent" instance and use that instead of None.

Resources