Andreas Launila wrote: > James Edward Gray II wrote: >> On Jun 6, 2007, at 5:21 AM, Andreas Launila wrote: >>> As an example there's a domain >>> constraint which basically says that x must be in a given range. >>> Negating the constraint is possible and might be written as follows. >>> >>> constrain x.in(1..17) >>> constrain x.not_in(1..17) >> This seems like a very viable solution to me. If it's possible to just >> negate all of the tests, that should work: >> >> equal/not_equal >> in/not_in >> includes/does_not_include >> > > Yes, that could work. I was probably locking myself in a bit too much > trying to make everything read as must/must_not. I will sketch how other > constraints could be expressed on a similar form to see if there are any > consistency problems. > If I understood the suggestion of the syntax correctly then constraints would basically be given on the form "constrain variable.predicate(argument)" when variable is a single (finite-domain) variable and "constrain function(variable).predicate(argument)" when variable is something enumerable. I have written down some examples of how constraints could look with that syntax at http://gecoder.lokorin.org/dev/wiki/Syntax_test . There are some constraints there which I couldn't get especially readable or self-evident. I will go through them below. == Element constraints == This is basically the array access of constraints. It takes an array of constant integers, selects the i:th one where i is decided by a variable, and constrains that variable to be equal to another variable. This can typically be used to convert e.g. an identifier to a quantity of some sort, for instance the price of a fruit. A short example: fruit_selection = IntVar.new(0..3) # We can pick one of four fruits. prices = [45, 60, 764, 45] # The prices of each fruit. price_to_pay = IntVar.new((prices.min)..(prices.max)) constrain prices[fruit_selection].equal(price_to_pay) constrain price_to_pay > 500 The above example will force fruit_selection to equal 2 (no branching required) since it's the only fruit with a price > 500. I would imagine the above syntax of "constrain array[x].equal(y)" to be easily understandable, but it would require modification to Enumerable to define/wrap []. Something more on the form of the rest of the syntax would probably be constrain element(array, x).equal(y) It just doesn't read as well to me. Maybe there's a better way of representing constraints where the function has to take multiple arguments, such as returning an helper with only one method, i.e. as follows. constrain element(x).in(array).equal(y) == Channel constraints == This is a constraint that I have little idea of how to produce something readable for. The constraint links two enumerables with variables to each other so that the xs_i = j <=> ys_j = i forall i where xs and ys are enumerables. It's used to represent a model from two different viewpoints. Lets say that you have a problem involving a sequence of length n with numbers in 0..(n-1) that all have to be distinct (for instance magic sequence). Naturally you might model this as an array where element i is the value at position i (so if you print the array you get the actual sequence). You could also model it as an array where element i is the position of value i in the sequence. These are two different viewpoints of the same problem. Below what the two arrays might contain when the problem is solved. First viewpoint: xs = [2,0,1,3] (the actual sequence) Second viewpoint: ys = [2,1,0,3] (the positions of the different numbers, e.g. the position of 0 in xs is 2, hence ys[0] == 2) The important part is that some constraints might be easier to model using the first viewpoint and others might be easier in the second one. The channel constraint is used to give the person modeling access to both viewpoints at the same time. The second viewpoint can be constructed from the first one by using the channel constraint. The best syntax I can think of for it is. constrain channel(xs, ys) That is probably because I can't think of any common concept that conveys the intention in a few words. == Sort constraints == There's a special form of sort constraint that operates on three enumerables: xs, ys and zs. What it does is that it constrains e.g. xs to be ys sorted using the positions specified in zs. Once again it's the problem of conveying a function with multiple arguments. Using the suggestion for element constraints this could become something like constrain sort(xs).with_indices(zs).equal(ys) I'm not sure how readable that is. == Cardinality constraints == This is a fairly straightforward constraint, it counts the number of occurrences in an array. For instance I might specify that an array of variables must contain 3 instances of 5 (3 and 5 can also be replaced by variables). Again it's multiple arguments for a function. Maybe it's more readable as the following. constrain number_of(y).in(xs).equal(z) == Beyond == There are more constraints to worry about, but the ones in the syntax test page represents the commonly used ones for finite domain integers and booleans. Hence it's probably best to hammer out a good syntax for them and then adapt it for the other constraints and set variables. -- Andreas Launila