190 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			190 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | USING THE GECODE MODULE | ||
|  | ======================= | ||
|  | 
 | ||
|  | :- use_module(library(gecode)). | ||
|  | 
 | ||
|  | 
 | ||
|  | CREATING A SPACE | ||
|  | ================ | ||
|  | 
 | ||
|  |     Space := space | ||
|  | 
 | ||
|  | CREATING VARIABLES | ||
|  | ================== | ||
|  | 
 | ||
|  | Unlike in Gecode, variable objects are not bound to a specific Space.  Each one | ||
|  | actually contains an index with which it is possible to access a Space-bound | ||
|  | Gecode variable.  Variables can be created using the following expressions: | ||
|  | 
 | ||
|  |    IVar := intvar(Space,SPEC...) | ||
|  |    BVar := boolvar(Space) | ||
|  |    SVar := setvar(Space,SPEC...) | ||
|  | 
 | ||
|  | where SPEC... is the same as in Gecode.  For creating lists of variables use | ||
|  | the following variants: | ||
|  | 
 | ||
|  |    IVars := intvars(Space,N,SPEC...) | ||
|  |    BVars := boolvars(Space,N,SPEC...) | ||
|  |    SVars := setvars(Space,N,SPEC...) | ||
|  | 
 | ||
|  | where N is the number of variables to create (just like for XXXVarArray in | ||
|  | Gecode).  Sometimes an IntSet is necessary: | ||
|  | 
 | ||
|  |    ISet := intset([SPEC...]) | ||
|  | 
 | ||
|  | where each SPEC is either an integer or a pair (I,J) of integers.  An IntSet | ||
|  | describes a set of ints by providing either intervals, or integers (which stand | ||
|  | for an interval of themselves).  It might be tempting to simply represent an | ||
|  | IntSet as a list of specs, but this would be ambiguous with IntArgs which, | ||
|  | here, are represented as lists of ints. | ||
|  | 
 | ||
|  |    Space += keep(Var) | ||
|  |    Space += keep(Vars) | ||
|  | 
 | ||
|  | Variables can be marked as "kept".  In this case, only such variables will be | ||
|  | explicitly copied during search.  This could bring substantial benefits in | ||
|  | memory usage.  Of course, in a solution, you can then only look at variables | ||
|  | that have been "kept".  If no variable is marked as "kept", then they are all | ||
|  | kept.  Thus marking variables as "kept" is purely an optimization. | ||
|  | 
 | ||
|  | 
 | ||
|  | CONSTRAINTS AND BRANCHINGS | ||
|  | ========================== | ||
|  | 
 | ||
|  | all constraint and branching posting functions are available just like in | ||
|  | Gecode.  Wherever a XXXArgs or YYYSharedArray is expected, simply use a list. | ||
|  | At present, there is no support for minimodel-like constraint posting. | ||
|  | Constraints and branchings are added to a space using: | ||
|  | 
 | ||
|  |     Space += CONSTRAINT | ||
|  |     Space += BRANCHING | ||
|  | 
 | ||
|  | For example: | ||
|  | 
 | ||
|  |     Space += rel(X,'IRT_EQ',Y) | ||
|  | 
 | ||
|  | arrays of variables are represented by lists of variables, and constants are | ||
|  | represented by atoms with the same name as the Gecode constant | ||
|  | (e.g. 'INT_VAR_SIZE_MIN'). | ||
|  | 
 | ||
|  | SEARCHING FOR SOLUTIONS | ||
|  | ======================= | ||
|  | 
 | ||
|  |     SolSpace := search(Space) | ||
|  | 
 | ||
|  | This is a backtrackable predicate that enumerates all solution spaces | ||
|  | (SolSpace).  It may also take options: | ||
|  | 
 | ||
|  |     SolSpace := search(Space,Options) | ||
|  | 
 | ||
|  | Options is a list whose elements maybe: | ||
|  | 
 | ||
|  | restart | ||
|  |     to select the Restart search engine | ||
|  | threads=N | ||
|  |     to activate the parallel search engine and control the number of | ||
|  |     workers (see Gecode doc) | ||
|  | c_d=N | ||
|  |     to set the commit distance for recomputation | ||
|  | a_d=N | ||
|  |     to set the adaptive distance for recomputation | ||
|  | 
 | ||
|  | EXTRACTING INFO FROM A SOLUTION | ||
|  | =============================== | ||
|  | 
 | ||
|  | An advantage of non Space-bound variables, is that you can use them both to | ||
|  | post constraints in the original space AND to consult their values in | ||
|  | solutions.  Below are methods for looking up information about variables.  Each | ||
|  | of these methods can either take a variable as argument, or a list of | ||
|  | variables, and returns resp. either a value, or a list of values: | ||
|  | 
 | ||
