File: formula_parser.h

package info (click to toggle)
dynare 4.4.3-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 41,356 kB
  • ctags: 15,842
  • sloc: cpp: 77,029; ansic: 29,056; pascal: 13,241; sh: 4,811; objc: 3,061; yacc: 3,013; makefile: 1,479; lex: 1,258; python: 162; lisp: 54; xml: 8
file content (416 lines) | stat: -rw-r--r-- 16,253 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
// Copyright (C) 2005-2011, Ondra Kamenik

#ifndef OGP_FORMULA_PARSER_H
#define OGP_FORMULA_PARSER_H

#include "tree.h"

namespace ogp {
	using std::vector;

	/** Pure virtual class defining a minimal interface for
	 * representation of nulary terms within FormulaParser. */
	class Atoms {
	public:
		Atoms() {}
		virtual ~Atoms() {}
		/** This returns previously assigned internal index to the
		 * given atom, or returns -1 if the atom has not been assigned
		 * yet. The method can raise an exception, if the Atoms
		 * implementation is strict and the name is not among
		 * prescribed possible values. */
		virtual int check(const char* name) const = 0;
		/** This method assigns an internal index to the nulary term
		 * described by the name. The internal index is allocated by
		 * OperationTree class. */
		virtual void assign(const char* name, int t) = 0;
		/** Returns a number of variables which will be used for
		 * differentiations. */
		virtual int nvar() const = 0;
		/** Returns a vector of variable's internal indices which will
		 * be used for differentiations. */
		virtual vector<int> variables() const = 0;
		/** Debug print. */
		virtual void print() const = 0;
	};

	/** Pure virtual class defining interface for all classes able to
	 * set nulary terms to evaluation tree EvalTree. The
	 * implementations of this class will have to be connected with
	 * Atoms to have knowledge about the atoms and their indices in
	 * the tree, and will call EvalTree::set_nulary. */
	class AtomValues {
	public:
		virtual ~AtomValues() {}
		virtual void setValues(EvalTree& et) const = 0;
	};

	class FormulaDerEvaluator;
	class FoldMultiIndex;
	/** For ordering FoldMultiIndex in the std::map. */
	struct ltfmi {
		bool operator()(const FoldMultiIndex& i1, const FoldMultiIndex& i2) const;
	};

	/** This class stores derivatives (tree indices) of one formula
	 * for all orders upto a given one. It stores the derivatives as a
	 * sequence (vector) of these tree indices and sequence of the
	 * multidimensional indices of variables wrt which the derivatives
	 * were taken. In order to speed up querying for a derivative
	 * given the variables, we have a map mapping the multidimensional
	 * index to the order of the derivative in the sequence.
	 * 
	 * The only reason we do not have only this map is that the
	 * iterators of the map do not survive the insertions to the map,
	 * and implementation of the constructor has to be very difficult.
	 */
	class FormulaDerivatives {
		friend class FormulaDerEvaluator;
	protected:
		/** Vector of derivatives. This is a list of derivatives (tree
		 * indices), the ordering is given by the algorithm used to
		 * create it. Currently, it starts with zero-th derivative,
		 * the formula itself and carries with first order, second,
		 * etc. */
		vector<int> tder;
		/** Vector of multiindices corresponding to the vector of
		 * derivatives. */
		vector<FoldMultiIndex> indices;
		/** For retrieving derivatives via a multiindex, we have a map
		 * mapping a multiindex to a derivative in the tder
		 * ordering. This means that indices[ind2der[index]] == index. */
		typedef map<FoldMultiIndex, int, ltfmi> Tfmiintmap;
		Tfmiintmap ind2der;
		/** The number of variables. */
		int nvar;
		/** The maximum order of derivatives. */
		int order;
	public:
		/** The constructor allocates and fills the sequence of the
		 * indices of derivatives for a formula.
		 * @param otree the OperationTree for which all work is done
		 * and to which the derivatives are added.
		 * @param vars the vector of nulary terms in the tree; the
		 * derivatives are taken with respect to these variables in
		 * the ordering given by the vector.
		 * @param f the index of the formula being differentiated. The
		 * zero derivative is set to f.
		 * @param max_order the maximum order of differentiation.
		 */ 
		FormulaDerivatives(OperationTree& otree, const vector<int>& vars, int f, int max_order);
		/** Copy constructor. */
		FormulaDerivatives(const FormulaDerivatives& fd);
		virtual ~FormulaDerivatives(){}
		/** Random access to the derivatives via multiindex. */
		int derivative(const FoldMultiIndex& mi) const;
		/** Return the order. */
		int get_order() const
			{return order;}
		/** Debug print. */
		void print(const OperationTree& otree) const;
	};

	class FormulaEvaluator;

	/** This class is able to parse a number of formulas and
	 * differentiate them. The life cycle of the object is as follows:
	 * After it is created, a few calls to parse will add formulas
	 * (zero derivatives) to the object. Then a method differentiate()
	 * can be called and a vector of pointers to derivatives for each
	 * formula is created. After this, no one should call other
	 * parse() or differentiate(). A const reference of the object can
	 * be used in constructors of FormulaEvaluator and
	 * FormulaDerEvaluator in order to evaluate formulas (zero
	 * derivatives) and higher derivatives resp. */
	class FormulaParser {
		friend class FormulaCustomEvaluator;
		friend class FormulaDerEvaluator;
	protected:
		/** The OperationTree of all formulas, including derivatives. */
		OperationTree otree;
		/** Reference to Atoms. The Atoms are filled with nulary terms
		 * during execution of parse(). */
		Atoms& atoms;
		/** Vector of formulas (zero derivatives) in the order as they
		 * have been parsed. */
		vector<int> formulas;
		/** The vector to derivatives, each vector corresponds to a
		 * formula in the vector formulas. */
		vector<FormulaDerivatives*> ders;
	public:
		/** Construct an empty formula parser. */
		FormulaParser(Atoms& a)
			: atoms(a) {}
		/** Copy constructor using a different instance of Atoms. */
		FormulaParser(const FormulaParser& fp, Atoms& a);
		virtual ~FormulaParser();

		/** Requires an addition of the formula; called from the
		 * parser. */
		void add_formula(int t);
		/** Requires an addition of the binary operation; called from
		 * the parser. */
		int add_binary(code_t code, int t1, int t2);
		/** Requires an addition of the unary operation; called from
		 * the parser. */
		int add_unary(code_t code, int t);
		/** Requires an addition of the nulary operation given by the
		 * string. The Atoms are consulted for uniquness and are given
		 * an internal index generated by the OperationTree. This is
		 * the channel through which the Atoms are filled. */
		int add_nulary(const char* str);

		/** Adds a derivative to the tree. This just calls
		 * OperationTree::add_derivative. */
		int add_derivative(int t, int v)
			{return otree.add_derivative(t, v);}
		/** Adds a substitution. This just calls
		 * OperationTree::add_substitution. */
		int add_substitution(int t, const map<int,int>& subst)
			{return otree.add_substitution(t, subst);}
		/** Add the substitution given by the map where left sides of
		 * substitutions come from another parser. The right sides are
		 * from this object. The given t is from the given parser fp. */
		int add_substitution(int t, const map<int,int>& subst,
							 const FormulaParser& fp)
			{return otree.add_substitution(t, subst, fp.otree);}
		/** This adds formulas from the given parser with (possibly)
		 * different atoms applying substitutions from the given map
		 * mapping atoms from fp to atoms of the object. */
		void add_subst_formulas(const map<int,int>& subst, const FormulaParser& fp);
		/** Substitute formulas. For each i from 1 through all
		 * formulas, it adds a substitution of the i-th formula and
		 * make it to be i-th formula.*/
		void substitute_formulas(const std::map<int,int>& subst);
		/** This method turns the given term to nulary operation. It
		 * should be used with caution, since this method does not
		 * anything do with atoms, but usually some action is also
		 * needed (at leat to assign the tree index t to some
		 * atom). */
		void nularify(int t)
			{otree.nularify(t);}
		/** Returns a set of nulary terms of the given term. Just
		 * calls OperationTree::nulary_of_term. */
		const unordered_set<int>& nulary_of_term(int t) const
			{return otree.nulary_of_term(t);}

		/** Parse a given string containing one or more formulas. The
		 * formulas are parsed and added to the OperationTree and to
		 * the formulas vector. */
		void parse(int length, const char* stream);
		/** Processes a syntax error from bison. */
		void error(const char* mes) const;
		/** Differentiate all the formulas up to the given order. The
		 * variables with respect to which the derivatives are taken
		 * are obtained by Atoms::variables(). If the derivates exist,
		 * they are destroyed and created again (with possibly
		 * different order). */
		void differentiate(int max_order);
		/** Return i-th formula derivatives. */
		const FormulaDerivatives& derivatives(int i) const;

		/** This returns a maximum index of zero derivative formulas
		 * including all nulary terms. This is a mimumum length of the
		 * tree for which it is safe to evaluate zero derivatives of
		 * the formulas. */
		int last_formula() const;
		/** This returns a tree index of the i-th formula in the
		 * vector. */
		int formula(int i) const
			{return formulas[i];}


		/** This returns a tree index of the last formula and pops its
		 * item from the formulas vector. The number of formulas is
		 * then less by one. Returns -1 if there is no formula. If
		 * there are derivatives of the last formula, they are
		 * destroyed and the vector ders is popped from the back. */
		int pop_last_formula();

		/** This returns a number of formulas. */
		int nformulas() const
			{return (int)(formulas.size());}

		/** This returns a reference to atoms. */
		const Atoms& getAtoms() const
			{return atoms;}
		Atoms& getAtoms()
			{return atoms;}
		/** This returns the tree. */
		const OperationTree& getTree() const
			{return otree;}
		OperationTree& getTree()
			{return otree;}

		/** Debug print. */
		void print() const;
	private:
		/** Hide this copy constructor declaration by declaring it as
		 * private. */
		FormulaParser(const FormulaParser& fp);
		/** Destroy all derivatives. */
		void destroy_derivatives();
	};

	/** This is a pure virtual class defining an interface for all
	 * classes which will load the results of formula (zero
	 * derivative) evaluations. A primitive implementation of this
	 * class can be a vector of doubles. */
	class FormulaEvalLoader {
	public:
		virtual ~FormulaEvalLoader() {}
		/** Set the value res for the given formula. The formula is
		 * identified by an index corresponding to the ordering in
		 * which the formulas have been parsed (starting from
		 * zero). */
		virtual void load(int i, double res) = 0;
	};

	/** This class evaluates a selected subset of terms of the
	 * tree. In the protected constructor, one can constraint the
	 * initialization of the evaluation tree to a given number of
	 * terms in the beginning. Using this constructor, one has to make
	 * sure, that the terms in the beginning do not refer to terms
	 * behind the initial part. */
	class FormulaCustomEvaluator {
	protected:
		/** The evaluation tree. */
		EvalTree etree;
		/** The custom tree indices to be evaluated. */
		vector<int> terms;
	public:
		/** Construct from FormulaParser and given list of terms. */
		FormulaCustomEvaluator(const FormulaParser& fp, const vector<int>& ts)
			: etree(fp.otree), terms(ts)
			{}
		/** Construct from OperationTree and given list of terms. */
		FormulaCustomEvaluator(const OperationTree& ot, const vector<int>& ts)
			: etree(ot), terms(ts)
			{}
		/** Evaluate the terms using the given AtomValues and load the
		 * results using the given loader. The loader is called for
		 * each term in the order of the terms. */
		void eval(const AtomValues& av, FormulaEvalLoader& loader);
	protected:
		FormulaCustomEvaluator(const FormulaParser& fp)
			: etree(fp.otree, fp.last_formula()), terms(fp.formulas)
			{}
	};

	/** This class evaluates zero derivatives of the FormulaParser. */
	class FormulaEvaluator : public FormulaCustomEvaluator {
	public:
		/** Construct from FormulaParser. */
		FormulaEvaluator(const FormulaParser& fp)
			: FormulaCustomEvaluator(fp) {}
	};

	/** This is a pure virtual class defining an interface for all
	 * classes which will load the results of formula derivative
	 * evaluations. */
	class FormulaDerEvalLoader {
	public:
		virtual ~FormulaDerEvalLoader() {}
		/** This loads the result of the derivative of the given
		 * order. The semantics of i is the same as in
		 * FormulaEvalLoader::load. The indices of variables with
		 * respect to which the derivative was taken are stored in
		 * memory pointed by vars. These are the tree indices of the
		 * variables. */
		virtual void load(int i, int order, const int* vars, double res) = 0;
	};

	/** This class is a utility class representing the tensor
	 * multindex. It can basically increment itself, and calculate
	 * its offset in the folded tensor. */
	class FoldMultiIndex {
		/** Number of variables. */
		int nvar;
		/** Dimension. */
		int ord;
		/** The multiindex. */
		int* data;
	public:
		/** Initializes to the zero derivative. Order is 0, data is
		 * empty. */
		FoldMultiIndex(int nv);
		/** Initializes the multiindex to zeros or given i. */
		FoldMultiIndex(int nv, int order, int i = 0);
		/** Makes a new multiindex of the same order applying a given
		 * mapping to the indices. The mapping is supposed to be monotone. */
		FoldMultiIndex(int nv, const FoldMultiIndex& mi, const vector<int>& mp);
		/** Shifting constructor. This adds a given number of orders
		 * to the end, copying the last item to the newly added items,
		 * keeping the index ordered. If the index was empty (zero-th
		 * dimension), then zeros are added. */
		FoldMultiIndex(const FoldMultiIndex& fmi, int new_orders);
		/** Copy constructor. */
		FoldMultiIndex(const FoldMultiIndex& fmi);
		/** Desctructor. */
		virtual ~FoldMultiIndex()
			{delete [] data;}
		/** Assignment operator. */
		const FoldMultiIndex& operator=(const FoldMultiIndex& fmi);
		/** Operator < implementing lexicographic ordering within one
		 * order, increasing order across orders. */
		bool operator<(const FoldMultiIndex& fmi) const;
		bool operator==(const FoldMultiIndex& fmi) const;
		/** Increment the multiindex. */
		void increment();
		/** Return offset of the multiindex in the folded tensor. */ 
		int offset() const;
		const int& operator[](int i) const
			{return data[i];}
		/** Return order of the multiindex, i.e. dimension of the
		 * tensor. */ 
		int order() const
			{return ord;}
		/** Return the number of variables. */
		int nv() const
			{return nvar;}
		/** Return the data. */
		const int* ind() const
			{return data;}
		/** Return true if the end of the tensor is reached. The
		 * result of a subsequent increment should be considered
		 * unpredictable. */
		bool past_the_end() const
			{return (ord == 0) || (data[0] == nvar);}
		/** Prints the multiindex in the brackets. */
		void print() const;
	private:
		static int offset_recurse(int* data, int len, int nv);
	};

	/** This class evaluates derivatives of the FormulaParser. */
	class FormulaDerEvaluator {
		/** Its own instance of EvalTree. */
		EvalTree etree;
		/** The indices of derivatives for each formula. This is a
		 * const copy FormulaParser::ders. We do not allocate nor
		 * deallocate anything here. */
		vector<const FormulaDerivatives*> ders;
		/** A copy of tree indices corresponding to atoms to with
		 * respect the derivatives were taken. */
		vector<int> der_atoms;
	public:
		/** Construct the object from FormulaParser. */
		FormulaDerEvaluator(const FormulaParser& fp);
		/** Evaluate the derivatives from the FormulaParser wrt to all
		 * atoms in variables vector at the given AtomValues. The
		 * given loader is used for output. */
		void eval(const AtomValues& av, FormulaDerEvalLoader& loader, int order);
		/** Evaluate the derivatives from the FormulaParser wrt to a
		 * selection of atoms of the atoms in der_atoms vector at the
		 * given AtomValues. The selection is given by a monotone
		 * mapping to the indices (not values) of the der_atoms. */
		void eval(const vector<int>& mp, const AtomValues& av, FormulaDerEvalLoader& loader,
				  int order);
	};
};

#endif

// Local Variables:
// mode:C++
// End: