All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.it.unibo.tuprolog.bdd.BinaryDecisionDiagramUtils.kt Maven / Gradle / Ivy

Go to download

Multi-platform library for representing and manipulating Binary Decision Diagrams

There is a newer version: 1.0.4
Show newest version
/**
 * @author Jason Dellaluce
 */

@file:JvmName("BinaryDecisionDiagramUtils")

package it.unibo.tuprolog.bdd

import it.unibo.tuprolog.bdd.exception.BinaryDecisionDiagramOperationException
import it.unibo.tuprolog.bdd.impl.AnyVisitor
import it.unibo.tuprolog.bdd.impl.ExpansionVisitor
import kotlin.js.JsName
import kotlin.jvm.JvmName

/**
 * Shortcut for the [BinaryDecisionDiagram.variableOf] method.
 */
@JsName("bddOf")
fun > bddOf(value: T): BinaryDecisionDiagram =
    BinaryDecisionDiagram.variableOf(value)

/**
 * Shortcut for the [BinaryDecisionDiagram.terminalOf] method.
 */
@JsName("bddTerminalOf")
fun > bddTerminalOf(
    value: Boolean
): BinaryDecisionDiagram = BinaryDecisionDiagram.terminalOf(value)

/** Internal helper function to catch all exceptions and wrap them into
 * BBD-specific ones. */
internal fun  runOperationAndCatchErrors(action: () -> T): T {
    try {
        return action()
    } catch (e: Throwable) {
        throw BinaryDecisionDiagramOperationException(
            "BinaryDecisionDiagram operation failure",
            e
        )
    }
}

/**
 * Applies a given operation over a [BinaryDecisionDiagram] using
 * the Shannon Expansion. The result is a reduction of a given diagram,
 * determined by applying an operation recursively over a BDD with
 * bottom-up order.
 */
@JsName("expansion")
fun , E> BinaryDecisionDiagram.expansion(
    falseTerminal: E,
    trueTerminal: E,
    operator: (node: T, low: E, high: E) -> E
): E {
    return runOperationAndCatchErrors {
        this.accept(
            ExpansionVisitor(
                operator,
                falseTerminal,
                trueTerminal
            )
        )
    }
}

/**
 * Returns true if the [BinaryDecisionDiagram] has at least one variable
 * element matching the given predicate.
 */
@JsName("anyWhere")
fun > BinaryDecisionDiagram.any(
    predicate: (T) -> Boolean
): Boolean {
    return runOperationAndCatchErrors {
        this.accept(AnyVisitor(predicate))
    }
}

/**
 * Returns true if the [BinaryDecisionDiagram] has at least one variable element.
 */
@JsName("any")
fun > BinaryDecisionDiagram.any(): Boolean {
    return runOperationAndCatchErrors {
        this.any { true }
    }
}

/**
 * Returns a [BinaryDecisionDiagram] containing nodes of applying the given
 * transform function to each element in the original [BinaryDecisionDiagram].
 * The internal structure of the diagram is maintained.
 */
@JsName("map")
fun , E : Comparable> BinaryDecisionDiagram.map(
    mapper: (T) -> E
): BinaryDecisionDiagram {
    val builder = BinaryDecisionDiagramBuilder.reducedOf()
    return runOperationAndCatchErrors {
        this.expansion(
            builder.buildTerminal(false),
            builder.buildTerminal(true)
        ) { node, low, high -> builder.buildVariable(mapper(node), low, high) }
    }
}

/**
 * Formats a [BinaryDecisionDiagram] using Graphviz DOT notation
 * (https://graphviz.org/). This provides a fast and widely supported solution
 * to visualize the contents of a BDD.
 */
@JsName("toDotString")
fun > BinaryDecisionDiagram.toDotString(): String {
    return runOperationAndCatchErrors {
        val checkSet = mutableSetOf()
        val labelBuilder = StringBuilder()
        val graphBuilder = StringBuilder()

        val falseValue = false.hashCode()
        val trueValue = true.hashCode()
        labelBuilder.append("$falseValue [shape=circle, label=\"0\"]\n")
        labelBuilder.append("$trueValue [shape=circle, label=\"1\"]\n")
        this.expansion(falseValue, trueValue) { node, low, high ->
            val nodeValue = Triple(node, low, high).hashCode()
            if (nodeValue !in checkSet) {
                labelBuilder.append(
                    "$nodeValue [shape=record, label=\"$node\"]\n"
                )
                graphBuilder.append("$nodeValue -> $low [style=dashed]\n")
                graphBuilder.append("$nodeValue -> $high\n")
                checkSet.add(nodeValue)
            }
            nodeValue
        }
        "digraph  {\n$labelBuilder$graphBuilder}"
    }
}

/**
 * Returns the number of variable nodes contained in a [BinaryDecisionDiagram].
 */
@JsName("countVariableNodes")
fun > BinaryDecisionDiagram.countVariableNodes(): Int {
    return runOperationAndCatchErrors {
        this.expansion(0, 0) {
                _, low, high ->
            1 + low + high
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy