Skip to content

Commit e47bc5a

Browse files
committedDec 9, 2021
Rewrite BDD internals. Add PHP example
1 parent 325d5d3 commit e47bc5a

File tree

9 files changed

+1491
-813
lines changed

9 files changed

+1491
-813
lines changed
 

‎README.adoc

+12-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ image:https://hitsofcode.com/github/Lipen/kotlin-bdd["Hits-of-Code",link="https:
1919
:link-lib-bdd: https://github.com/sybila/biodivine-lib-bdd[lib-bdd]
2020
:link-sylvan: https://github.com/trolando/sylvan[Sylvan]
2121
:link-adiar: https://github.com/SSoelvsten/adiar[Adiar]
22+
:link-kobdd: https://github.com/korifey/kobdd[kobdd]
2223

2324
`kotlin-bdd` was heavily inspired by {link-cudd} (C/C++), {link-dd} (Python) and {link-lib-bdd} (Rust).
2425

25-
CAUTION: `kotlin-bdd` is currently a purely educational project and may not be as feature-complete and/or performant as full-fledged BDD packages such as {link-cudd}, {link-sylvan}, {link-adiar}.
26+
CAUTION: `kotlin-bdd` is currently a purely educational project and may not be as feature-complete and/or performant as full-fledged BDD packages such as {link-cudd}, {link-sylvan}, {link-adiar}, {link-kobdd}.
2627

2728
== Installation
2829

@@ -44,9 +45,18 @@ dependencies {
4445
// TODO
4546
----
4647

48+
== Run examples
49+
50+
=== PHP
51+
52+
----
53+
gw :examples:shadowJar
54+
java -cp examples/build/libs/examples.jar com.github.lipen.bdd.PHPKt
55+
----
56+
4757
'''
4858

49-
=== Bibliography
59+
== Bibliography
5060

5161
- R. E. Bryant.
5262
*"Graph-Based Algorithms for Boolean Function Manipulation,"* 1986. link:https://doi.org/10.1109/TC.1986.1676819[DOI].

‎build.gradle.kts

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ group = "com.github.Lipen"
55
plugins {
66
kotlin("jvm") version "1.6.0"
77
application
8+
id("com.github.johnrengelman.shadow") version "7.1.0" apply false
89
id("fr.brouillard.oss.gradle.jgitver") version "0.9.1"
910
id("com.github.ben-manes.versions") version "0.39.0"
1011
`maven-publish`
@@ -18,10 +19,11 @@ dependencies {
1819
implementation(platform(kotlin("bom")))
1920
implementation(kotlin("stdlib-jdk8"))
2021

21-
implementation("io.github.microutils:kotlin-logging:2.1.0")
22-
runtimeOnly("ch.qos.logback:logback-classic:1.2.3")
22+
implementation("io.github.microutils:kotlin-logging:2.1.15")
23+
runtimeOnly("ch.qos.logback:logback-classic:1.2.7")
2324

2425
testImplementation(kotlin("test"))
26+
testImplementation("com.soywiz.korlibs.klock:klock-jvm:2.4.8")
2527
}
2628

2729
tasks.test {

‎examples/build.gradle.kts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
2+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
3+
4+
plugins {
5+
kotlin("jvm")
6+
id("com.github.johnrengelman.shadow")
7+
}
8+
9+
repositories {
10+
mavenCentral()
11+
}
12+
13+
dependencies {
14+
implementation(platform(kotlin("bom")))
15+
implementation(kotlin("stdlib-jdk8"))
16+
17+
implementation(rootProject)
18+
implementation("io.github.microutils:kotlin-logging:2.1.15")
19+
runtimeOnly("ch.qos.logback:logback-classic:1.2.7")
20+
implementation("com.soywiz.korlibs.klock:klock-jvm:2.4.8")
21+
implementation("com.squareup.okio:okio:3.0.0")
22+
}
23+
24+
tasks.withType<KotlinCompile> {
25+
kotlinOptions.jvmTarget = "1.8"
26+
}
27+
28+
tasks.withType<ShadowJar> {
29+
archiveBaseName.set(project.name)
30+
archiveClassifier.set("")
31+
archiveVersion.set("")
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package com.github.lipen.bdd
2+
3+
import com.soywiz.klock.PerformanceCounter
4+
import com.soywiz.klock.measureTime
5+
import okio.buffer
6+
import okio.sink
7+
import java.io.File
8+
9+
private fun generatePhpClausesA(pigeons: Int, holes: Int): Sequence<List<Int>> = sequence {
10+
fun v(i: Int, j: Int) = (i - 1) * holes + j
11+
12+
// A: p clauses
13+
for (i in 1..pigeons)
14+
yield((1..holes).map { j -> v(i, j) })
15+
}
16+
17+
private fun generatePhpClausesBj(pigeons: Int, holes: Int, j: Int): Sequence<List<Int>> = sequence {
18+
fun v(i: Int, j: Int) = (i - 1) * holes + j
19+
20+
// B[j] clauses
21+
for (i in 1..pigeons) //(p-1) * p / 2
22+
for (k in i + 1..pigeons)
23+
yield(listOf(-v(i, j), -v(k, j)))
24+
}
25+
26+
private fun generatePhpClausesB(pigeons: Int, holes: Int): Sequence<List<Int>> = sequence {
27+
// B clauses
28+
for (j in 1..holes) //h *
29+
yieldAll(generatePhpClausesBj(pigeons, holes, j))
30+
}
31+
32+
private fun generatePhpClauses(pigeons: Int, holes: Int): Sequence<List<Int>> = sequence {
33+
require(pigeons > 0)
34+
require(holes > 0)
35+
// A: p clauses
36+
yieldAll(generatePhpClausesA(pigeons, holes))
37+
// B clauses
38+
yieldAll(generatePhpClausesB(pigeons, holes))
39+
}
40+
41+
fun php(pigeons: Int, holes: Int = pigeons - 1) {
42+
require(pigeons > 0)
43+
require(holes > 0)
44+
45+
println("Running PHP(p = $pigeons, h = $holes})...")
46+
47+
val timeStart = PerformanceCounter.reference
48+
val bdd = BDD()
49+
var f = bdd.one
50+
var totaltime = 0.0
51+
52+
fun v(i: Int, j: Int) = (i - 1) * holes + j
53+
54+
println("Generating and adding PHP clauses...")
55+
val file = File("data-php-${pigeons}.txt")
56+
println("Writing data to: '$file'")
57+
file.sink().buffer().use {
58+
with(it) {
59+
writeUtf8("step name BDD.size f.size steptime totaltime hits misses\n")
60+
61+
var count = 0
62+
63+
fun step(name: String, init: () -> Unit) {
64+
val steptime = measureTime {
65+
init()
66+
if ((count + 1) % 50 == 0) {
67+
bdd.collectGarbage(listOf(f))
68+
}
69+
}
70+
val fsize = bdd.descendants(f).size
71+
println(
72+
"Step #${count + 1} ($name) in %.3fs, BDD.size = ${bdd.size} (real size = ${bdd.realSize()}), f (size=$fsize) = $f, hits = ${bdd.cacheHits}, misses = ${bdd.cacheMisses}"
73+
.format(steptime.seconds)
74+
)
75+
totaltime += steptime.seconds
76+
val nameSafe = name.replace(" ", "_")
77+
writeUtf8(
78+
"${count + 1} $nameSafe ${bdd.realSize()} $fsize %.3f %.3f ${bdd.cacheHits} ${bdd.cacheMisses}\n"
79+
.format(steptime.seconds, totaltime)
80+
)
81+
count++
82+
}
83+
84+
for (clause in generatePhpClausesA(pigeons, holes)) {
85+
step("JoinA") {
86+
val c = bdd.clause(clause)
87+
f = bdd.applyAnd(f, c)
88+
}
89+
}
90+
91+
for (j in 1..holes) {
92+
for (clause in generatePhpClausesBj(pigeons, holes, j)) {
93+
step("JoinB") {
94+
val c = bdd.clause(clause)
95+
f = bdd.applyAnd(f, c)
96+
}
97+
}
98+
if (j < holes) {
99+
for (i in 1..pigeons) {
100+
step("Proj") {
101+
f = bdd.exists(f, v(i, j))
102+
}
103+
}
104+
}
105+
}
106+
}
107+
}
108+
109+
println("final f = $f")
110+
check(bdd.isZero(f)) {
111+
"Formula must be Zero (UNSAT) after adding all PHP clauses"
112+
}
113+
val totalTime = PerformanceCounter.reference - timeStart
114+
println("PHP($pigeons, $holes) done in %.2fs (totaltime=%.2f)".format(totalTime.seconds, totaltime))
115+
}
116+
117+
fun main(args: Array<String>) {
118+
val pigeons = if (args.isNotEmpty()) {
119+
args[0].toInt()
120+
} else {
121+
10 // default
122+
}
123+
php(pigeons = pigeons)
124+
}

‎settings.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
rootProject.name = "kotlin-bdd"
2+
3+
include("examples")

‎src/main/kotlin/com/github/lipen/bdd/BDD.kt

+307-808
Large diffs are not rendered by default.
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@file:Suppress("FunctionName")
2+
3+
package com.github.lipen.bdd
4+
5+
import kotlin.math.absoluteValue
6+
7+
fun BDD.clause(literals: Iterable<Int>): Int {
8+
// TODO: check uniqueness and consistency
9+
var current = zero
10+
for (lit in literals.sortedByDescending { it.absoluteValue }) {
11+
val x = variable(lit)
12+
current = applyOr(current, x)
13+
}
14+
return current
15+
}
16+
17+
fun BDD.clause_(literals: IntArray): Int {
18+
return clause(literals.asList())
19+
}
20+
21+
fun BDD.clause(vararg literals: Int): Int {
22+
return clause_(literals)
23+
}

‎src/main/kotlin/com/github/lipen/bdd/oldBDD.kt

+986
Large diffs are not rendered by default.

‎src/main/resources/logback.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</encoder>
66
</appender>
77

8-
<root level="debug">
8+
<root level="info">
99
<appender-ref ref="STDOUT"/>
1010
</root>
1111
</configuration>

0 commit comments

Comments
 (0)
Please sign in to comment.