Source

z3 / src / smt / proto_model / value_factory.h

Full commit
/*++
Copyright (c) 2006 Microsoft Corporation

Module Name:

    value_factory.h

Abstract:

    <abstract>

Author:

    Leonardo de Moura (leonardo) 2008-10-28.

Revision History:

--*/
#ifndef _VALUE_FACTORY_H_
#define _VALUE_FACTORY_H_

#include"ast.h"
#include"obj_hashtable.h"

/**
   \brief Auxiliary object used during model construction.
*/
class value_factory {
protected:
    ast_manager & m_manager;
    family_id     m_fid;
public:
    value_factory(ast_manager & m, family_id fid);

    virtual ~value_factory();

    /**
       \brief Return some value of the given sort. The result is always different from zero.
    */
    virtual expr * get_some_value(sort * s) = 0;

    /**
       \brief Return two distinct values of the given sort. The results are stored in v1 and v2.
       Return false if the intended interpretation of the given sort has only one element. 
    */
    virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) = 0;
    
    /**
       \brief Return a fresh value of the given sort. 
       Return 0 if it is not possible to do that (e.g., the sort is finite).
    */
    virtual expr * get_fresh_value(sort * s) = 0;

    /**
       \brief Used to register that the given value was used in model construction.
       So, get_fresh_value cannot return this value anymore.
    */
    virtual void register_value(expr * n) = 0;

    family_id get_family_id() const { return m_fid; }
};

class basic_factory : public value_factory {
public:
    basic_factory(ast_manager & m);
    
    virtual expr * get_some_value(sort * s);

    virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2);
    
    virtual expr * get_fresh_value(sort * s);

    virtual void register_value(expr * n) { }
};

/**
   \brief Template for value factories for numeric (and enumeration-like) sorts
*/
template<typename Number>
class simple_factory : public value_factory {
protected:
    struct value_set {
        obj_hashtable<expr> m_values;
        Number              m_next;
        value_set():
            m_next(0) {
        }
    };
    
    typedef obj_map<sort, value_set *> sort2value_set;
    
    sort2value_set         m_sort2value_set;
    expr_ref_vector        m_values;
    sort_ref_vector        m_sorts;
    ptr_vector<value_set>  m_sets;

    value_set * get_value_set(sort * s) {
        value_set * set = 0;
        if (!m_sort2value_set.find(s, set)) {
            set = alloc(value_set);
            m_sort2value_set.insert(s, set);
            m_sorts.push_back(s);
            m_sets.push_back(set);
        }
        SASSERT(set != 0);
        DEBUG_CODE({
            value_set * set2 = 0;
            SASSERT(m_sort2value_set.find(s, set2));
            SASSERT(set == set2);
        });
        return set;
    }

    virtual app * mk_value_core(Number const & val, sort * s) = 0;

    app * mk_value(Number const & val, sort * s, bool & is_new) {
        value_set * set = get_value_set(s);
        app * new_val   = mk_value_core(val, s);
        is_new          = false;
        if (!set->m_values.contains(new_val)) {
            m_values.push_back(new_val);
            set->m_values.insert(new_val);
            is_new = true;
        }
        SASSERT(set->m_values.contains(new_val));
        return new_val;
    }

public:
    simple_factory(ast_manager & m, family_id fid):
        value_factory(m, fid),
        m_values(m),
        m_sorts(m) {
    }

    virtual ~simple_factory() {
        std::for_each(m_sets.begin(), m_sets.end(), delete_proc<value_set>());
    }
    
    virtual expr * get_some_value(sort * s) {
        value_set * set = 0;
        expr * result = 0;
        if (m_sort2value_set.find(s, set) && !set->m_values.empty()) 
            result = *(set->m_values.begin());
        else
            result = mk_value(Number(0), s);
        return result;
    }

    virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
        value_set * set = 0;
        if (m_sort2value_set.find(s, set)) {
            switch (set->m_values.size()) {
            case 0:
                v1 = mk_value(Number(0), s);
                v2 = mk_value(Number(1), s);
                break;
            case 1:
                v1 = *(set->m_values.begin());
                v2 = mk_value(Number(0), s);
                if (v1 == v2)
                    v2 = mk_value(Number(1), s);
                break;
            default:
                obj_hashtable<expr>::iterator it = set->m_values.begin();
                v1 = *it;
                ++it;
                v2 = *it;
                break;
            }
            SASSERT(v1 != v2);
            return true;
        }
        v1 = mk_value(Number(0), s);
        v2 = mk_value(Number(1), s);
        return true;
    }

    virtual expr * get_fresh_value(sort * s) {
        value_set * set  = get_value_set(s);
        bool is_new      = false;
        expr * result    = 0;
        Number & next    = set->m_next;
        while (!is_new) {
            result = mk_value(next, s, is_new);
            next++;
        }
        SASSERT(result != 0);
        return result;
    }

    virtual void register_value(expr * n) {
        sort * s = this->m_manager.get_sort(n);
        value_set * set  = get_value_set(s);
        if (!set->m_values.contains(n)) {
            m_values.push_back(n);
            set->m_values.insert(n);
        }
    }
        
    virtual app * mk_value(Number const & val, sort * s) {
        bool is_new;
        return mk_value(val, s, is_new);
    }

    unsigned get_num_sorts() const { return m_sorts.size(); }

    sort * get_sort(unsigned idx) const { return m_sorts.get(idx); }
};

/**
   \brief Factory for creating values for uninterpreted sorts and user
   declared (uninterpreted) sorts.
*/
class user_sort_factory : public simple_factory<unsigned> {
    obj_hashtable<sort>  m_finite;   //!< set of sorts that are marked as finite.
    obj_hashtable<expr>  m_empty_universe;
    virtual app * mk_value_core(unsigned const & val, sort * s);
public:
    user_sort_factory(ast_manager & m);
    virtual ~user_sort_factory() {}

    /**
       \brief Make the universe of \c s finite, by preventing new
       elements to be added to its universe.
    */
    void freeze_universe(sort * s);

    /**
       \brief Return true if the universe of \c s is frozen and finite.
    */
    bool is_finite(sort * s) const {
        return m_finite.contains(s);
    }

    /**
       \brief Return the "known" universe of \c s. It doesn't matter whether
       s is finite or not. If \c s is finite, then it is the whole universe.
    */
    obj_hashtable<expr> const & get_known_universe(sort * s) const;

    /**
       \brief Return sorts with finite interpretations.
    */
    obj_hashtable<sort> const & get_finite_sorts() const { return m_finite; }

    virtual expr * get_some_value(sort * s);

    virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2);

    virtual expr * get_fresh_value(sort * s);
    
    virtual void register_value(expr * n);
};

#endif /* _VALUE_FACTORY_H_ */