Skip to content

Commit e7aaac4

Browse files
committed
more logic tests
1 parent 4cb2efb commit e7aaac4

File tree

3 files changed

+202
-3
lines changed

3 files changed

+202
-3
lines changed

build.sbt

+3
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ lazy val logic = crossProject(JSPlatform, JVMPlatform, NativePlatform)
198198
.settings(
199199
name := "dotty-cps-async-logic",
200200
libraryDependencies += "com.github.sbt" % "junit-interface" % "0.13.3" % "test",
201+
).jsSettings(
202+
scalaJSUseMainModuleInitializer := true,
203+
libraryDependencies += ("org.scala-js" %% "scalajs-junit-test-runtime" % "1.8.0" % Test).cross(CrossVersion.for3Use2_13),
201204
)
202205

203206

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package cps.logic
2+
3+
import org.junit.{Test,Ignore}
4+
5+
import cps.*
6+
import cps.monads.logic.*
7+
8+
/**
9+
* Someone in Dreadsbury Mansion killed Aunt Agatha.
10+
*Agatha
11+
*, the butler
12+
*, and Charles live in Dreadsbury Mansion
13+
*, and
14+
* are the only ones to live there.
15+
* (+)A killer always hates and is
16+
* (+) no richer than his victim.
17+
* (+)Charles hates noone that Agatha hates
18+
*.
19+
*(+)Agatha hates everybody except the butler
20+
*.(+) The butler hates everyone
21+
*not richer than Aunt Agatha.
22+
* (+) The butler hates everyone whom Agatha hates.
23+
*(+) Noone hates everyone.
24+
* Who killed Agatha ?
25+
**/
26+
27+
class AgadaTest {
28+
29+
@Test def testAgada(): Unit = {
30+
val worlds = AgadaTest.allWorlds()
31+
val result = worlds.toLazyList.toIndexedSeq
32+
val killer = result.map(_.killer).toSet
33+
//for { r <- result } {
34+
// println(s"result.killer=${r.killer}")
35+
// println(s"result.richer=${r.richer}")
36+
// println(s"result.hates=${r.hates}")
37+
// println("------------------")
38+
//}
39+
assert(killer.size == 1)
40+
assert(killer.head == AgadaTest.agata)
41+
}
42+
43+
}
44+
45+
object AgadaTest {
46+
47+
case class Person(name: String)
48+
case class Richer(p1: Person, p2: Person)
49+
case class Hates(p1: Person, p2: Person)
50+
51+
val agata = Person("Agatha")
52+
val butler = Person("Butler")
53+
val charles = Person("Charles")
54+
55+
val citizents = List(agata,butler,charles)
56+
57+
case class World(
58+
richer: Set[Richer],
59+
hates: Set[Hates],
60+
killer: Person
61+
)
62+
63+
def allWorlds(): LogicStream[World] = reify[LogicStream]{
64+
val richer = reflect(allRichers())
65+
val hates = reflect(allHates())
66+
val killer = reflect(LogicStream.fromCollection(citizents))
67+
68+
// a killer alwasy hates. ... victim
69+
70+
guard {
71+
hates.contains(Hates(killer,agata))
72+
}
73+
74+
guard {
75+
// a killer is no richer than his victim
76+
!richer.contains(Richer(killer,agata))
77+
}
78+
79+
80+
//The butler hates everyone
81+
// * not richer than Aunt Agatha
82+
guard {
83+
citizents.forall(p =>
84+
if (richer.contains(Richer(agata,p))) {
85+
hates.contains(Hates(butler,p))
86+
} else {
87+
true
88+
}
89+
)
90+
}
91+
92+
World(richer, hates, killer)
93+
}
94+
95+
96+
def allRichers(): LogicStream[Set[Richer]] = reify[LogicStream]{
97+
val allRicher = for(p1 <- citizents; p2 <- citizents if p1!=p2) yield Richer(p1,p2)
98+
val candidate = reflect(allSubsets(allRicher.toIndexedSeq)).toSet
99+
guard(candidate.forall{ case Richer(p1,p2) => !candidate.contains(Richer(p2,p1)) })
100+
guard{
101+
// note, that if we assume, that all wealth are different.
102+
// if we don't assume this, other solutions become possible
103+
val pairs = for{ p1 <- citizents; p2 <- citizents if p1!=p2 } yield (p1,p2)
104+
pairs.forall{ case (p1,p2) =>
105+
candidate.contains(Richer(p1,p2)) || candidate.contains(Richer(p2,p1))
106+
}
107+
}
108+
candidate
109+
}
110+
111+
def allHates(): LogicStream[Set[Hates]] = reify[LogicStream]{
112+
def allPairs = for(p1 <- citizents; p2 <- citizents) yield Hates(p1,p2)
113+
val candidate = reflect(allSubsets(allPairs.toIndexedSeq)).toSet
114+
115+
// Agatha hates everybody except the butler
116+
guard(
117+
!candidate.contains(Hates(agata,butler)) &&
118+
candidate.contains(Hates(agata,agata)) &&
119+
candidate.contains(Hates(agata,charles))
120+
)
121+
122+
// Charles hates noone that Agatha hates
123+
// The butler hates everyone whom Agatha hates.
124+
guard(
125+
citizents.forall{ p =>
126+
if (candidate.contains(Hates(agata,p))) {
127+
!candidate.contains(Hates(charles,p))
128+
&&
129+
candidate.contains(Hates(butler,p))
130+
} else {
131+
true
132+
}
133+
}
134+
)
135+
136+
137+
138+
//Noone hates everyone.
139+
guard{
140+
citizents.forall(p => !citizents.forall(p1 => candidate.contains(Hates(p,p1))))
141+
}
142+
143+
candidate
144+
}
145+
146+
def allSubsets[T](xs: IndexedSeq[T], from:Int=0): LogicStream[List[T]] = reify[LogicStream]{
147+
if (xs.size == from) {
148+
List.empty
149+
} else {
150+
val head = xs(from)
151+
val tail = reflect(allSubsets(xs,from+1))
152+
val next = LogicStream.pure(head::tail) |+| LogicStream.pure(tail)
153+
reflect(next)
154+
}
155+
}
156+
157+
158+
}

logic/shared/src/test/scala/cps/logic/DefaultLogicMonadBasicTest.scala

+41-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,47 @@ import cps.monads.logic.*
88
class DefaultLogicMonadBasicTest {
99

1010
@Test
11-
def logicMonadFromCollection() = {
12-
val m = LogicStream.fromCollection(List(1,2,3))
13-
11+
def basicInterleaveFromCollection() = {
12+
val m1 = LogicStream.fromCollection(List(1,2,3))
13+
val m2 = LogicStream.fromCollection(List(4,5,6))
14+
assert(m1.toLazyList.toSeq == Seq(1,2,3))
15+
val m3 = m1 |+| m2
16+
assert(m3.toLazyList.toSeq == Seq(1,2,3,4,5,6))
17+
val m4 = m2 |+| m1
18+
assert(m4.toLazyList.toSeq == Seq(4,5,6,1,2,3))
19+
val m5 = m1 | m2
20+
//println(s"m5=${m5.toLazyList.toIndexedSeq}")
21+
assert(m5.toLazyList.toSeq == Seq(1,4,2,5,3,6))
22+
}
23+
24+
@Test
25+
def basicFairFlatMap() = {
26+
val m1 = LogicStream.fromCollection(List(1, 2))
27+
val m2 = m1 &>> { x =>
28+
if (x == 2) {
29+
LogicStream.fromCollection(List(4, 5, 6))
30+
} else {
31+
LogicStream.fromCollection(List(7, 8, 9))
32+
}
33+
}
34+
assert(m2.toLazyList.toSeq == Seq(7,4,8,5,9,6))
35+
}
36+
37+
@Test
38+
def testBaiscOnce(): Unit = {
39+
val m1 = LogicStream.fromCollection(List(1, 2))
40+
val m2 = once(m1)
41+
assert(m2.toLazyList.toSeq == Seq(1))
42+
}
43+
44+
@Test
45+
def testEmpty() = {
46+
val m1 = LogicStream.fromCollection(List.empty[Int])
47+
val m2 = LogicStream.fromCollection(List(1, 2))
48+
val m3 = m1 |+| m2
49+
assert(m1.toLazyList.toSeq == Seq.empty)
50+
assert(m2.toLazyList.toSeq == Seq(1,2))
51+
assert(m3.toLazyList.toSeq == Seq(1,2))
1452
}
1553

1654

0 commit comments

Comments
 (0)