Source code for prodigy.pgcl.pgcl_operations

from __future__ import annotations

import copy
import functools
import logging
from typing import Dict, List, Tuple

from prodigy.pgcl import Program, WhileInstr
from prodigy.pgcl.ast import (Binop, BinopExpr, BoolLitExpr, Expr, IfInstr,
                               Instr, NatLitExpr, SkipInstr, VarExpr)

from prodigy.util.logger import log_setup

logger = log_setup(str(__name__).rsplit(".", maxsplit=1)[-1], logging.DEBUG)


[docs] def make_else_if(instructions: List[Tuple[BinopExpr, List[Instr]]]) -> IfInstr: """Creates an else-if chain from a list of conditions and bodies for if-instructions""" outer_instr: IfInstr | None = None curr_instr: IfInstr | None = None for cond, body in instructions: instr = IfInstr(cond=cond, true=body, false=None) if outer_instr is None: outer_instr = instr if curr_instr is not None: curr_instr.false = [instr] curr_instr = instr if curr_instr: curr_instr.false = [SkipInstr()] return outer_instr
[docs] def state_to_equality_expression(state: Dict[str, int]) -> BinopExpr: equalities: List[Expr] = [] for var, val in state.items(): equalities.append( BinopExpr(Binop.EQ, lhs=VarExpr(var), rhs=NatLitExpr(val))) return functools.reduce( lambda expr1, expr2: BinopExpr(Binop.AND, expr1, expr2), equalities, BoolLitExpr(value=True))
[docs] def cav_phi(program: Program, invariant: Program) -> Program: """ The characteristic loop functional. It unrolls a loop exactly once. The result is ``if (G) { B; I } else { skip }`` for a program ``while (G) { B }`` and an invariant program ``I``. Declarations, constants, parameters and functions are taken from the invariant. The instructions are copied, so the result shares no nodes with its inputs. .. returns: A new program object equivalent to one loop unrolling of :param: program. .. raises: ValueError if :param: program is not a single while loop. """ if len(program.instructions) != 1 or not isinstance(program.instructions[0], WhileInstr): raise ValueError("Program can only be one big loop to analyze.") loop = program.instructions[0] logger.debug("Create modified invariant program.") new_instructions = copy.deepcopy(loop.body) + copy.deepcopy(invariant.instructions) guarded_instr = IfInstr(cond=copy.deepcopy(loop.cond), true=new_instructions, false=[SkipInstr()]) return Program(declarations=invariant.declarations, variables=invariant.variables, constants=invariant.constants, parameters=invariant.parameters, instructions=[guarded_instr], functions=invariant.functions)