------------------------------------------------------------------------------ --- Library for finite domain constraint solving. ---
--- The general structure of a specification of an FD problem is as follows: --- --- domain_constraint & fd_constraint & labeling --- --- where: --- --- `domain_constraint` --- specifies the possible range of the FD variables (see constraint `domain`) --- --- `fd_constraint` --- specifies the constraint to be satisfied by a valid solution --- (see constraints #+, #-, allDifferent, etc below) --- --- `labeling` --- is a labeling function to search for a concrete solution. --- --- Note: This library is based on the corresponding library of Sicstus-Prolog --- but does not implement the complete functionality of the --- Sicstus-Prolog library. --- However, using the PAKCS interface for external functions, it is relatively --- easy to provide the complete functionality. --- --- @author Michael Hanus --- @version June 2012 --- @category general ------------------------------------------------------------------------------ module CLPFD(domain, (+#), (-#), (*#), (=#), (/=#), (<#), (<=#), (>#), (>=#), Constraint, (#=#), (#/=#), (#<#), (#<=#), (#>#), (#>=#), neg, (#/\#), (#\/#), (#=>#), (#<=>#), solve, sum, scalarProduct, allDifferent, all_different, count, indomain, labeling, LabelingOption(..)) where -- The operator declarations are similar to the standard arithmetic -- and relational operators. infixl 7 *# infixl 6 +#, -# infix 4 =#, /=#, <#, <=#, >#, >=# infix 4 #=#, #/=#, #<#, #<=#, #>#, #>=# infixr 3 #/\# infixr 2 #\/# infixr 1 #=>#, #<=># --- Constraint to specify the domain of all finite domain variables. --- @param xs - list of finite domain variables --- @param min - minimum value for all variables in xs --- @param max - maximum value for all variables in xs domain :: [Int] -> Int -> Int -> Bool domain vs l u = ((prim_domain $!! (ensureSpine vs)) $# l) $# u prim_domain :: [Int] -> Int -> Int -> Bool prim_domain external --- Addition of FD variables. (+#) :: Int -> Int -> Int x +# y = (prim_FD_plus $! y) $! x prim_FD_plus :: Int -> Int -> Int prim_FD_plus external --- Subtraction of FD variables. (-#) :: Int -> Int -> Int x -# y = (prim_FD_minus $! y) $! x prim_FD_minus :: Int -> Int -> Int prim_FD_minus external --- Multiplication of FD variables. (*#) :: Int -> Int -> Int x *# y = (prim_FD_times $! y) $! x prim_FD_times :: Int -> Int -> Int prim_FD_times external --- Equality of FD variables. (=#) :: Int -> Int -> Bool x =# y = (prim_FD_equal $! y) $! x prim_FD_equal :: Int -> Int -> Bool prim_FD_equal external --- Disequality of FD variables. (/=#) :: Int -> Int -> Bool x /=# y = (prim_FD_notequal $! y) $! x prim_FD_notequal :: Int -> Int -> Bool prim_FD_notequal external --- "Less than" constraint on FD variables. (<#) :: Int -> Int -> Bool x <# y = (prim_FD_le $! y) $! x prim_FD_le :: Int -> Int -> Bool prim_FD_le external --- "Less than or equal" constraint on FD variables. (<=#) :: Int -> Int -> Bool x <=# y = (prim_FD_leq $! y) $! x prim_FD_leq :: Int -> Int -> Bool prim_FD_leq external --- "Greater than" constraint on FD variables. (>#) :: Int -> Int -> Bool x ># y = (prim_FD_ge $! y) $! x prim_FD_ge :: Int -> Int -> Bool prim_FD_ge external --- "Greater than or equal" constraint on FD variables. (>=#) :: Int -> Int -> Bool x >=# y = (prim_FD_geq $! y) $! x prim_FD_geq :: Int -> Int -> Bool prim_FD_geq external --------------------------------------------------------------------------- -- Reifyable constraints. --- A datatype to represent reifyable constraints. data Constraint = FDEqual Int Int | FDNotEqual Int Int | FDGreater Int Int | FDGreaterOrEqual Int Int | FDLess Int Int | FDLessOrEqual Int Int | FDNeg Constraint | FDAnd Constraint Constraint | FDOr Constraint Constraint | FDImply Constraint Constraint | FDEquiv Constraint Constraint --- Reifyable equality constraint on FD variables. (#=#) :: Int -> Int -> Constraint x #=# y = FDEqual x y --- Reifyable inequality constraint on FD variables. (#/=#) :: Int -> Int -> Constraint x #/=# y = FDNotEqual x y --- Reifyable "less than" constraint on FD variables. (#<#) :: Int -> Int -> Constraint x #<# y = FDLess x y --- Reifyable "less than or equal" constraint on FD variables. (#<=#) :: Int -> Int -> Constraint x #<=# y = FDLessOrEqual x y --- Reifyable "greater than" constraint on FD variables. (#>#) :: Int -> Int -> Constraint x #># y = FDGreater x y --- Reifyable "greater than or equal" constraint on FD variables. (#>=#) :: Int -> Int -> Constraint x #>=# y = FDGreaterOrEqual x y --- The resulting constraint is satisfied if both argument constraints --- are satisfied. neg :: Constraint -> Constraint neg x = FDNeg x --- The resulting constraint is satisfied if both argument constraints --- are satisfied. (#/\#) :: Constraint -> Constraint -> Constraint x #/\# y = FDAnd x y --- The resulting constraint is satisfied if both argument constraints --- are satisfied. (#\/#) :: Constraint -> Constraint -> Constraint x #\/# y = FDOr x y --- The resulting constraint is satisfied if the first argument constraint --- do not hold or both argument constraints are satisfied. (#=>#) :: Constraint -> Constraint -> Constraint x #=># y = FDImply x y --- The resulting constraint is satisfied if both argument constraint --- are either satisfied and do not hold. (#<=>#) :: Constraint -> Constraint -> Constraint x #<=># y = FDEquiv x y --- Solves a reified constraint. solve :: Constraint -> Bool solve c = prim_solve_reify $!! c prim_solve_reify :: Constraint -> Bool prim_solve_reify external --------------------------------------------------------------------------- -- Complex constraints. --- Relates the sum of FD variables with some integer of FD variable. sum :: [Int] -> (Int -> Int -> Bool) -> Int -> Bool sum vs rel v = seq (normalForm (ensureSpine vs)) (seq (ensureNotFree rel) (seq v (prim_sum vs rel v))) prim_sum :: [Int] -> (Int -> Int -> Bool) -> Int -> Bool prim_sum external --- (scalarProduct cs vs relop v) is satisfied if ((cs*vs) relop v) is satisfied. --- The first argument must be a list of integers. The other arguments are as --- in `sum`. scalarProduct :: [Int] -> [Int] -> (Int -> Int -> Bool) -> Int -> Bool scalarProduct cs vs rel v = seq (groundNormalForm cs) (seq (normalForm (ensureSpine vs)) (seq (ensureNotFree rel) (seq v (prim_scalarProduct cs vs rel v)))) prim_scalarProduct :: [Int] -> [Int] -> (Int -> Int -> Bool) -> Int -> Bool prim_scalarProduct external --- (count v vs relop c) is satisfied if (n relop c), where n is the number of --- elements in the list of FD variables vs that are equal to v, is satisfied. --- The first argument must be an integer. The other arguments are as --- in `sum`. count :: Int -> [Int] -> (Int -> Int -> Bool) -> Int -> Bool count v vs rel c = seq (ensureNotFree v) (seq (normalForm (ensureSpine vs)) (seq (ensureNotFree rel) (seq c (prim_count v vs rel c)))) prim_count :: Int -> [Int] -> (Int -> Int -> Bool) -> Int -> Bool prim_count external --- "All different" constraint on FD variables. --- @param xs - list of FD variables --- @return satisfied if the FD variables in the argument list xs --- have pairwise different values. allDifferent :: [Int] -> Bool allDifferent vs = seq (normalForm (ensureSpine vs)) (prim_allDifferent vs) --- For backward compatibility. Use `allDifferent`. all_different :: [Int] -> Bool all_different = allDifferent prim_allDifferent :: [Int] -> Bool prim_allDifferent external --- Instantiate a single FD variable to its values in the specified domain. indomain :: Int -> Bool indomain x = seq x (prim_indomain x) prim_indomain :: Int -> Bool prim_indomain external --------------------------------------------------------------------------- -- Labeling. --- Instantiate FD variables to their values in the specified domain. --- @param options - list of option to control the instantiation of FD variables --- @param xs - list of FD variables that are non-deterministically --- instantiated to their possible values. labeling :: [LabelingOption] -> [Int] -> Bool labeling options vs = seq (normalForm (map ensureNotFree (ensureSpine options))) (seq (normalForm (ensureSpine vs)) (prim_labeling options vs)) prim_labeling :: [LabelingOption] -> [Int] -> Bool prim_labeling external --- This datatype contains all options to control the instantiated of FD variables --- with the enumeration constraint `labeling`. --- @cons LeftMost - The leftmost variable is selected for instantiation (default) --- @cons FirstFail - The leftmost variable with the smallest domain is selected --- (also known as first-fail principle) --- @cons FirstFailConstrained - The leftmost variable with the smallest domain --- and the most constraints on it is selected. --- @cons Min - The leftmost variable with the smalled lower bound is selected. --- @cons Max - The leftmost variable with the greatest upper bound is selected. --- @cons Step - Make a binary choice between `x=#b` and --- `x/=#b` for the selected variable --- `x` where `b` is the lower or --- upper bound of `x` (default). --- @cons Enum - Make a multiple choice for the selected variable for all the values --- in its domain. --- @cons Bisect - Make a binary choice between `x<=#m` and --- `x>#m` for the selected variable --- `x` where `m` is the midpoint --- of the domain `x` --- (also known as domain splitting). --- @cons Up - The domain is explored for instantiation in ascending order (default). --- @cons Down - The domain is explored for instantiation in descending order. --- @cons All - Enumerate all solutions by backtracking (default). --- @cons Minimize v - Find a solution that minimizes the domain variable v --- (using a branch-and-bound algorithm). --- @cons Maximize v - Find a solution that maximizes the domain variable v --- (using a branch-and-bound algorithm). --- @cons Assumptions x - The variable x is unified with the number of choices --- made by the selected enumeration strategy when a solution --- is found. --- @cons RandomVariable x - Select a random variable for instantiation --- where `x` is a seed value for the random numbers --- (only supported by SWI-Prolog). --- @cons RandomValue x - Label variables with random integer values --- where `x` is a seed value for the random numbers --- (only supported by SWI-Prolog). data LabelingOption = LeftMost | FirstFail | FirstFailConstrained | Min | Max | Step | Enum | Bisect | Up | Down | All | Minimize Int | Maximize Int | Assumptions Int | RandomVariable Int | RandomValue Int -- end of library CLPFD