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

gapt.formats.tip.transformation.ocnfTranformation.scala Maven / Gradle / Ivy

The newest version!
package gapt.formats.tip.transformation

import gapt.formats.tip.analysis.SymbolTable
import gapt.formats.tip.parser.TipSmtAnd
import gapt.formats.tip.parser.TipSmtAssertion
import gapt.formats.tip.parser.TipSmtCase
import gapt.formats.tip.parser.TipSmtDistinct
import gapt.formats.tip.parser.TipSmtEq
import gapt.formats.tip.parser.TipSmtExists
import gapt.formats.tip.parser.TipSmtExpression
import gapt.formats.tip.parser.TipSmtFalse
import gapt.formats.tip.parser.TipSmtForall
import gapt.formats.tip.parser.TipSmtFun
import gapt.formats.tip.parser.TipSmtFunctionDefinition
import gapt.formats.tip.parser.TipSmtGoal
import gapt.formats.tip.parser.TipSmtIdentifier
import gapt.formats.tip.parser.TipSmtImp
import gapt.formats.tip.parser.TipSmtIte
import gapt.formats.tip.parser.TipSmtMatch
import gapt.formats.tip.parser.TipSmtMutualRecursiveFunctionDefinition
import gapt.formats.tip.parser.TipSmtNot
import gapt.formats.tip.parser.TipSmtOr
import gapt.formats.tip.parser.TipSmtProblem
import gapt.formats.tip.parser.TipSmtTrue
import gapt.formats.tip.util.Substitute
import gapt.formats.tip.util.find
import gapt.formats.tip.util.freeVariables

object toOuterConditionalNormalForm extends TipSmtProblemTransformation {
  def transform(problem: TipSmtProblem): TipSmtProblem =
    new TipOcnf(problem)()
}

class TipOcnf(problem: TipSmtProblem) {

  problem.symbolTable = Some(SymbolTable(problem))

  def apply(): TipSmtProblem = {
    val newDefinitions = problem.definitions map { definition =>
      definition match {
        case funDef @ TipSmtFunctionDefinition(_, _, _, _, _) =>
          apply(funDef)
        case goal @ TipSmtGoal(_, _) =>
          goal.copy(expr = tipOcnf(goal.expr))
        case funDefs @ TipSmtMutualRecursiveFunctionDefinition(_) =>
          funDefs.copy(functions = funDefs.functions.map { apply })
        case assertion @ TipSmtAssertion(_, _) =>
          assertion.copy(expr = tipOcnf(assertion.expr))
        case _ => definition
      }
    }
    TipSmtProblem(newDefinitions)
  }

  private def apply(
      fun: TipSmtFunctionDefinition
  ): TipSmtFunctionDefinition = {
    fun.copy(body = tipOcnf(fun.body))
  }

  private def tipOcnf(expression: TipSmtExpression): TipSmtExpression = {
    expression match {
      case expr @ TipSmtAnd(_) =>
        ocnfConnective(AndConnective(expr))
      case expr @ TipSmtOr(_) =>
        ocnfConnective(OrConnective(expr))
      case expr @ TipSmtImp(_) =>
        ocnfConnective(ImpConnective(expr))
      case expr @ TipSmtEq(_) =>
        ocnfConnective(EqConnective(expr))
      case expr @ TipSmtForall(_, _) => ocnfForall(expr)
      case expr @ TipSmtExists(_, _) => ocnfExists(expr)
      case expr @ TipSmtIte(_, _, _) => ocnfIte(expr)
      case expr @ TipSmtMatch(_, _)  => ocnfMatch(expr)
      case expr @ TipSmtFun(_, _) =>
        ocnfConnective(FunConnective(expr))
      case expr @ TipSmtNot(_) => ocnfNot(expr)
      case TipSmtIdentifier(_) => expression
      case TipSmtTrue          => TipSmtTrue
      case TipSmtFalse         => TipSmtFalse
      case TipSmtDistinct(_)   => throw new IllegalArgumentException()
    }
  }

