-- | Sets whose members are represented compactly using a-- Presburger arithmetic formula. This is a high-level interface to-- 'OmegaSet'.---- This module is intended to be imported qualified, e.g.---- > import qualified Data.Presburger.Omega.Set as WSetmoduleData.Presburger.Omega.Set(Set,-- * Building setsset,fromOmegaSet,-- * Operations on setstoOmegaSet,-- ** Inspectingdimension,predicate,lowerBoundSatisfiable,upperBoundSatisfiable,obviousTautology,definiteTautology,exact,inexact,unknown,equal,-- ** BoundsupperBound,lowerBound,-- ** Binary operationsunion,intersection,difference,Effort(..),gist,-- ** Unary operationscomplement,approximate)whereimportSystem.IO.UnsafeimportData.Presburger.Omega.ExprimportqualifiedData.Presburger.Omega.LowLevelasLimportData.Presburger.Omega.LowLevel(OmegaSet,Effort(..))importData.Presburger.Omega.SetRel-- | Sets of points in Z^n defined by a formula.dataSet=Set{setDim::!Int-- ^ the number of variables,setExp::BoolExp-- ^ a predicate defining the set,setOmegaSet::OmegaSet-- ^ low-level representation of this set}instanceShowSetwhere-- Generate a call to 'set'showsPrecns=showParen(n>=10)$showString"set ".shows(setDims).showChar' '.showsPrec10(setExps)-- | Create a set whose members are defined by a predicate.---- The expression should have one free variable for each dimension.---- For example, the set of all points on the plane is-- -- > set 2 trueE-- -- The set of all points (x, y, z) where x > y + z is-- -- > set 3 (case takeFreeVariables' 3 of [x,y,z] -> x |>| y |+| z)--set::Int-- ^ Number of dimensions->BoolExp-- ^ Predicate defining the set->Setsetdimexpr|variablesWithinRangedimexpr=Set{setDim=dim,setExp=expr,setOmegaSet=unsafePerformIO$mkOmegaSetdimexpr}|otherwise=error"set: Variables out of range"mkOmegaSet::Int->BoolExp->IOOmegaSetmkOmegaSetdimexpr=L.newOmegaSetdim(\vars->expToFormulavarsexpr)--------------------------------------------------------------------------------- Creating sets from Omega sets-- | Convert an 'OmegaSet' to a 'Set'.fromOmegaSet::OmegaSet->IOSetfromOmegaSetoset=do(dim,expr)<-setToExpressionosetreturn$Set{setDim=dim,setExp=expr,setOmegaSet=oset}-- | Internal function to convert an 'OmegaSet' to a 'Set', when we know-- the set's dimension. This can avoid actually building the expression-- when all we want is the dimension.omegaSetToSet::Int->OmegaSet->IOSetomegaSetToSetdimoset=return$Set{setDim=dim,setExp=unsafePerformIO$do(_,expr)<-setToExpressionosetreturnexpr,setOmegaSet=oset}--------------------------------------------------------------------------------- Using sets-- First, some helper functions for applying OmegaSet functions to SetsuseSet::(OmegaSet->IOa)->Set->auseSetfs=unsafePerformIO$f(setOmegaSets)useSetSet::(OmegaSet->IOOmegaSet)->Int->Set->SetuseSetSetfdims=unsafePerformIO$doomegaSetToSetdim=<<f(setOmegaSets)useSet2::(OmegaSet->OmegaSet->IOa)->Set->Set->auseSet2fs1s2=unsafePerformIO$f(setOmegaSets1)(setOmegaSets2)useSet2Set::(OmegaSet->OmegaSet->IOOmegaSet)->Int->Set->Set->SetuseSet2Setfdims1s2=unsafePerformIO$doomegaSetToSetdim=<<f(setOmegaSets1)(setOmegaSets2)-- | Get the dimensionality of the space a set inhabitsdimension::Set->Intdimension=setDim-- | Get the predicate defining a set's memberspredicate::Set->BoolExppredicate=setExp-- | Convert a 'Set' to an 'OmegaSet'.toOmegaSet::Set->OmegaSettoOmegaSet=setOmegaSet-- | Compute the upper bound of a set by setting all UNKNOWN-- constraints to true.upperBound::Set->SetupperBounds=useSetSetL.upperBound(setDims)s-- | Compute the lower bound of a set by setting all UNKNOWN-- constraints to false.lowerBound::Set->SetlowerBounds=useSetSetL.lowerBound(setDims)slowerBoundSatisfiable::Set->BoollowerBoundSatisfiable=useSetL.lowerBoundSatisfiableupperBoundSatisfiable::Set->BoolupperBoundSatisfiable=useSetL.upperBoundSatisfiableobviousTautology::Set->BoolobviousTautology=useSetL.obviousTautologydefiniteTautology::Set->BooldefiniteTautology=useSetL.definiteTautology-- | True if the set has no UNKNOWN constraints.exact::Set->Boolexact=useSetL.exact-- | True if the set has UNKNOWN constraints.inexact::Set->Boolinexact=useSetL.inexact-- | True if the set is completely UNKNOWN.unknown::Set->Boolunknown=useSetL.unknown-- | Test whether two sets are equal.-- The sets must have the same dimension-- (@dimension s1 == dimension s2@), or an error will be raised.---- The answer is precise if both relations are 'exact'.-- If either relation is inexact, this function returns @False@.equal::Set->Set->Boolequal=useSet2L.equal-- | Union of two sets.-- The sets must have the same dimension-- (@dimension s1 == dimension s2@), or an error will be raised.union::Set->Set->Setunions1s2=useSet2SetL.union(setDims1)s1s2-- | Intersection of two sets.-- The sets must have the same dimension-- (@dimension s1 == dimension s2@), or an error will be raised.intersection::Set->Set->Setintersections1s2=useSet2SetL.intersection(setDims1)s1s2-- | Difference of two sets.-- The sets must have the same dimension-- (@dimension s1 == dimension s2@), or an error will be raised.difference::Set->Set->Setdifferences1s2=useSet2SetL.difference(setDims1)s1s2-- | Get the gist of a set, given some background truth. The-- gist operator uses heuristics to simplify the set while-- retaining sufficient information to regenerate the original by-- re-introducing the background truth. The sets must have the-- same dimension.---- The gist satisfies the property---- > x === gist effort x given `intersection` givengist::Effort->Set->Set->Setgistefforts1s2=useSet2Set(L.gisteffort)(setDims1)s1s2complement::Set->Setcomplements=useSetSetL.complement(setDims)sapproximate::Set->Setapproximates=useSetSetL.approximate(setDims)s