// Copyright (C) 2005, Ondra Kamenik // $Id: dynamic_atoms.h 2269 2008-11-23 14:33:22Z michel $ #ifndef OGP_DYNAMIC_ATOMS_H #define OGP_DYNAMIC_ATOMS_H #include "formula_parser.h" #include #include #include #include #include namespace ogp { using std::vector; using std::map; using std::set; using std::string; struct ltstr { bool operator()(const char* a1, const char* a2) const { return strcmp(a1, a2) < 0; } }; /** Class storing names. We will keep names of variables in * various places, and all these pointers will point to one * storage, which will be responsible for allocation and * deallocation. The main function of the class is to allocate * space for names, and return a pointer of the stored name if * required. */ class NameStorage { protected: /** Vector of names allocated, this is the storage. */ vector name_store; /** Map useful to quickly decide if the name is already * allocated or not. */ set name_set; public: NameStorage() {} NameStorage(const NameStorage& stor); virtual ~NameStorage(); /** Query for the name. If the name has been stored, it * returns its address, otherwise 0. */ const char* query(const char* name) const; /** Insert the name if it has not been inserted yet, and * return its new or old allocation. */ const char* insert(const char* name); int num() const {return (int)name_store.size();} const char* get_name(int i) const {return name_store[i];} /** Debug print. */ void print() const; }; class Constants : public AtomValues { public: /** Type for a map mapping tree indices to double values. */ typedef map Tconstantmap; typedef map Tintintmap; protected: /** Map mapping a tree index of a constant to its double value. */ Tconstantmap cmap; public: Constants() {} /** Copy constructor. */ Constants(const Constants& c) : cmap(c.cmap), cinvmap(c.cinvmap) {} /** Copy constructor registering the constants in the given * tree. The mapping from old tree indices to new ones is * traced in tmap. */ Constants(const Constants& c, OperationTree& otree, Tintintmap& tmap) {import_constants(c, otree, tmap);} /** Import constants registering their tree indices in the * given tree. The mapping form old tree indices to new ones * is traced in tmap. */ void import_constants(const Constants& c, OperationTree& otree, Tintintmap& tmap); /** Implements AtomValues interface. This sets the values to * the evaluation tree EvalTree. */ void setValues(EvalTree& et) const; /** This adds a constant with the given tree index. The * constant must be checked previously and asserted that it * does not exist. */ void add_constant(int t, double val); /** Returns true if the tree index is either an hardwired * constant (initial number OperationTree:num_constants in * OperationTree) or the tree index is a registered constant * by add_constant method. */ bool is_constant(int t) const; double get_constant_value(int t) const; /** Return -1 if the given string representation of a constant * is not among the constants (double represenations). If it * is, its tree index is returned. */ int check(const char* str) const; /** Debug print. */ void print() const; const Tconstantmap& get_constantmap() const {return cmap;} private: /** Inverse map to Tconstantmap. */ typedef map Tconstantinvmap; /** This is an inverse map to cmap. This is only used for fast * queries for the existing double constants in check * method and add_constant. */ Tconstantinvmap cinvmap; }; /** This class is a parent to Atoms classes which distinguish between * constants (numerical literals), and variables with lags and * leads. This abstraction does not distinguish between a parameter * and a variable without lag or lead. In this sense, everything is a * variable.*/ class DynamicAtoms : public Atoms, public Constants { public: /** Definition of a type mapping lags to the indices of the variables. */ typedef map Tlagmap; protected: /** Definition of a type mapping names of the atoms to Tlagmap. */ typedef map Tvarmap; /** Definition of a type mapping indices of variables to the variable names. */ typedef map Tindexmap; /** This is just a storage for variable names, since all other * instances of a variable name just point to the memory * allocated by this object. */ NameStorage varnames; /** This is the map for variables. Each variable name is * mapped to the Tlagmap, which maps lags/leads to the nulary * term indices in the tree. */ Tvarmap vars; /** This is almost inverse map to the vars. It maps variable * indices to the names. A returned name can be in turn used * as a key in vars. */ Tindexmap indices; /** Number of variables. */ int nv; /** Minimum lag, if there is at least one lag, than this is a negative number. */ int minlag; /** Maximum lead, if there is at least one lead, than this is a positive number. */ int maxlead; public: /** Construct empty DynamicAtoms. */ DynamicAtoms(); DynamicAtoms(const DynamicAtoms& da); virtual ~DynamicAtoms() {} /** Check the nulary term identified by its string * representation. The nulary term can be either a constant or * a variable. If constant, -1 is returned so that it could be * assigned regardless if the same constant has already * appeared or not. If variable, then -1 is returned only if * the variable has not been assigned an index, otherwise the * assigned index is returned. */ int check(const char* name) const; /** Assign the nulary term identified by its string * representation. This method should be called when check() * returns -1. */ void assign(const char* name, int t); /** Return a number of all variables. */ int nvar() const { return nv; } /** Return the vector of variable indices. */ vector variables() const; /** Return max lead and min lag for a variable given by the * index. If a variable cannot be found, the method retursn * the smallest integer as maxlead and the largest integer as * minlag. */ void varspan(int t, int& mlead, int& mlag) const; /** Return max lead and min lag for a variable given by the * name (without lead, lag). The same is valid if the variable * name cannot be found. */ void varspan(const char* name, int& mlead, int& mlag) const; /** Return max lead and min lag for a vector of variables given by the names. */ void varspan(const vector& names, int& mlead, int& mlag) const; /** Return true for all tree indices corresponding to a * variable in the sense of this class. (This is parameters, * exo and endo). Since the semantics of 'variable' will be * changed in subclasses, we use name 'named atom'. These are * all atoms but constants. */ bool is_named_atom(int t) const; /** Return index of the variable described by the variable * name and lag/lead. If it doesn't exist, return -1. */ int index(const char* name, int ll) const; /** Return true if a variable is referenced, i.e. it has lag * map. */ bool is_referenced(const char* name) const; /** Return the lag map for the variable name. */ const Tlagmap& lagmap(const char* name) const; /** Return the variable name for the tree index. It throws an * exception if the tree index t is not a named atom. */ const char* name(int t) const; /** Return the lead/lag for the tree index. It throws an * exception if the tree index t is not a named atom. */ int lead(int t) const; /** Return maximum lead. */ int get_maxlead() const {return maxlead;} /** Return minimum lag. */ int get_minlag() const {return minlag;} /** Return the name storage to allow querying to other * classes. */ const NameStorage& get_name_storage() const {return varnames;} /** Assign the variable with a given lead. The varname must be * from the varnames storage. The method checks if the * variable iwht the given lead/lag is not assigned. If so, an * exception is thrown. */ void assign_variable(const char* varname, int ll, int t); /** Unassign the variable with a given lead and given tree * index. The tree index is only provided as a check. An * exception is thrown if the name, ll, and the tree index t * are not consistent. The method also updates nv, indices, * maxlead and minlag. The varname must be from the varnames * storage. */ void unassign_variable(const char* varname, int ll, int t); /** Debug print. */ void print() const; protected: /** Do the check for the variable. A subclass may need to * reimplement this so that it could raise an error if the * variable is not among a given list. */ virtual int check_variable(const char* name) const; /** Assign the constant. */ void assign_constant(const char* name, int t); /** Assign the variable. */ void assign_variable(const char* name, int t); /** The method just updates minlag or/and maxlead. Note that * when assigning variables, the update is done when inserting * to the maps, however, if removing a variable, we need to * call this method. */ void update_minmaxll(); /** The method parses the string to recover a variable name * and lag/lead ll. The variable name doesn't contain a lead/lag. */ virtual void parse_variable(const char* in, string& out, int& ll) const = 0; public: /** Return true if the str represents a double.*/ static bool is_string_constant(const char* str); }; /** This class is a parent of all orderings of the dynamic atoms * of variables which can appear before t, at t, or after t. It * encapsulates the ordering, and the information about the number * of static (appearing only at time t) predetermined (appearing * before t and possibly at t), both (appearing before t and after * t and possibly at t) and forward looking (appearing after t and * possibly at t). * * The constructor takes a list of variable names. The class also * provides mapping from the ordering of the variables in the list * (outer) to the new ordering (at time t) and back. * * The user of the subclass must call do_ordering() after * initialization. * * The class contains a few preimplemented methods for * ordering. The class is used in this way: Make a subclass, and * implement pure virtual do_ordering() by just plugging a * preimplemented method, or plugging your own implementation. The * method do_ordering() is called by the user after the constructor. */ class VarOrdering { protected: /** Number of static variables. */ int n_stat; /** Number of predetermined variables. */ int n_pred; /** Number of both variables. */ int n_both; /** Number of forward looking variables. */ int n_forw; /** This is a set of tree indices corresponding to the * variables at all times as they occur in the formulas. In * fact, since this is used only for derivatives, the ordering * of this vector is only important for ordering of the * derivatives, in other contexts the ordering is not * important, so it is rather a set of indices.*/ vector der_atoms; /** This maps tree index of the variable to the position in * the row of the ordering. One should be careful with making * space in the positions for variables not appearing at time * t. For instance in the pred(t-1), both(t-1), stat(t), * pred(t), both(t), forw(t), both(t+1), forw(t+1) ordering, * the variables x(t-1), y(t-1), x(t+1), z(t-1), z(t), and * z(t+1) having tree indices 6,5,4,3,2,1 will be ordered as * follows: y(t-1), x(t-1), z(t-1), [y(t)], [x(t)], z(t), * x(t+1), where a bracketed expresion means non-existent by * occupying a space. The map thus will look as follows: * {5->0, 6->1, 3->2, 2->5, 3->6}. Note that nothing is mapped * to positions 3 and 4. */ map positions; /** This maps an ordering of the list of variables in * constructor to the new ordering (at time t). The length is * the number of variables. */ vector outer2y; /** This maps a new ordering to the ordering of the list of * variables in constructor (at time t). The length is the * number of variables. */ vector y2outer; /** This is just a reference for variable names to keep it * from constructor to do_ordering() implementations. */ const vector& varnames; /** This is just a reference to atoms to keep it from * constructor to do_ordering() implementations. */ const DynamicAtoms& atoms; public: /** This is an enum type for an ordering type implemented by * do_general. */ enum ord_type {pbspbfbf, bfspbfpb}; /** Construct the ordering of the variables given by the names * with their dynamic occurrences defined by the atoms. It * calls the virtual method do_ordering which can be * reimplemented. */ VarOrdering(const vector& vnames, const DynamicAtoms& a) : n_stat(0), n_pred(0), n_both(0), n_forw(0), varnames(vnames), atoms(a) {} VarOrdering(const VarOrdering& vo, const vector& vnames, const DynamicAtoms& a); virtual VarOrdering* clone(const vector& vnames, const DynamicAtoms& a) const = 0; /** Destructor does nothing here. */ virtual ~VarOrdering() {} /** This is the method setting the ordering and the map. A * subclass must reimplement it, possibly using a * preimplemented ordering. This method must be called by the * user after the class has been created. */ virtual void do_ordering() = 0; /** Return number of static. */ int nstat() const {return n_stat;} /** Return number of predetermined. */ int npred() const {return n_pred;} /** Return number of both. */ int nboth() const {return n_both;} /** Return number of forward looking. */ int nforw() const {return n_forw;} /** Return the set of tree indices for derivatives. */ const vector& get_der_atoms() const {return der_atoms;} /** Return the y2outer. */ const vector& get_y2outer() const {return y2outer;} /** Return the outer2y. */ const vector& get_outer2y() const {return outer2y;} /** Query the atom given by the tree index. True is returned * if the atom is one of the variables in the object. */ bool check(int t) const; /** Return the position of the atom (nulary term) given by a * tree index. It is a lookup to the map. If the atom cannot * be found, the exception is raised. */ int get_pos_of(int t) const; /** This returns a length of ordered row of atoms. In all * cases so far, it does not depend on the ordering and it is * as follows. */ int length() const {return n_stat+2*n_pred+3*n_both+2*n_forw;} /** Debug print. */ void print() const; protected: /** This is a general ordering method which orders the * variables by the given ordering ord_type. See documentation * for respective do_ methods. */ void do_general(ord_type ordering); /** This is a preimplemented ordering for do_ordering() * method. It assumes that the variables appear only at time * t-1, t, t+1. It orders the atoms as pred(t-1), both(t-1), * stat(t), pred(t), both(t), forw(t), both(t+1), * forw(t+1). It builds the der_atoms, the map of positions, * as well as y2outer and outer2y. */ void do_pbspbfbf() {do_general(pbspbfbf);} /** This is a preimplemented ordering for do_ordering() * method. It assumes that the variables appear only at time * t-1, t, t+1. It orders the atoms as both(t+1), forw(t+1), * stat(t), pred(t), both(t), forw(t), pred(t-1), * both(t-1). It builds the der_atoms, the map of positions, * as well as y2outer and outer2y. */ void do_bfspbfpb() {do_general(bfspbfpb);} /** This is a preimplemented ordering for do_ordering() * method. It makes no assumptions about occurences of * variables at different times. It orders the atoms with * increasing time keeping the given ordering within one * time. This implies that y2outer and outer2y will be * identities. The der_atoms will be just a sequence of atoms * from the least to the most time preserving the order of atoms * within one time. */ void do_increasing_time(); private: /** Declare this copy constructor as private to hide it. */ VarOrdering(const VarOrdering& vo); }; }; #endif // Local Variables: // mode:C++ // End: