Advertisement
Guest User

162p7

a guest
Mar 20th, 2015
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 13.34 KB | None | 0 0
  1. package miniprologfd.solver
  2.  
  3. // note the renaming that is being done by these imports
  4. import scala.collection.mutable.{ Map => MMap }
  5. import miniprologfd.interpreter.{ Value, NumValue, SymPlaceholder => Variable }
  6. import miniprologfd.syntax.lowlevel.{
  7.   SymbolicROP => ROP,
  8.   SymEQ => EQ,
  9.   SymNE => NE,
  10.   SymLT => LT,
  11.   SymLE => LE,
  12.   SymGT => GT,
  13.   SymGE => GE
  14. }
  15.  
  16.  
  17. // an interval of integers from 0 to Intervals.maxValue, inclusive
  18. case class Interval(low: Int, hi: Int) {
  19.   assert(low >= 0 && hi >= low && hi <= Intervals.maxValue)
  20.   override def toString = "[" + low + ".." + hi + "]"
  21. }
  22.  
  23. // represents the possible values of a variable as a list of
  24. // intervals. by construction this list contains non-overlapping
  25. // intervals in ascending order.
  26. case class Intervals(ns: List[Interval]) {
  27.   // are there no possible values?
  28.   def isEmpty: Boolean = ns.isEmpty
  29.  
  30.   // apply function f to every possible value
  31.   def foreach(f: Int => Unit): Unit = {
  32.     var a = 0
  33.     for (interval <- ns) {
  34.       // for loop execution with a range
  35.       for (a <- interval.low to interval.hi) {
  36.         f(a)
  37.       }
  38.     }
  39.   }
  40.  
  41.   // compute the intersection of these possible values and another set
  42.   // of possible values
  43.   def intersect(i: Intervals): Intervals = {
  44.     val intersectionList = List[Interval]()
  45.  
  46.     for (i_curr <- ns) {
  47.       for (i_new <- i.ns) {
  48.         intersectIntervalPair(i_curr, i_new) match {
  49.           case Some(intersected_interval_pair) => intersectionList :+ intersected_interval_pair
  50.           case None => intersectionList
  51.         }
  52.       }
  53.     }
  54.     Intervals(intersectionList)
  55.   }
  56.  
  57.   def intersectIntervalPair(i1: Interval, i2: Interval): Option[Interval] = {
  58.     // overlapping case
  59.     ((i2.low <= i1.hi) && (i1.low <= i2.hi)) match {
  60.       // overlap is true
  61.       case true => (i1.low <= i2.low) match {
  62.         case true => Some(Interval(i1.low, i2.hi))
  63.         case false => Some(Interval(i2.low, i1.hi))
  64.       }
  65.       case false => None
  66.     }
  67.   }
  68.  
  69.   // is there only a single possible value?
  70.   def singleton: Boolean = {
  71.     if ((ns.length == 1) && (ns.head.low == ns.head.hi)) true else false
  72.   }
  73.  
  74.   // retrieve the single possible value (only valid if there is only a
  75.   // single possible value to retrieve)
  76.   def getSingleton: Int = {
  77.     assert(singleton, "Not a singleton error")
  78.     ns.head.low
  79.   }
  80.  
  81.   // remove a possible value from the current set of possible values
  82.   def -(n: Int): Intervals = intersect(Intervals.getIntervals(NE, n))
  83.  
  84.   // return the lowest currently possible value
  85.   def lowest: Int = if (!isEmpty) ns.head.low else -1
  86.  
  87.   // return the highest currently possible value
  88.   def highest: Int = if (!isEmpty) ns.reverse.head.hi else -1
  89.  
  90.   // returns all currently possible values < n
  91.   def LT(n: Int): Intervals = intersect(Intervals.getIntervals(miniprologfd.syntax.lowlevel.SymLT, n))
  92.  
  93.   // returns all currently possible values ≤ n
  94.   def LE(n: Int): Intervals = intersect(Intervals.getIntervals(miniprologfd.syntax.lowlevel.SymLE, n))
  95.  
  96.   // returns all currently possible values > n
  97.   def GT(n: Int): Intervals = intersect(Intervals.getIntervals(miniprologfd.syntax.lowlevel.SymGT, n))
  98.  
  99.   // returns all currently possible values ≥ n
  100.   def GE(n: Int): Intervals = intersect(Intervals.getIntervals(miniprologfd.syntax.lowlevel.SymGE, n))
  101.  
  102.   override def toString =
  103.     ns.mkString(", ")
  104. }
  105.  
  106. // companion object with useful functions
  107. object Intervals {
  108.   // maximum possible value
  109.   val maxValue = 500
  110.  
  111.   // default Intervals value, i.e., the default set of possible values
  112.   // for any variable
  113.   val default = Intervals(0, maxValue)
  114.  
  115.   // create an Intervals with a single possible value
  116.   def apply(n: Int): Intervals = Intervals(n)
  117.  
  118.   // create and Intervals with no possible values
  119.   def apply(): Intervals = Intervals(List[Interval]())
  120.  
  121.   // create an Intervals with a set of contiguous possible values in
  122.   // the range low to hi
  123.   def apply(low: Int, hi: Int): Intervals = Intervals(low, hi)
  124.  
  125.   // Create an Intervals containing all possible values that have the
  126.   // given relation op with the given integer n.  `max` below refers
  127.   // to the `maxValue` constant defined above.
  128.   //
  129.   // examples: getIntervals(<,  10) = [[0..9]]
  130.   //           getIntervals(=,  10) = [[10..10]]
  131.   //           getIntervals(≠,  10) = [[0..9], [11..max]]
  132.   //           getIntervals(<,   0) = []          // less than minimum
  133.   //           getIntervals(>, max) = []          // greater than maximum
  134.   //           getIntervals(=,  -1) = []          // out of range
  135.   //           getIntervals(>,  -5) = [[0..max]]  // the whole valid range
  136.   def getIntervals(op: ROP, n: Int): Intervals = op match {
  137.     case EQ => n match {
  138.       case v if (v == Intervals.maxValue) => Intervals()
  139.       case v if (v < 0) => default
  140.       case _ => Intervals(n)
  141.     }
  142.     case NE => n match {
  143.       case v if (v == 0) => Intervals(1, maxValue)
  144.       case v if (v < 0 || v > Intervals.maxValue) => default
  145.       case _ => Intervals(List(Interval(0, n - 1), Interval(n + 1, maxValue)))
  146.     }
  147.     case LT => n match {
  148.       case v if (v <= 0) => Intervals()
  149.       case v if (v > Intervals.maxValue) => default
  150.       case _ => Intervals(0, n - 1)
  151.     }
  152.     case LE => n match {
  153.       case v if (v < 0) => Intervals()
  154.       case v if (v > maxValue) => default
  155.       case _ => Intervals(0, n)
  156.     }
  157.     case GT => n match {
  158.       case v if (v >= Intervals.maxValue) => Intervals()
  159.       case v if (n < 0) => default
  160.       case _ => Intervals(n + 1, Intervals.maxValue)
  161.     }
  162.     case GE => n match {
  163.       case v if (v > Intervals.maxValue) => Intervals()
  164.       case v if (n < 0) => default
  165.       case _ => Intervals(n, Intervals.maxValue)
  166.     }
  167.   }
  168. }
  169.  
  170. // constraints between variables
  171. case class Constraint(op: ROP, x1: Variable, x2: Variable)
  172.  
  173. // a map from variables to their possible values
  174. case class Values(vs: Map[Variable, Intervals] = Map()) {
  175.   // retrieve the possible values for the given variable; if the
  176.   // variable isn't in vs then return the default set of possible
  177.   // values
  178.   def apply(x: Variable): Intervals = vs.getOrElse(x,Intervals.default)
  179.  
  180.   // return a mutable copy of this map
  181.   def mutableCopy: MValues = collection.mutable.Map() ++ vs
  182.  
  183.  
  184. // a mutable map from variables to their possible values
  185. case class MValues(vs: MMap[Variable, Intervals] = MMap()) {
  186.   // retrieve the possible values for the given variable; if the
  187.   // variable isn't in vs then return the default set of possible
  188.   // values
  189.   def apply(x: Variable): Intervals = vs.getOrElse(x,Intervals.default)
  190.  
  191.   // update the possible values of the given variable
  192.   def update(x: Variable, i: Intervals) {
  193.     vs += (x -> i)
  194.   }
  195.  
  196.   // clear the map
  197.   def clear() {
  198.     vs.clear
  199.   }
  200.  
  201.   // is the map empty?
  202.   def isEmpty: Boolean = vs.isEmpty
  203.  
  204.   // return an immutable copy of this map
  205.   def immutableCopy: Values = collection.immutable.Map() ++ vs
  206. }
  207.  
  208. // a map from variables to the constraints mentioning that variable
  209. case class Constraints(cs: Map[Variable, Set[Constraint]] = Map()) {
  210.   // retrieve the constraint set for the given variable; if the
  211.   // variable isn't in cs then return the empty set
  212.   def apply(x: Variable): Set[Constraint] = cs.getOrElse(x,Set[Constraint]())
  213.  
  214.   // add constraint c to the constraints sets for variables x1 and x2
  215.   // mentioned in constraint c
  216.   // Constraint(op: ROP, x1: Variable, x2: Variable)
  217.   def +(c: Constraint): Constraints = {
  218.     val newset1 = cs(c.x1) + c
  219.     val newset2 = cs(c.x2) + c
  220.     cs + (c.x1 -> newset1, c.x2 -> newset2)
  221. }
  222.  
  223. // this is the actual solver, including an API used by the
  224. // miniprolog-fd interpreter to insert constraints and query for
  225. // satisfiable values.
  226. case class ConstraintStore(
  227.   // map from variable to intervals (possible values for that variable)
  228.   values: Values = Values(),
  229.   // a map from variables to the constraints mentioning that variable
  230.   constraints: Constraints = Constraints()) {
  231.  
  232.   ////////// API FOR INTERPRETER //////////
  233.  
  234.   // insert a new constraint into the constraint store. the return
  235.   // value is None if the new constraint is inconsistent with existing
  236.   // constraints, otherwise it is Some(the updated constraint store).
  237.   def insert(op: ROP, v1: Value, v2: Value): Option[ConstraintStore] = (v1,v2) match {
  238.     // have to switch them
  239.     case (n@NumValue, v@Variable) =>
  240.     {
  241.      
  242.       // add new constraint
  243.       val newConstraints = constraints + Constraint(op, x1, x2)
  244.       val possibleValues =  Intervals.getIntervals(reverseOp(op), n)
  245.       var vmc = values.mutableCopy
  246.       propagate(vmc, v, possibleValues)
  247.       if(!vmc.isEmpty) Some(ConstraintStore(vmc.immutableCopy,newConstraints)) else None
  248.     }
  249.     // regular case
  250.     case (n@Variable, v@NumValue) => {
  251.       // add new constraint
  252.       val newConstraints = constraints + Constraint(op, x1, x2)
  253.       val possibleValues =  Intervals.getIntervals(op, n)
  254.       var vmc = values.mutableCopy
  255.       propagate(vmc, v, possibleValues)
  256.       if(!vmc.isEmpty) Some(ConstraintStore(vmc.immutableCopy,newConstraints)) else None
  257.     }
  258.  
  259.     // if two variables
  260.     case (v1@Variable, v2@Variable) => values.vs(v1).singleton && values.vs(v2).singleton match {
  261.       // both variables singletons
  262.       case true => compare(values.vs(v1).getSingleton,op,values.vs(v2).getSingleton) match {
  263.         // constraint holds
  264.         case true => Some(ConstraintStore(values,constraints))
  265.         // constraint does not hold
  266.         case false => None
  267.       }
  268.       // variables not both singletons
  269.       case false => {
  270.         // add new constraint to constraints
  271.         val newConstraints = constraints + Constraint(op, x1, x2)
  272.         // solve(values, [x1,x2]) => gives you Option[Values]
  273.         solve(values,List(v1,v2)) match {
  274.           case Some(_) => ConstraintStore(values,constraints) //satisfiable
  275.           case None => None
  276.         }
  277.       }
  278.     }
  279.  
  280.   }
  281.  
  282.  
  283.   // Compares two integers with respect to the given operator.
  284.   def compare(n1: Int, op: ROP, n2: Int): Boolean = op match {
  285.     case GT => if(n1 > n2) true else false
  286.     case LT => if(n1 < n2) true else false
  287.     case LE => if (n1 <= n2) true else false
  288.     case GE => if (n1 >= n2) true else false
  289.     case EQ => if(n1 == n2) true else false
  290.     case NE => if(n1 != n2) true else false
  291.   }
  292.  
  293.   // query the constraint store for single satisfying values for the given
  294.   // list of variables
  295.   def SAT(xs: List[Variable]): List[NumValue] = solve(values,xs) match {
  296.     // if there is a singleton solution for each variable given all of the variable constraints
  297.     case Some(vals) => {
  298.       // get all the singleton values for each variable, put them in the same order as the original list by folding right
  299.       xs.foldright(List[NumValue]())((value:Variable, accumulator:List[NumValue])=> NumValue(vals(value))::accumulator)
  300.     }
  301.     // no satisfiable solution
  302.     case None => List[NumValue]()
  303.   }
  304.  
  305.   ////////// INTERNAL METHODS //////////
  306.  
  307.   // given the current possible values for all the variables, compute
  308.   // satisfying values for the given list of variables
  309.  
  310.   def solve(currValues: Values, xs: List[Variable]): Option[Values] = {
  311.     val x = xs.head
  312.     val tl = xs.tail
  313.     // for each possible value of x
  314.     for (v <- currValues(x)) {
  315.       // strip out all the values of x that don't work,
  316.       // and propagate these changes for all the other
  317.       // variables that depend on x
  318.       var mutableCV = currValues.mutableCopy
  319.       propagate(mutableCV,x,v)
  320.       // if there was a satisfiable solution for x
  321.       if(!mutableCV.isEmpty){
  322.         var currValuesN = mutableCV.immutableCopy
  323.         // repeat recursively if there are more variables
  324.         if(!tl.isEmpty){
  325.           solve(currValuesN,tl) match {
  326.             case None => None
  327.             case Some(cv) => return Some(cv)
  328.           }
  329.         }
  330.         else return Some(currValuesN)
  331.       }
  332.     }
  333.   }
  334.  
  335.   // constraint propagation: restrict the possible values of x to only
  336.   // include values in ranges. if that makes x unsatisfiable then
  337.   // return; if that changes the possible values of x then recursively
  338.   // propagate those changes to the other variables.
  339.   //
  340.   // IMPORTANT NOTE: because mutableCV returns a default set of
  341.   // possible values for any variable not contained in the mapping, we
  342.   // can't just iterate through all the constraints as done in the
  343.   // pseudocode (it would incorrectly propagate default values if
  344.   // mutableCV is made empty in some recursive call to
  345.   // propagate). instead, we need to explicitly check after each
  346.   // recursive call to propagate whether mutableCV is empty, and if so
  347.   // then explicitly return from the function.
  348.   def propagate(mutableCV: MValues, x: Variable, ranges: Intervals) {
  349.     ??? // FILL ME IN
  350.   }
  351.  
  352.   // narrow the current possible values of x1 (given as rangesX1)
  353.   // according to the constraint c, which is between x1 and some
  354.   // variable x2 (where rangesX2 gives the possible values of x2)
  355.   def narrow(x1: Variable, rangesX1: Intervals, c: Constraint, rangesX2: Intervals): Intervals =
  356.     ??? // FILL ME IN
  357.  
  358.   // reverse the meaning of a relational operator (e.g., < becomes >
  359.   // and ≤ becomes ≥)
  360.   def reverseOp(op: ROP): ROP =
  361.     op match {
  362.       case EQ => EQ
  363.       case NE => NE
  364.       case LT => GT
  365.       case LE => GE
  366.       case GT => LT
  367.       case GE => LE
  368.     }
  369. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement