hu.bme.mit.theta.xsts.cli.XstsCliPetrinetMdd.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of theta-xsts-cli Show documentation
Show all versions of theta-xsts-cli Show documentation
Xsts Cli subproject in the Theta model checking framework
/*
* Copyright 2024 Budapest University of Technology and Economics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package hu.bme.mit.theta.xsts.cli
import com.github.ajalt.clikt.parameters.groups.provideDelegate
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.enum
import com.github.ajalt.clikt.parameters.types.file
import com.google.common.base.Stopwatch
import hu.bme.mit.delta.java.mdd.JavaMddFactory
import hu.bme.mit.delta.java.mdd.MddHandle
import hu.bme.mit.delta.java.mdd.MddNode
import hu.bme.mit.delta.mdd.LatticeDefinition
import hu.bme.mit.delta.mdd.MddInterpreter
import hu.bme.mit.delta.mdd.MddVariableDescriptor
import hu.bme.mit.theta.analysis.algorithm.mdd.MddChecker
import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.*
import hu.bme.mit.theta.common.logging.Logger
import hu.bme.mit.theta.frontend.petrinet.analysis.PtNetDependency2Gxl
import hu.bme.mit.theta.frontend.petrinet.analysis.PtNetSystem
import hu.bme.mit.theta.frontend.petrinet.analysis.VariableOrderingFactory
import hu.bme.mit.theta.frontend.petrinet.model.PetriNet
import hu.bme.mit.theta.frontend.petrinet.model.Place
import hu.bme.mit.theta.xsts.cli.optiongroup.PetrinetDependencyOutputOptions
import java.io.File
import java.io.PrintStream
import java.util.*
import java.util.concurrent.TimeUnit
import javax.imageio.ImageIO
import kotlin.system.exitProcess
class XstsCliPetrinetMdd : XstsCliBaseCommand(
name = "PN_MDD", help = "Model checking of Petri nets using MDDs (Multi-value Decision Diagrams)"
) {
private val ordering: File? by option(help = "Path of the input variable ordering").file(
mustExist = true, canBeDir = false, mustBeReadable = true
)
private val id: String by option(help = "ID of the input model. Used for symbolic output").default("")
private val iterationStrategy: MddChecker.IterationStrategy by option(
help = "The state space generation algorithm to use"
).enum().default(MddChecker.IterationStrategy.GSAT)
private val dependencyOutput by PetrinetDependencyOutputOptions()
private fun loadOrdering(petriNet: PetriNet): List =
if (ordering == null) petriNet.places.sortedWith { p1: Place, p2: Place ->
String.CASE_INSENSITIVE_ORDER.compare(
p1.id.reversed(), p2.id.reversed()
)
} else VariableOrderingFactory.fromFile(ordering, petriNet)
private fun petrinetAnalysis() {
val totalTimer = Stopwatch.createStarted()
val petriNet = inputOptions.loadPetriNet()[0]
val effectiveOrdering = loadOrdering(petriNet)
val system = PtNetSystem(petriNet, effectiveOrdering)
createDepGxl(system)
createDepGxlGSat(system)
createDepMat(system)
createDepMatPng(system)
val variableOrder = JavaMddFactory.getDefault().createMddVariableOrder(LatticeDefinition.forSets())
effectiveOrdering.forEach { variableOrder.createOnTop(MddVariableDescriptor.create(it)) }
val ssgTimer = Stopwatch.createStarted()
val provider: StateSpaceEnumerationProvider = when (iterationStrategy) {
MddChecker.IterationStrategy.BFS -> BfsProvider(variableOrder)
MddChecker.IterationStrategy.SAT -> SimpleSaturationProvider(variableOrder)
MddChecker.IterationStrategy.GSAT -> GeneralizedSaturationProvider(variableOrder)
}
val stateSpace = provider.compute(
system.initializer, system.transitions, variableOrder.defaultSetSignature.topVariableHandle
)
ssgTimer.stop()
totalTimer.stop()
val unionProvider = variableOrder.defaultUnionProvider
listOf(
id,
inputOptions.model.path,
system.name,
MddInterpreter.calculateNonzeroCount(stateSpace),
numberOfNodes(stateSpace),
totalTimer.elapsed(TimeUnit.MICROSECONDS),
ssgTimer.elapsed(TimeUnit.MICROSECONDS),
variableOrder.mddGraph.uniqueTableSize,
unionProvider.cacheSize,
unionProvider.queryCount,
unionProvider.hitCount,
).forEach(writer::cell)
if (iterationStrategy in setOf(MddChecker.IterationStrategy.GSAT, MddChecker.IterationStrategy.SAT)) {
listOf(
provider.cacheSize, provider.queryCount, provider.hitCount
).forEach(writer::cell)
}
listOf(
provider.cacheSize, provider.queryCount, provider.hitCount
).forEach(writer::cell)
if (iterationStrategy in setOf(MddChecker.IterationStrategy.GSAT, MddChecker.IterationStrategy.SAT)) {
val collector: MutableSet = mutableSetOf()
provider.clear()
listOf(collector.size).forEach(writer::cell)
}
}
private fun createDepMatPng(system: PtNetSystem) {
if (dependencyOutput.depMatPng == null) return
if (system.placeCount > 10000 || system.transitionCount > 10000) {
logger.write(
Logger.Level.INFO,
"[WARNING] Skipping image generation because the model size exceeds 10k places or " + "transitions."
)
return
}
ImageIO.write(system.dependencyMatrixImage(1), "PNG", dependencyOutput.depMatPng)
}
private fun createDepMat(system: PtNetSystem) {
val file = dependencyOutput.depMat ?: return
file.createNewFile()
with(PrintStream(file)) { print(system.printDependencyMatrixCsv()) }
}
private fun createDepGxlGSat(system: PtNetSystem) {
val file = dependencyOutput.depGxlGsat ?: return
file.createNewFile()
with(PrintStream(file)) { print(PtNetDependency2Gxl.toGxl(system, true)) }
}
private fun createDepGxl(system: PtNetSystem) {
val file = dependencyOutput.depGxl ?: return
file.createNewFile()
with(PrintStream(file)) { print(PtNetDependency2Gxl.toGxl(system, false)) }
}
override fun run() {
try {
if (inputOptions.isPnml()) petrinetAnalysis()
} catch (e: Exception) {
printError(e)
exitProcess(1)
}
}
private fun numberOfNodes(root: MddHandle): Int {
val result: MutableSet = mutableSetOf()
val stack = Stack()
stack.push(root.node)
while (stack.isNotEmpty()) {
val current = stack.pop()
if (!result.add(current) || current.isTerminal) continue
val cursor = current.cursor()
while (cursor.moveNext()) {
stack.push(cursor.value())
}
}
return result.size
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy