Skip to content

Commit b64a5ec

Browse files
committed
And, Or take sets of Props
Remove redundant UniqueSym class.
1 parent bdae51d commit b64a5ec

File tree

3 files changed

+57
-39
lines changed

3 files changed

+57
-39
lines changed

src/compiler/scala/tools/nsc/transform/patmat/Logic.scala

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import scala.language.postfixOps
1111
import scala.collection.mutable
1212
import scala.reflect.internal.util.Statistics
1313
import scala.reflect.internal.util.HashSet
14+
import scala.annotation.tailrec
1415

1516
trait Logic extends Debugging {
1617
import PatternMatchingStats._
@@ -46,7 +47,7 @@ trait Logic extends Debugging {
4647
type Tree
4748

4849
class Prop
49-
case class Eq(p: Var, q: Const) extends Prop
50+
final case class Eq(p: Var, q: Const) extends Prop
5051

5152
type Const
5253

@@ -103,39 +104,53 @@ trait Logic extends Debugging {
103104
def implications: List[(Sym, List[Sym], List[Sym])]
104105
}
105106

107+
private def propToLinkedHashSet(ops: Seq[Prop]) = {
108+
val set = new mutable.LinkedHashSet[Prop]()
109+
ops.foreach(set += _)
110+
set
111+
}
112+
106113
// would be nice to statically check whether a prop is equational or pure,
107114
// but that requires typing relations like And(x: Tx, y: Ty) : (if(Tx == PureProp && Ty == PureProp) PureProp else Prop)
108-
case class And(a: Prop, b: Prop) extends Prop
109-
case class Or(a: Prop, b: Prop) extends Prop
110-
case class Not(a: Prop) extends Prop
115+
final case class And(ops: mutable.LinkedHashSet[Prop]) extends Prop
116+
object And {
117+
def apply(ops: Prop*) = new And(propToLinkedHashSet(ops))
118+
}
119+
final case class Or(ops: mutable.LinkedHashSet[Prop]) extends Prop
120+
object Or {
121+
def apply(ops: Prop*) = new Or(propToLinkedHashSet(ops))
122+
}
123+
124+
final case class Not(a: Prop) extends Prop
111125

112126
case object True extends Prop
113127
case object False extends Prop
114128

115129
// symbols are propositions
116-
abstract case class Sym(variable: Var, const: Const) extends Prop {
130+
final class Sym private[PropositionalLogic] (val variable: Var, val const: Const) extends Prop {
117131
private val id: Int = Sym.nextSymId
118132

119-
override def toString = variable +"="+ const +"#"+ id
133+
override def toString = variable + "=" + const + "#" + id
120134
}
121-
class UniqueSym(variable: Var, const: Const) extends Sym(variable, const)
135+
122136
object Sym {
123137
private val uniques: HashSet[Sym] = new HashSet("uniques", 512)
124138
def apply(variable: Var, const: Const): Sym = {
125-
val newSym = new UniqueSym(variable, const)
139+
val newSym = new Sym(variable, const)
126140
(uniques findEntryOrUpdate newSym)
127141
}
128-
private def nextSymId = {_symId += 1; _symId}; private var _symId = 0
142+
def nextSymId = {_symId += 1; _symId}; private var _symId = 0
129143
implicit val SymOrdering: Ordering[Sym] = Ordering.by(_.id)
130144
}
131145

132-
def /\(props: Iterable[Prop]) = if (props.isEmpty) True else props.reduceLeft(And(_, _))
133-
def \/(props: Iterable[Prop]) = if (props.isEmpty) False else props.reduceLeft(Or(_, _))
146+
def /\(props: Iterable[Prop]) = if (props.isEmpty) True else And(props.toSeq: _*)
147+
def \/(props: Iterable[Prop]) = if (props.isEmpty) False else Or(props.toSeq: _*)
148+
134149

135150
trait PropTraverser {
136151
def apply(x: Prop): Unit = x match {
137-
case And(a, b) => apply(a); apply(b)
138-
case Or(a, b) => apply(a); apply(b)
152+
case And(ops) => ops foreach apply
153+
case Or(ops) => ops foreach apply
139154
case Not(a) => apply(a)
140155
case Eq(a, b) => applyVar(a); applyConst(b)
141156
case _ =>
@@ -154,8 +169,8 @@ trait Logic extends Debugging {
154169

155170
trait PropMap {
156171
def apply(x: Prop): Prop = x match { // TODO: mapConserve
157-
case And(a, b) => And(apply(a), apply(b))
158-
case Or(a, b) => Or(apply(a), apply(b))
172+
case And(ops) => And(ops map apply)
173+
case Or(ops) => Or(ops map apply)
159174
case Not(a) => Not(apply(a))
160175
case p => p
161176
}
@@ -255,8 +270,8 @@ trait Logic extends Debugging {
255270
}
256271
}
257272

258-
debug.patmat("eqAxioms:\n"+ cnfString(toFormula(eqAxioms)))
259-
debug.patmat("pure:"+ pure.map(p => cnfString(p)).mkString("\n"))
273+
debug.patmat(s"eqAxioms:\n$eqAxioms")
274+
debug.patmat(s"pure:${pure.mkString("\n")}")
260275

261276
if (Statistics.canEnable) Statistics.stopTimer(patmatAnaVarEq, start)
262277

src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
4646
val cond = test.prop
4747

4848
def simplify(c: Prop): Set[Prop] = c match {
49-
case And(a, b) => simplify(a) ++ simplify(b)
50-
case Or(_, _) => Set(False) // TODO: make more precise
51-
case Not(Eq(Var(_), NullConst)) => Set(True) // not worth remembering
49+
case And(ops) => ops.toSet flatMap simplify
50+
case Or(ops) => Set(False) // TODO: make more precise
51+
case Not(Eq(Var(_), NullConst)) => Set(True) // not worth remembering
5252
case _ => Set(c)
5353
}
5454
val conds = simplify(cond)
5555

5656
if (conds(False)) false // stop when we encounter a definite "no" or a "not sure"
5757
else {
58-
val nonTrivial = conds filterNot (_ == True)
58+
val nonTrivial = conds - True
5959
if (nonTrivial nonEmpty) {
6060
tested ++= nonTrivial
6161

src/compiler/scala/tools/nsc/transform/patmat/Solving.scala

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,23 @@ trait Solving extends Logic {
4444
def negationNormalFormNot(p: Prop, budget: Int): Prop =
4545
if (budget <= 0) throw AnalysisBudget.exceeded
4646
else p match {
47-
case And(a, b) => Or(negationNormalFormNot(a, budget - 1), negationNormalFormNot(b, budget - 1))
48-
case Or(a, b) => And(negationNormalFormNot(a, budget - 1), negationNormalFormNot(b, budget - 1))
49-
case Not(p) => negationNormalForm(p, budget - 1)
50-
case True => False
51-
case False => True
52-
case s: Sym => Not(s)
47+
case And(ps) => Or (ps map (negationNormalFormNot(_, budget - 1)))
48+
case Or(ps) => And(ps map (negationNormalFormNot(_, budget - 1)))
49+
case Not(p) => negationNormalForm(p, budget - 1)
50+
case True => False
51+
case False => True
52+
case s: Sym => Not(s)
5353
}
5454

5555
def negationNormalForm(p: Prop, budget: Int = AnalysisBudget.max): Prop =
5656
if (budget <= 0) throw AnalysisBudget.exceeded
5757
else p match {
58-
case And(a, b) => And(negationNormalForm(a, budget - 1), negationNormalForm(b, budget - 1))
59-
case Or(a, b) => Or(negationNormalForm(a, budget - 1), negationNormalForm(b, budget - 1))
60-
case Not(negated) => negationNormalFormNot(negated, budget - 1)
58+
case Or(ps) => Or (ps map (negationNormalForm(_, budget - 1)))
59+
case And(ps) => And(ps map (negationNormalForm(_, budget - 1)))
60+
case Not(negated) => negationNormalFormNot(negated, budget - 1)
6161
case True
6262
| False
63-
| (_ : Sym) => p
63+
| (_ : Sym) => p
6464
}
6565

6666
val TrueF = formula()
@@ -92,14 +92,17 @@ trait Solving extends Logic {
9292
case False => FalseF
9393
case s: Sym => lit(s)
9494
case Not(s: Sym) => negLit(s)
95-
case And(a, b) =>
96-
val cnfA = conjunctiveNormalForm(a, budget - 1)
97-
val cnfB = conjunctiveNormalForm(b, budget - cnfA.size)
98-
cnfA ++ cnfB
99-
case Or(a, b) =>
100-
val cnfA = conjunctiveNormalForm(a)
101-
val cnfB = conjunctiveNormalForm(b)
102-
distribute(cnfA, cnfB, budget - (cnfA.size + cnfB.size))
95+
case And(ps) =>
96+
val formula = formulaBuilder
97+
ps foreach { p =>
98+
val cnf = conjunctiveNormalForm(p, budget - 1)
99+
addFormula(formula, cnf)
100+
}
101+
toFormula(formula)
102+
case Or(ps) =>
103+
ps map (conjunctiveNormalForm(_)) reduceLeft { (a, b) =>
104+
distribute(a, b, budget - (a.size + b.size))
105+
}
103106
}
104107
}
105108

0 commit comments

Comments
 (0)