/*++
Copyright (c) 2013 Microsoft Corporation

Module Name:

    smt_farkas_util.h

Abstract:

    Utility for combining inequalities using coefficients obtained from Farkas lemmas.
    
Author:

    Nikolaj Bjorner (nbjorne) 2013-11-2.

Revision History:

    NB. This utility is specialized to proofs generated by the arithmetic solvers.

--*/

#pragma once

#include "ast/arith_decl_plugin.h"

namespace smt {

    class farkas_util {
        ast_manager&     m;
        arith_util       a;
        app_ref_vector   m_ineqs;
        vector<rational> m_coeffs;
        rational         m_normalize_factor;
        // utilities for separating coefficients
        bool             m_split_literals;
        unsigned         m_time;
        unsigned_vector  m_roots, m_size, m_his, m_reps, m_ts;

        void mk_coerce(expr*& e1, expr*& e2);
        app* mk_add(expr* e1, expr* e2);
        app* mk_mul(expr* e1, expr* e2);
        app* mk_le(expr* e1, expr* e2);
        app* mk_ge(expr* e1, expr* e2);
        app* mk_gt(expr* e1, expr* e2);
        app* mk_lt(expr* e1, expr* e2);
        void mul(rational const& c, expr* e, expr_ref& res);
        bool is_int_sort(app* c);
        bool is_int_sort();
        void normalize_coeffs();
        app* mk_one();
        app* fix_sign(bool is_pos, app* c);
        void partition_ineqs();
        unsigned find(unsigned idx);
        void merge(unsigned i, unsigned j);
        unsigned process_term(expr* e);
        expr_ref extract_consequence(unsigned lo, unsigned hi);
        void fix_dl(expr_ref& r);

    public:
        farkas_util(ast_manager& m);

        /**
           \brief Reset state
         */
        void reset();

        /** 
            \brief add a multiple of constraint c to the current state 
            Fail if the constraint cannot be classified.
         */
        bool add(rational const & coef, app * c);

        /**
           \brief Extract the complement of premises multiplied by Farkas coefficients.
        */
        expr_ref get();

        /**
           \brief Coefficients are normalized for integer problems.
           Retrieve multiplicant for normalization.
         */
        rational const& get_normalize_factor() const { return m_normalize_factor; }

        /**
           \brief extract one or multiple consequences based on literal partition.
           Multiple consequences are strongst modulo a partition of variables.
           Consequence generation under literal partitioning maintains difference logic constraints.
           That is, if the original constraints are difference logic, then the consequent 
           produced by literal partitioning is also difference logic. 
         */
        void set_split_literals(bool f) { m_split_literals = f; }

    };
}

