Exemplo n.º 1
0
def literal_to_bounds(f: FNode):
    """
    obtain bounds on variable x from inequality atom
    :param literal: ax + by + c < dx + ey + f
    :param x: variable
    :return: symbolic bound for x, is_lower, k_inclduded

    for example, given literal 3x + 2y + 4 < x + y + 1,
    first move all terms to left hand side: 2x + y + 3 < 0,
    then it returns [-1/2 y - 3/2, False]
    since the literal is equivalent to x < -1/2 y - 3/2
    """
    assert (is_literal(f))
    assert f.is_le() or f.is_lt()
    variables = list(get_real_variables(f))

    k_included = f.is_le()
    f = simplify(f)
    lhs, rhs = f.arg(0), f.arg(1)

    lhs_coef, lhs_const = get_coefficients(lhs), get_constants(lhs)
    rhs_coef, rhs_const = get_coefficients(rhs), get_constants(rhs)
    # move all terms to lhs
    const = simplify(lhs_const - rhs_const)
    coef = dict()
    for v in variables:
        coef[v] = simplify(lhs_coef[v] - rhs_coef[v])

    bounds = dict()
    for v in variables:
        if float(coef[v].constant_value()) == 0:
            continue

        bound_terms = [simplify(const * Real(-1) / coef[v])]
        for w in variables:
            if w == v or float(coef[w].constant_value()) == 0:
                continue
            new_w_coef = simplify(coef[w] * Real(-1) / coef[v])
            bound_terms.append(Times(new_w_coef, w))
        bound = Plus(bound_terms)
        is_lower = coef[v].constant_value() < 0
        bounds[v] = bound, is_lower, k_included

    return bounds
Exemplo n.º 2
0
def atom_to_bound(atom: FNode, x_symbol: FNode):
    """
    obtain bounds on variable x from inequality atom
    :param atom: must be of plus form or a single term on each side
    :param x_symbol:
    :return:
    """
    assert atom.is_le() or atom.is_lt()
    variables = list(get_real_variables(atom))
    if x_symbol not in variables:
        return [atom, NEITHER]

    lhs, rhs = atom.arg(0), atom.arg(1)

    lhs_coef, lhs_const = get_coefficients(lhs), get_constants(lhs)
    rhs_coef, rhs_const = get_coefficients(rhs), get_constants(rhs)

    lhs_x_coef = lhs_coef[x_symbol] if lhs_coef.get(x_symbol) else Real(0)
    rhs_x_coef = rhs_coef[x_symbol] if rhs_coef.get(x_symbol) else Real(0)
    x_coef_diff = simplify(lhs_x_coef - rhs_x_coef)

    assert float(x_coef_diff.constant_value()) != 0
    flag = simplify(x_coef_diff > 0)
    bound = simplify((rhs_const - lhs_const) / x_coef_diff)
    bound_type = UPPER if flag.is_true() else LOWER

    if len(variables) == 1:
        return [bound, bound_type]

    y_symbol = variables[0] if x_symbol == variables[1] else variables[1]
    lhs_y_coef = lhs_coef[y_symbol] if lhs_coef.get(y_symbol) else Real(0)
    rhs_y_coef = rhs_coef[y_symbol] if rhs_coef.get(y_symbol) else Real(0)
    y_coef_diff = simplify(lhs_y_coef - rhs_y_coef)

    if float(y_coef_diff.constant_value()) == 0:
        return [bound, bound_type]

    new_y_coef = simplify(y_coef_diff * Real(-1) / x_coef_diff)
    bound = Plus(bound, Times(new_y_coef, y_symbol))
    return [bound, bound_type]