|  |     Val := assigned(Space,X) | ||
|  | 
 | ||
|  |     Val := min(Space,X) | ||
|  |     Val := max(Space,X) | ||
|  |     Val := med(Space,X) | ||
|  |     Val := val(Space,X) | ||
|  |     Val := size(Space,X) | ||
|  |     Val := width(Space,X) | ||
|  |     Val := regret_min(Space,X) | ||
|  |     Val := regret_max(Space,X) | ||
|  | 
 | ||
|  |     Val := glbSize(Space,V) | ||
|  |     Val := lubSize(Space,V) | ||
|  |     Val := unknownSize(Space,V) | ||
|  |     Val := cardMin(Space,V) | ||
|  |     Val := cardMax(Space,V) | ||
|  |     Val := lubMin(Space,V) | ||
|  |     Val := lubMax(Space,V) | ||
|  |     Val := glbMin(Space,V) | ||
|  |     Val := glbMax(Space,V) | ||
|  |     Val := glb_ranges(Space,V) | ||
|  |     Val := lub_ranges(Space,V) | ||
|  |     Val := unknown_ranges(Space,V) | ||
|  |     Val := glb_values(Space,V) | ||
|  |     Val := lub_values(Space,V) | ||
|  |     Val := unknown_values(Space,V) | ||
|  | 
 | ||
|  | DISJUNCTORS | ||
|  | =========== | ||
|  | 
 | ||
|  | Disjunctors provide support for disjunctions of clauses, where each clause is a | ||
|  | conjunction of constraints: | ||
|  | 
 | ||
|  |     C1 or C2 or ... or Cn | ||
|  | 
 | ||
|  | Each clause is executed "speculatively": this means it does not affect the main | ||
|  | space.  When a clause becomes failed, it is discarded.  When only one clause | ||
|  | remains, it is committed: this means that it now affects the main space. | ||
|  | 
 | ||
|  | Example: | ||
|  | 
 | ||
|  | Consider the problem where either X=Y=0 or X=Y+(1 or 2) for variable X and Y | ||
|  | that take values in 0..3. | ||
|  | 
 | ||
|  |     Space := space, | ||
|  |     [X,Y] := intvars(Space,2,0,3), | ||
|  | 
 | ||
|  | First, we must create a disjunctor as a manager for our 2 clauses: | ||
|  | 
 | ||
|  |     Disj := disjunctor(Space), | ||
|  | 
 | ||
|  | We can now create our first clause: | ||
|  | 
 | ||
|  |     C1 := clause(Disj), | ||
|  | 
 | ||
|  | This clause wants to constrain X and Y to 0.  However, since it must be | ||
|  | executed "speculatively", it must operate on new variables X1 and Y1 that | ||
|  | shadow X and Y: | ||
|  | 
 | ||
|  |     [X1,Y1] := intvars(C1,2,0,3), | ||
|  |     C1 += forward([X,Y],[X1,Y1]), | ||
|  | 
 | ||
|  | The forward(...) stipulation indicates which global variable is shadowed by | ||
|  | which clause-local variable.  Now we can post the speculative clause-local | ||
|  | constraints for X=Y=0: | ||
|  | 
 | ||
|  |     C1 += rel(X1,'IRT_EQ',0), | ||
|  |     C1 += rel(Y1,'IRT_EQ',0), | ||
|  | 
 | ||
|  | We now create the second clause which uses X2 and Y2 to shadow X and Y: | ||
|  | 
 | ||
|  |     C2 := clause(Disj), | ||
|  |     [X2,Y2] := intvars(C2,2,0,3), | ||
|  |     C2 += forward([X,Y],[X2,Y2]), | ||
|  | 
 | ||
|  | However, this clause also needs a clause-local variable Z2 taking values 1 or | ||
|  | 2 in order to post the clause-local constraint X2=Y2+Z2: | ||
|  | 
 | ||
|  |     Z2 := intvar(C2,1,2), | ||
|  |     C2 += linear([-1,1,1],[X2,Y2,Z2],'IRT_EQ',0), | ||
|  | 
 | ||
|  | Finally, we can branch and search: | ||
|  | 
 | ||
|  |     Space += branch([X,Y],'INT_VAR_SIZE_MIN','INT_VAL_MIN'), | ||
|  |     SolSpace := search(Space), | ||
|  | 
 | ||
|  | and lookup values of variables in each solution: | ||
|  | 
 | ||
|  |     [X_,Y_] := val(SolSpace,[X,Y]). |