  private def ocnfNot(expression: TipSmtNot): TipSmtExpression = {
    val newSubExpression = tipOcnf(expression.expr)
    newSubExpression match {
      case c @ TipSmtIte(_, _, _) =>
        val newIfTrue = tipOcnf(TipSmtNot(c.ifTrue))
        val newIfFalse = tipOcnf(TipSmtNot(c.ifFalse))
        TipSmtIte(c.cond, newIfTrue, newIfFalse)
      case m @ TipSmtMatch(_, _) =>
        val newCases = m.cases map { c =>
          TipSmtCase(c.pattern, tipOcnf(TipSmtNot(c.expr)))
        }
        TipSmtMatch(m.expr, newCases)
      case _ =>
        TipSmtNot(newSubExpression)
    }
  }

  private def ocnfMatch(expression: TipSmtMatch): TipSmtExpression = {
    val newMatchedExpr = tipOcnf(expression.expr)
    newMatchedExpr match {
      case c @ TipSmtIte(_, _, _) =>
        val newIfTrue = tipOcnf(TipSmtMatch(c.ifTrue, expression.cases))
        val newIfFalse = tipOcnf(TipSmtMatch(c.ifFalse, expression.cases))
        TipSmtIte(c.cond, newIfTrue, newIfFalse)
      case m @ TipSmtMatch(_, _) =>
        val matchExpr = captureAvoiding(m, Seq(expression))
        val newCases = matchExpr.cases map { c =>
          TipSmtCase(
            c.pattern,
            tipOcnf(TipSmtMatch(c.expr, expression.cases))
          )
        }
        TipSmtMatch(matchExpr.expr, newCases)
      case _ =>
        TipSmtMatch(
          newMatchedExpr,
          expression.cases.map { c =>
            TipSmtCase(c.pattern, tipOcnf(c.expr))
          }
        )
    }
  }

  private def ocnfIte(expression: TipSmtIte): TipSmtExpression = {
    val newCond = tipOcnf(expression.cond)
    newCond match {
      case c @ TipSmtIte(_, _, _) =>
        val newIfTrue = tipOcnf(
          TipSmtIte(c.ifTrue, expression.ifTrue, expression.ifFalse)
        )
        val newIfFalse = tipOcnf(
          TipSmtIte(c.ifFalse, expression.ifTrue, expression.ifFalse)
        )
        TipSmtIte(c.cond, newIfTrue, newIfFalse)
      case m @ TipSmtMatch(_, _) =>
        val matchExpr =
          captureAvoiding(m, Seq(expression.ifTrue, expression.ifFalse))
        val newCases = matchExpr.cases map { c =>
          TipSmtCase(
            c.pattern,
            tipOcnf(TipSmtIte(c.expr, expression.ifTrue, expression.ifFalse))
          )
        }
        TipSmtMatch(matchExpr.expr, newCases)
      case _ =>
        TipSmtIte(
          newCond,
          tipOcnf(expression.ifTrue),
          tipOcnf(expression.ifFalse)
        )
    }
  }

  private def ocnfExists(expression: TipSmtExists): TipSmtExpression = {
    TipSmtExists(expression.variables, tipOcnf(expression.formula))
  }

  private def ocnfForall(expression: TipSmtForall): TipSmtExpression = {
    TipSmtForall(expression.variables, tipOcnf(expression.formula))
  }

  private abstract class Connective(
      val subexpressions: Seq[TipSmtExpression]
  ) {
    def toExpression: TipSmtExpression
    def copy(subexpressions: Seq[TipSmtExpression]): TipSmtExpression
  }
  private case class AndConnective(
      tipSmtAnd: TipSmtAnd
  ) extends Connective(tipSmtAnd.exprs) {
    def toExpression = TipSmtAnd(subexpressions)
    def copy(subexpressions: Seq[TipSmtExpression]): TipSmtAnd =
      TipSmtAnd(subexpressions)
  }
  private case class OrConnective(
      tipSmtOr: TipSmtOr
  ) extends Connective(tipSmtOr.exprs) {
    def toExpression = TipSmtOr(subexpressions)
    def copy(subexpressions: Seq[TipSmtExpression]): TipSmtOr =
      TipSmtOr(subexpressions)
  }
  private case class ImpConnective(
      tipSmtImp: TipSmtImp
  ) extends Connective(tipSmtImp.exprs) {
    def toExpression = TipSmtImp(subexpressions)
    def copy(subexpressions: Seq[TipSmtExpression]): TipSmtImp =
      TipSmtImp(subexpressions)
  }
  private case class EqConnective(
      tipSmtEq: TipSmtEq
  ) extends Connective(tipSmtEq.exprs) {
    def toExpression = TipSmtEq(subexpressions)
    def copy(subexpressions: Seq[TipSmtExpression]): TipSmtEq =
      TipSmtEq(subexpressions)
  }
  private case class FunConnective(
      tipSmtFun: TipSmtFun
  ) extends Connective(tipSmtFun.arguments) {
    def toExpression = TipSmtFun(tipSmtFun.name, subexpressions)
    def copy(subexpressions: Seq[TipSmtExpression]): TipSmtFun =
      tipSmtFun.copy(arguments = subexpressions)
  }

  private def ocnfConnective(connective: Connective): TipSmtExpression = {
    val newSubExpressions = connective.subexpressions map tipOcnf
    if (newSubExpressions.exists(_.isInstanceOf[TipSmtIte])) {
      ocnfConnectiveIte(connective, newSubExpressions)
    } else if (newSubExpressions.exists(_.isInstanceOf[TipSmtMatch])) {
      ocnfConnectiveMatch(connective, newSubExpressions)
    } else {
      connective.copy(newSubExpressions)
    }
  }

  private def ocnfConnectiveIte(
      connective: Connective,
      newSubExpressions: Seq[TipSmtExpression]
  ): TipSmtExpression = {
    val Some((left, ite, right)) =
      find(
        newSubExpressions,
        { (expr: TipSmtExpression) => expr.isInstanceOf[TipSmtIte] }
      ): @unchecked

    val TipSmtIte(cond, ifTrue, ifFalse) = ite: @unchecked
    val newIfTrue = connective.copy(left ++ Seq(ifTrue) ++ right)
    val newIfFalse = connective.copy(left ++ Seq(ifFalse) ++ right)
    TipSmtIte(cond, tipOcnf(newIfTrue), tipOcnf(newIfFalse))
  }

  private def ocnfConnectiveMatch(
      connective: Connective,
      newSubExpressions: Seq[TipSmtExpression]
  ): TipSmtExpression = {
    val Some((left, m, right)) =
      find(
        newSubExpressions,
        { (expr: TipSmtExpression) => expr.isInstanceOf[TipSmtMatch] }
      ): @unchecked
    val matchExpr =
      captureAvoiding(m.asInstanceOf[TipSmtMatch], left ++ right)
    val TipSmtMatch(matchedTerm, cases) = matchExpr
    val newCases = cases map {
      cas =>
        TipSmtCase(
          cas.pattern,
          tipOcnf(connective.copy(left ++ Seq(cas.expr) ++ right))
        )
    }
    TipSmtMatch(matchedTerm, newCases)
  }

  private def captureAvoiding(
      tipSmtMatch: TipSmtMatch,
      expressions: Seq[TipSmtExpression]
  ): TipSmtMatch = {
    val blacklist = expressions.flatMap(freeVariables(problem, _))
    TipSmtMatch(
      tipSmtMatch.expr,
      tipSmtMatch.cases map { c =>
        new Substitute(problem).awayFrom(c, blacklist)
      }
    )
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy