Пример #1
0
def formulaRekSkolemize(f, variables, subst):
    """
    Perform Skolemization of f, which is assumed to be in the scope of
    the list of variables provided.
    """
    if f.isLiteral():
        child = f.child1.instantiate(subst)
        f = Formula("", child)
    elif f.op == "?":
        var = f.child1
        skTerm = skolemGenerator(variables)
        oldbinding = subst.modifyBinding((var, skTerm))
        f = formulaRekSkolemize(f.child2, variables, subst)
        subst.modifyBinding((var, oldbinding))
    elif f.op == "!":
        var = f.child1
        variables.append(var)
        handle = formulaRekSkolemize(f.child2, variables, subst)
        f = Formula("!", var, handle)
        variables.pop()
    else:
        arg1 = None
        arg2 = None
        if f.hasSubform1():
            arg1 = formulaRekSkolemize(f.child1, variables, subst)
        if f.hasSubform2():
            arg2 = formulaRekSkolemize(f.child2, variables, subst)
        f = Formula(f.op, arg1, arg2)
    return f
Пример #2
0
 def __init__(self, baseline_variable=None):
     self.name = unicode(self.__class__.__name__)
     attr = dict(self.__class__.__dict__)
     self.baseline_variable = baseline_variable
     self.value_type = self.set(attr,
                                'value_type',
                                required=True,
                                allowed_values=VALUE_TYPES.keys())
     self.dtype = VALUE_TYPES[self.value_type]['dtype']
     self.json_type = VALUE_TYPES[self.value_type]['json_type']
     if self.value_type == Enum:
         self.possible_values = self.set(attr,
                                         'possible_values',
                                         required=True,
                                         allowed_type=EnumMeta)
     if self.value_type == str:
         self.max_length = self.set(attr, 'max_length', allowed_type=int)
         if self.max_length:
             self.dtype = '|S{}'.format(self.max_length)
     default_type = self.possible_values if self.value_type == Enum else self.value_type
     self.default_value = self.set(
         attr,
         'default_value',
         allowed_type=default_type,
         default=VALUE_TYPES[self.value_type].get('default'))
     self.entity = self.set(attr,
                            'entity',
                            required=True,
                            setter=self.set_entity)
     self.definition_period = self.set(attr,
                                       'definition_period',
                                       required=True,
                                       allowed_values=(MONTH, YEAR,
                                                       ETERNITY))
     self.label = self.set(attr,
                           'label',
                           allowed_type=basestring,
                           setter=self.set_label)
     self.end = self.set(attr,
                         'end',
                         allowed_type=basestring,
                         setter=self.set_end)
     self.reference = self.set(attr, 'reference', setter=self.set_reference)
     self.cerfa_field = self.set(attr,
                                 'cerfa_field',
                                 allowed_type=(basestring, dict))
     self.unit = self.set(attr, 'unit', allowed_type=basestring)
     self.set_input = self.set_set_input(attr.pop('set_input', None))
     self.calculate_output = self.set_calculate_output(
         attr.pop('calculate_output', None))
     self.is_period_size_independent = self.set(
         attr,
         'is_period_size_independent',
         allowed_type=bool,
         default=VALUE_TYPES[self.value_type]['is_period_size_independent'])
     self.base_function = self.set_base_function(
         attr.pop('base_function', None))
     self.formula = Formula.build_formula_class(attr, self,
                                                baseline_variable)
     self.is_neutralized = False
Пример #3
0
def separateQuantors(f, varlist=None):
    """
    Remove all quantors from f, returning the quantor-free core of the
    formula and a list of quanified variables. This will only be
    applied to Skolemized formulas, thus finding an existential
    quantor is an error. To be useful, the inpt formula also has to be
    variable-normalized.
    """
    if varlist == None:
        varlist = list()

    if f.isQuantified():
        assert f.op == "!"
        varlist.append(f.child1)
        f, dummy = separateQuantors(f.child2, varlist)
    elif f.isLiteral():
        pass
    else:
        arg1 = None
        arg2 = None
        if f.hasSubform1():
            arg1, dummy = separateQuantors(f.child1, varlist)
        if f.hasSubform2():
            arg2, dummy = separateQuantors(f.child2, varlist)
        f = Formula(f.op, arg1, arg2)
    return f, varlist
Пример #4
0
def formulaSimplify(f):
    """
    Exhaustively apply simplification to f. See formulaTopSimplify()
    above for the

    Returns (f', True) if f!=f, (f', False) otherwise.
    """
    if f.isLiteral():
        return f, False

    modified = False

    # First simplify the subformulas
    if f.hasSubform1():
        child1, m = formulaSimplify(f.child1)
        modified |= m
    else:
        child1 = f.child1

    if f.hasSubform2():
        child2, m = formulaSimplify(f.child2)
        modified |= m
    else:
        child2 = None

    if modified:
        f = Formula(f.op, child1, child2)

    topmod = True

    while topmod:
        f, topmod = formulaTopSimplify(f)
        modified |= topmod

    return f, modified
Пример #5
0
def formulaShiftQuantorsOut(f):
    """
    Shift all (universal) quantor to the outermost level.
    """
    f, varlist = separateQuantors(f)

    while varlist:
        f = Formula("!", varlist.pop(), f)

    return f
Пример #6
0
def formulaOpSimplify(f):
    """
    Simplify the formula by eliminating the <=, ~|, ~& and <~>. This
    is not strictly necessary, but means fewer cases to consider
    later. The following rules are applied exhaustively:
    F~|G  -> ~(F|G)
    F~&G  -> ~(F&G)
    F<=G  -> G=>F
    F<~>G -> ~(F<=>G)

    Returns f', modified
    """
    if f.isLiteral():
        return f, False

    modified = False

    # First simplify the subformulas
    if f.hasSubform1():
        child1, m = formulaOpSimplify(f.child1)
        modified |= m
    else:
        child1 = f.child1

    if f.hasSubform2():
        child2, m = formulaOpSimplify(f.child2)
        modified |= m
    else:
        child2 = None

    if modified:
        f = Formula(f.op, child1, child2)

    if f.op == "<~>":
        handle = Formula("<=>", f.child1, f.child2)
        newform = Formula("~", handle)
        return newform, True
    elif f.op == "<=":
        newform = Formula("=>", f.child2, f.child1)
        return newform, True
    elif f.op == "~|":
        handle = Formula("|", f.child1, f.child2)
        newform = Formula("~", handle)
        return newform, True
    elif f.op == "~&":
        handle = Formula("&", f.child1, f.child2)
        newform = Formula("~", handle)
        return newform, True
    return f, modified
Пример #7
0
def formulaVarRename(f, subst=None):
    """
    Rename variables in f so that all bound variables are unique.
    """
    if subst == None:
        subst = Substitution()

    if f.isQuantified():
        # New scope of a variable -> add a new binding to a new
        # variable. Store potential old binding to restore when
        # leaving the scope later
        var = f.child1
        newvar = freshVar()
        oldbinding = subst.modifyBinding((var, newvar))

    if f.isLiteral():
        # Create copy with the new variables recorded in subst
        child = f.child1.instantiate(subst)
        f = Formula("", child)
    else:
        # This is a composite formula. Rename it...
        arg1 = None
        arg2 = None
        if f.isQuantified():
            # Apply new renaming locally to the bound variable and
            # recusively to the subformula
            arg1 = newvar
            arg2 = formulaVarRename(f.child2, subst)
        else:
            # Apply renaming to all subformulas
            if f.hasSubform1():
                arg1 = formulaVarRename(f.child1, subst)
            if f.hasSubform2():
                arg2 = formulaVarRename(f.child2, subst)
        f = Formula(f.op, arg1, arg2)

    if f.isQuantified():
        # We are leaving the scope of the quantifier, so restore
        # substitution.
        subst.modifyBinding((var, oldbinding))

    return f
Пример #8
0
def formulaSimplify(f):
    """
    Exhaustively apply simplification to f, creating the simplified
    version f'. See formulaTopSimplify()
    above for the individual rules.

    Returns (f', True) if f'!=f, (f', False) otherwise (i.e. if no
    simplification happened because the formula already was completely
    simplified.
    """
    if f.isLiteral():
        return f, False

    modified = False

    # First simplify the subformulas
    if f.hasSubform1():
        child1, m = formulaSimplify(f.child1)
        modified |= m
    else:
        child1 = f.child1

    if f.hasSubform2():
        child2, m = formulaSimplify(f.child2)
        modified |= m
    else:
        child2 = None

    if modified:
        f = Formula(f.op, child1, child2)

    topmod = True

    while topmod:
        f, topmod = formulaTopSimplify(f)
        modified |= topmod

    return f, modified
Пример #9
0
def formulaNNF(f, polarity):
    """
    Convert f into a NNF. Equivalences (<=>) are eliminated
    polarity-dependend, top to bottom. Returns (f', m), where f' is a
    NNF of f, and m indicates if f!=f'
    """

    normalform = False
    modified = False

    while not normalform:
        normalform = True
        f, m = rootFormulaNNF(f, polarity)
        modified |= m

        if f.op == "~":
            handle, m = formulaNNF(f.child1, -polarity)
            if m:
                normalform = False
                f = Formula("~", handle)
        elif f.op in ["!", "?"]:
            handle, m = formulaNNF(f.child2, polarity)
            if m:
                normalform = False
                f = Formula(f.op, f.child1, handle)
        elif f.op in ["|", "&"]:
            handle1, m1 = formulaNNF(f.child1, polarity)
            handle2, m2 = formulaNNF(f.child2, polarity)
            m = m1 or m2
            if m:
                normalform = False
                f = Formula(f.op, handle1, handle2)
        else:
            assert f.isLiteral()
        modified |= m

    return f, modified
Пример #10
0
def formulaDistributeDisjunctions(f):
    """
    Convert a Skolemized formula in prefix-NNF form into Conjunctive
    Normal Form.
    """
    arg1 = None
    arg2 = None
    if f.isQuantified():
        arg1 = f.child1
        arg2 = formulaDistributeDisjunctions(f.child2)
        f = Formula(f.op, arg1, arg2)
    elif f.isLiteral():
        pass
    else:
        if f.hasSubform1():
            arg1 = formulaDistributeDisjunctions(f.child1)
        if f.hasSubform2():
            arg2 = formulaDistributeDisjunctions(f.child2)
        f = Formula(f.op, arg1, arg2)
    if f.op == "|":
        if f.child1.op == "&":
            # (P&Q)|R -> (P|R) & (Q|R)
            arg1 = Formula("|", f.child1.child1, f.child2)
            arg2 = Formula("|", f.child1.child2, f.child2)
            f = Formula("&", arg1, arg2)
            f = formulaDistributeDisjunctions(f)
        elif f.child2.op == "&":
            # (R|(P&Q) -> (R|P) & (R|Q)
            arg1 = Formula("|", f.child1, f.child2.child1)
            arg2 = Formula("|", f.child1, f.child2.child2)
            f = Formula("&", arg1, arg2)
            f = formulaDistributeDisjunctions(f)
    return f
Пример #11
0
def formulaMiniScope(f):
    """
    Perform miniscoping, i.e. move quantors in as far as possible, so
    that their scope is only the smallest subformula in which the
    variable occurs.
    """
    res = False
    if f.isQuantified():
        op = f.child2.op
        quant = f.op
        var = f.child1
        subf = f.child2
        if op == "&" or op == "|":
            if not var in subf.child1.collectFreeVars():
                # q[X]:(P op Q)  -> P op (q[X]:Q) if X not free in P
                arg2 = Formula(quant, var, subf.child2)
                arg1 = subf.child1
                f = Formula(op, arg1, arg2)
                res = True
            elif not var in subf.child2.collectFreeVars():
                # q[X]:(P op Q)  -> (q[X]:P) op Q if X not free in Q
                arg1 = Formula(quant, var, subf.child1)
                arg2 = subf.child2
                f = Formula(op, arg1, arg2)
                res = True
            else:
                if op == "&" and quant == "!":
                    # ![X]:(P&Q) -> ![X]:P & ![X]:Q
                    arg1 = Formula("!", var, subf.child1)
                    arg2 = Formula("!", var, subf.child2)
                    f = Formula("&", arg1, arg2)
                    res = True
                elif op == "|" and quant == "?":
                    # ?[X]:(P|Q) -> ?[X]:P | ?[X]:Q
                    arg1 = Formula("?", var, subf.child1)
                    arg2 = Formula("?", var, subf.child2)
                    f = Formula("|", arg1, arg2)
                    res = True
    arg1 = f.child1
    arg2 = f.child2
    modified = False
    if f.hasSubform1():
        arg1, m = formulaMiniScope(f.child1)
        modified |= m
    if f.hasSubform2():
        arg2, m = formulaMiniScope(f.child2)
        modified |= m
    if modified:
        f = Formula(f.op, arg1, arg2)
        f, m = formulaMiniScope(f)
        res = True
    return f, res
Пример #12
0
def rootFormulaNNF(f, polarity):
    """
    Apply all NNF transformation rules that can be applied at top
    level. Return result and modification flag.
    """

    normalform = False
    modified = False

    while not normalform:
        normalform = True
        m = False

        if f.op == "~":
            if f.child1.isLiteral():
                # Move negations into literals
                f = Formula("", f.child1.child1.negate())
                m = True
            elif f.child1.op == "|":
                # De Morgan: ~(P|Q) -> ~P & ~Q
                f = Formula("&", Formula("~", f.child1.child1),
                            Formula("~", f.child1.child2))
                m = True
            elif f.child1.op == "&":
                # De Morgan: ~(P&Q) -> ~P | ~Q
                f = Formula("|", Formula("~", f.child1.child1),
                            Formula("~", f.child1.child2))
                m = True
            elif f.child1.op == "!":
                # ~(![X]:P) -> ?[X]:~P
                f = Formula("?", f.child1.child1,
                            Formula("~", f.child1.child2))
                m = True
            elif f.child1.op == "?":
                # ~(?[X]:P) -> ![X]:~P
                f = Formula("!", f.child1.child1,
                            Formula("~", f.child1.child2))
                m = True
        elif f.op == "=>":
            # Expand P=>Q into ~P|Q
            f = Formula("|", Formula("~", f.child1), f.child2)
            m = True
        elif f.op == "<=>":
            if polarity == 1:
                # P<=>Q -> (P=>Q)&(Q=>P)
                f = Formula("&", Formula("=>", f.child1, f.child2),
                            Formula("=>", f.child2, f.child1))
                m = True
            else:
                assert polarity == -1
                # P<=>Q -> (P & Q) | (~P & ~Q)
                f = Formula(
                    "|", Formula("&", f.child1, f.child2),
                    Formula("&", Formula("~", f.child1),
                            Formula("~", f.child2)))
                m = True

        normalform = not m
        modified |= m
    return f, modified
Пример #13
0
def formulaTopSimplify(f):
    """
    Try to apply the following simplification rules to f at the top
    level. Return (f',m), where f' is the result of simplification,
    and m indicates if f'!=f.
    """
    if f.op == "~":
        if f.child1.isLiteral():
            # Push ~ into literals if possible. This covers the case
            # of ~~P -> P if one of the negations is in the literal.
            return Formula("", f.child1.child1.negate()), True
    elif f.op == "|":
        if f.child1.isPropConst(True):
            # T | P -> T. Note that child1 is $true or
            # equivalent. This applies to several other cases where we
            # can reuse a $true or $false child instead of creating a
            # new formula.
            return f.child1, True
        elif f.child2.isPropConst(True):
            # P | T -> T
            return f.child2, True
        elif f.child1.isPropConst(False):
            # F | P -> P
            return f.child2, True
        elif f.child2.isPropConst(False):
            # P | F -> P
            return f.child1, True
        elif f.child1.isEqual(f.child2):
            # P | P -> P
            return f.child2, True
    elif f.op == "&":
        if f.child1.isPropConst(True):
            # T & P -> P
            return f.child2, True
        elif f.child2.isPropConst(True):
            # P & T -> P
            return f.child1, True
        elif f.child1.isPropConst(False):
            # F & P -> F
            return f.child1, True
        elif f.child2.isPropConst(False):
            # P & F -> F
            return f.child2, True
        elif f.child1.isEqual(f.child2):
            # P & P -> P
            return f.child2, True
    elif f.op == "<=>":
        if f.child1.isPropConst(True):
            # T <=> P -> P
            return f.child2, True
        elif f.child2.isPropConst(True):
            # P <=> T -> P
            return f.child1, True
        elif f.child1.isPropConst(False):
            # P <=> F -> ~P
            newform = Formula("~", f.child2)
            newform, m = formulaSimplify(newform)
            return newform, True
        elif f.child2.isPropConst(False):
            # F <=> P -> ~P
            newform = Formula("~", f.child1)
            newform, m = formulaSimplify(newform)
            return newform, True
        elif f.child1.isEqual(f.child2):
            # P <=> P -> T
            return Formula("", Literal(["$true"])), True
    elif f.op == "=>":
        if f.child1.isPropConst(True):
            # T => P -> P
            return f.child2, True
        elif f.child1.isPropConst(False):
            # F => P -> T
            return Formula("", Literal(["$true"])), True
        elif f.child2.isPropConst(True):
            # P => T -> T
            return Formula("", Literal(["$true"])), True
        elif f.child2.isPropConst(False):
            # P => F -> ~P
            newform = Formula("~", f.child1)
            newform, m = formulaSimplify(newform)
            return newform, True
        elif f.child1.isEqual(f.child2):
            # P => P -> T
            return Formula("", Literal(["$true"])), True
    elif f.op in ["!", "?"]:
        # ![X] F -> F if X is not free in F
        # ?[X] F -> F if X is not free in F
        vars = f.child2.collectFreeVars()
        if not f.child1 in vars:
            return f.child2, True
    else:
        assert f.op == "" or "Unexpected op"
    return f, False