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

hu.bme.mit.theta.xsts.analysis.util.RandomXsts.kt Maven / Gradle / Ivy

There is a newer version: 6.5.2
Show newest version
/*
 *  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.analysis.util

import hu.bme.mit.theta.core.decl.Decls
import hu.bme.mit.theta.core.decl.VarDecl
import hu.bme.mit.theta.core.stmt.*
import hu.bme.mit.theta.core.type.Expr
import hu.bme.mit.theta.core.type.Type
import hu.bme.mit.theta.core.type.booltype.BoolExprs
import hu.bme.mit.theta.core.type.booltype.BoolType
import hu.bme.mit.theta.core.type.inttype.IntExprs
import hu.bme.mit.theta.core.type.inttype.IntType
import hu.bme.mit.theta.core.utils.ExprUtils
import hu.bme.mit.theta.xsts.XSTS
import kotlin.random.Random

@JvmOverloads
fun generateXsts(seed: Int, numCtrl: Int = 1, numClock: Int = 1, numOther: Int = 3,
    requireAllVarsWritten: Boolean = false): XSTS {
    val writtenVars = object : StmtVisitor>, Set>> {
        override fun visit(stmt: SkipStmt?, param: Set>): Set> {
            return param
        }

        override fun visit(stmt: AssumeStmt?, param: Set>): Set> {
            return param
        }

        override fun  visit(stmt: AssignStmt, param: Set>): Set> {
            return setOf(stmt.varDecl) + param
        }

        override fun  visit(stmt: HavocStmt, param: Set>): Set> {
            return setOf(stmt.varDecl) + param
        }

        override fun visit(stmt: SequenceStmt, param: Set>): Set> {
            var res = param
            for (s in stmt.stmts) {
                res = s.accept(this, setOf())
            }
            return res
        }

        override fun visit(stmt: NonDetStmt, param: Set>): Set> {
            var res = param
            for (s in stmt.stmts) {
                res = s.accept(this, setOf())
            }
            return res
        }

        override fun visit(stmt: OrtStmt?, param: Set>?): Set> {
            TODO("Not yet implemented")
        }

        override fun visit(stmt: LoopStmt, param: Set>): Set> {
            return stmt.stmt.accept(this, param)
        }

        override fun visit(stmt: IfStmt, param: Set>): Set> {
            return stmt.then.accept(this, stmt.elze.accept(this, param))
        }

        override fun  visit(
            stmt: MemoryAssignStmt?, param: Set>?): Set> {
            TODO("Not yet implemented")
        }

    }

    val all = numCtrl + numOther + numClock
    val xsts = RandomXsts(seed, 3).generateRandomXsts(10, numCtrl, numClock, numOther) {
        if (requireAllVarsWritten) {
            val decls = it.tran.accept(writtenVars, setOf())
            decls.size == all // all vars are written
        } else {
            true
        }
    }
    return xsts
}

class RandomXsts(seed: Int, val exprMaxDepth: Int) {

    lateinit var ctrlVars: List>
    lateinit var otherVars: List>
    lateinit var boolVars: List>
    lateinit var clockVars: List>
    lateinit var intVars: List>

    val random = Random(seed)

    fun generateRandomXsts(
        depth: Int,
        numCtrl: Int,
        numClock: Int,
        numOther: Int,
        constraint: (XSTS) -> Boolean
    ): XSTS {
        var xsts: XSTS
        do {
            val trans = generateRandomStmt(depth, numCtrl, numClock, numOther)
            val env = Stmts.NonDetStmt(listOf(Stmts.Skip()))
            val init = Stmts.NonDetStmt(listOf(Stmts.Skip()))
            val initExpr = BoolExprs.And(
                ctrlVars.map { IntExprs.Eq(it.ref, IntExprs.Int(0)) }
                    + boolVars.map { BoolExprs.Not(it.ref) }
                    + intVars.map { IntExprs.Eq(it.ref, IntExprs.Int(0)) }
            )
            var expr: Expr
            do expr = randomBoolExpr(0)
            while (ExprUtils.getVars(expr).isEmpty())
            xsts = XSTS(
                ctrlVars.toSet(),
                init, NonDetStmt.of(listOf(trans)), env, initExpr, expr
            )
        } while (!(constraint(xsts)))
        return xsts
    }

    fun generateRandomStmt(depth: Int, numCtrl: Int, numClock: Int, numOther: Int): Stmt {
        var i = 2
        ctrlVars = Array(numCtrl) { Decls.Var("ctlr${i++}", IntType.getInstance()) }.toList()
        do {
            otherVars = listOf(
                Decls.Var("var0", IntType.getInstance()) as VarDecl,
                Decls.Var("var1", BoolType.getInstance()) as VarDecl,
            ) + Array(numOther - 2) { randomVar("var${i++}") }.toList()
        } while (otherVars.all { it.type is IntType } || otherVars.all { it.type is BoolType })
        boolVars = otherVars.filter { it.type is BoolType }.map { it as VarDecl }
        intVars = otherVars.filter { it.type is IntType }.map { it as VarDecl }
        clockVars = Array(numClock) { Decls.Var("clock${i++}", IntType.getInstance()) }.toList()

        return randomIntermediate(0, depth)
    }

    fun randomVar(name: String): VarDecl {
        return listOf(
            { Decls.Var(name, IntType.getInstance()) as VarDecl },
            { Decls.Var(name, BoolType.getInstance()) as VarDecl }
        ).random(random)()
    }

    fun randomIntermediate(currDepth: Int, maxDepth: Int): Stmt {
        if (currDepth == maxDepth) return randomLeaf()
        return listOf(
            { randomLeaf() },
            { randomSeq(currDepth + 1, maxDepth) },
            { randomNonDet(currDepth + 1, maxDepth) },
            { randomIf(currDepth + 1, maxDepth) },
//                { randomLoop(currDepth + 1, maxDepth) },
        ).random(random)()
    }

    fun randomLeaf(): Stmt {
        return listOf(
//            { Stmts.Skip() },
            { randomAssign() },
            { randomAssign() },
            { randomAssume() },
//                { randomHavoc() },
        ).random(random)()
    }

    fun randomSeq(currDepth: Int, maxDepth: Int): Stmt {
        return Stmts.SequenceStmt(listOf(
            randomIntermediate(currDepth + 1, maxDepth),
            randomIntermediate(currDepth + 1, maxDepth)
        ))
    }

    fun randomNonDet(currDepth: Int, maxDepth: Int): Stmt {
        return Stmts.NonDetStmt(listOf(
            randomIntermediate(currDepth + 1, maxDepth),
            randomIntermediate(currDepth + 1, maxDepth)
        ))

    }

    fun randomIf(currDepth: Int, maxDepth: Int): Stmt {
        var expr: Expr
        do expr = randomBoolExpr(0)
        while (ExprUtils.getVars(expr).isEmpty())
        return IfStmt.of(expr,
            randomIntermediate(currDepth + 1, maxDepth),
            randomIntermediate(currDepth + 1, maxDepth)
        )
    }

    fun randomBoolExpr(currDepth: Int): Expr {
        return (if (currDepth == exprMaxDepth)
            listOf(
                { BoolExprs.True() },
                { boolVars[random.nextInt((boolVars.size))].ref },
            ).random(random)
        else
            listOf(
                { BoolExprs.True() },
                { boolVars[random.nextInt((boolVars.size))].ref },
                { BoolExprs.Not(randomBoolExpr(currDepth + 1)) },
                {
                    BoolExprs.And(
                        randomBoolExpr(currDepth + 1),
                        randomBoolExpr(currDepth + 1)
                    )
                },
                {
                    BoolExprs.Or(
                        randomBoolExpr(currDepth + 1),
                        randomBoolExpr(currDepth + 1))
                },
                { BoolExprs.Imply(randomBoolExpr(currDepth + 1), randomBoolExpr(currDepth + 1)) },
                { BoolExprs.Iff(randomBoolExpr(currDepth + 1), randomBoolExpr(currDepth + 1)) },
                { BoolExprs.Xor(randomBoolExpr(currDepth + 1), randomBoolExpr(currDepth + 1)) },
                { IntExprs.Eq(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
                { IntExprs.Geq(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
                { IntExprs.Leq(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
                { IntExprs.Lt(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
                { IntExprs.Gt(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
                { IntExprs.Neq(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
            ).random(random))()
    }


    fun randomIntExpr(currDepth: Int): Expr {
        return (if (currDepth == exprMaxDepth)
            listOf(
                { IntExprs.Int(random.nextInt(5)) },
                { intVars[random.nextInt((intVars.size))].ref },
            ).random(random)
        else
            listOf(
                { IntExprs.Int(random.nextInt(5)) },
                { intVars[random.nextInt((intVars.size))].ref },
                { IntExprs.Neg(randomIntExpr(currDepth + 1)) },
                { IntExprs.Add(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
                { IntExprs.Mul(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
                { IntExprs.Sub(randomIntExpr(currDepth + 1), randomIntExpr(currDepth + 1)) },
            ).random(random))()
    }

    fun randomLoop(currDepth: Int, maxDepth: Int): Stmt {
        return LoopStmt.of(randomIntermediate(currDepth + 1, maxDepth), ctrlVars.random(random),
            IntExprs.Int(0),
            randomIntExpr(0) { ctrlVars.containsAll(ExprUtils.getVars(it)) }
        )
    }

    fun randomAssign(): Stmt {
        return (listOf(
            {
                val v = otherVars.random(random)
                when (v.type) {
                    is IntType -> Stmts.Assign(v as VarDecl,
                        randomIntExpr { ExprUtils.getVars(it).size > 0 && it != v.ref })

                    is BoolType -> Stmts.Assign(v as VarDecl,
                        randomBoolExpr { ExprUtils.getVars(it).size > 0 && it != v.ref })

                    else -> throw Exception()
                }
            },
            { Stmts.Assign(ctrlVars.random(random), randomIntExpr(0)) },
        ) + (if (clockVars.isEmpty()) listOf() else listOf({ randomClockReset() }))).random(random)()
    }

    fun randomIntExpr(currDepth: Int = 0, constraint: (Expr) -> Boolean): Expr {
        var res: Expr
        do {
            res = randomIntExpr(currDepth)
        } while (!(constraint(res)))
        return res
    }

    fun randomBoolExpr(currDepth: Int = 0, constraint: (Expr) -> Boolean): Expr {
        var res: Expr
        do {
            res = randomBoolExpr(currDepth)
        } while (!(constraint(res)))
        return res
    }

    fun randomAssume() = (listOf(this::randomDataAssume) + (if (clockVars.isEmpty()) listOf() else listOf(
        this::randomClockConstraint))).random(random)()

    fun randomDataAssume(): Stmt {
        var expr: Expr
        do expr = randomBoolExpr(0)
        while (ExprUtils.getVars(expr).isEmpty())

        return Stmts.Assume(expr)
    }

    fun randomClockReset(): Stmt {
        val c = clockVars.random(random)
        val resetTo = IntExprs.Int(random.nextInt(4))
        return Stmts.Assign(c, resetTo)
    }

    fun randomClockConstraint(): Stmt {
        val c = if (clockVars.size == 1) clockVars[0].ref else listOf(
            { clockVars.random(random).ref },
            {
                val c1 = clockVars.random(random)
                val c2 = (clockVars - listOf(c1)).random()
                IntExprs.Sub(c1.ref, c2.ref)
            }
        ).random()()

        val compareTo = IntExprs.Int(random.nextInt(10))
        return Stmts.Assume(listOf(
            { IntExprs.Leq(c, compareTo) },
            { IntExprs.Lt(c, compareTo) },
            { IntExprs.Geq(c, compareTo) },
            { IntExprs.Gt(c, compareTo) },
            { IntExprs.Eq(c, compareTo) },
        ).random(random)())
    }

    fun randomHavoc(): Stmt {
        return Stmts.Havoc((otherVars + clockVars).random(random))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy