1 /*
2 
3  HyPhy - Hypothesis Testing Using Phylogenies.
4 
5  Copyright (C) 1997-now
6  Core Developers:
7  Sergei L Kosakovsky Pond (spond@ucsd.edu)
8  Art FY Poon    (apoon42@uwo.ca)
9  Steven Weaver (sweaver@ucsd.edu)
10 
11  Module Developers:
12  Lance Hepler (nlhepler@gmail.com)
13  Martin Smith (martin.audacis@gmail.com)
14 
15  Significant contributions from:
16  Spencer V Muse (muse@stat.ncsu.edu)
17  Simon DW Frost (sdf22@cam.ac.uk)
18 
19  Permission is hereby granted, free of charge, to any person obtaining a
20  copy of this software and associated documentation files (the
21  "Software"), to deal in the Software without restriction, including
22  without limitation the rights to use, copy, modify, merge, publish,
23  distribute, sublicense, and/or sell copies of the Software, and to
24  permit persons to whom the Software is furnished to do so, subject to
25  the following conditions:
26 
27  The above copyright notice and this permission notice shall be included
28  in all copies or substantial portions of the Software.
29 
30  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
34  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
35  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
36  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 
38  */
39 
40 #ifndef     __FORMULAS__
41 #define     __FORMULAS__
42 
43 #include "baseobj.h"
44 #include "classes.h"
45 #include "defines.h"
46 #include "avllistxl.h"
47 #include "stack.h"
48 #include "operation.h"
49 
50 
51 #include "hy_string_buffer.h"
52 #include "formula_parsing_context.h"
53 
54 class _Variable;
55 class _VariableContainer;
56 class _Polynomial;
57 
58 
59 union       _SimpleFormulaDatum {
60     hyFloat value;
61     hyPointer        reference;
62 };
63 
64 
65 enum _hyFormulaStringConversionMode  {
66   kFormulaStringConversionNormal = 0L,
67   kFormulaStringConversionSubstiteValues = 2L,
68   kFormulaStringConversionReportRanges = 3L
69 };
70 
71 class   _Formula {
72 
73     friend class _Variable;
74     friend class _VariableContainer;
75 
76 protected:
77 
78     unsigned    long    call_count;
79     HBLObjectRef        recursion_calls;
80     _List*              resultCache;
81     _Stack              theStack;
82     _List               theFormula;
83     long*                simpleExpressionStatus;
84     /**
85         SLKP: 20200924
86             Added this shorthand to improve memory locality and speed-up SimpleCompute performance
87             one entry per formula operator with the following values
88                 -1     : constant value
89                 >=0 : reference to variable value
90                    - 2: matrix storage
91                    - 3 : matrix access
92                    - 4 : no shortcut
93                 < -10000:
94                    - HY_OP_CODE : (-10000-HY_OP_CODE for binary operatons)
95                 < -100000:
96                    - HY_OP_CODE (-100000-HY_OP_CODE for unary operatons)
97      */
98 
99     node<long>* theTree; // this formula converted to a tree for operation purposes
100     // such as simplification, differentiation and printing.
101     // trees store numbers referencing operations inside
102     // "theFormula"
103 
104 
105 public:
106     _Formula (void);
107     _Formula (_String const&,_VariableContainer const* theParent=nil,_String* errorString = nil);
108     _Formula (const _Polynomial *);
109 
110     long     ParseFormula (_String const&,_VariableContainer const* theParent=nil,_String* errorString = nil);
111 
112     _Formula (HBLObjectRef, bool isAVar = false);
113     _Formula (_Formula const & rhs);
114     const _Formula & operator = (_Formula const & rhs);
115     virtual ~_Formula (void);
116     HBLObjectRef   Compute             (long = 0, _VariableContainer const* = nil, _List* additionalCacheArguments = nil, _String *errMsg = nil, long object_type = HY_ANY_OBJECT, bool can_cache = true);
117     // compute the value of the formula
118     // 1st argument : execute from this instruction onwards
119     // see the commend for ExecuteFormula for the second argument
120 
121     bool        IsEmpty             (void) const; // is there anything in the formula
122     long        NumberOperations    (void) const; // how many ops in the formula?
123 
124     friend  long        Parse               (_Formula*, _String&, _FormulaParsingContext&, _Formula*);
125     // the main expression parser
126 
127     friend  long        ExecuteFormula      (_Formula*, _Formula*, long, long, _VariableContainer*, char);
128     // the execution block for "compiled formulae
129     /*
130      SLKP 20100119: added an execution name space to allow correct scoping of "pass-by-reference"
131                     arguments when calling ExecuteAFile within a namespace.
132 
133                     e.g. in
134 
135                     function foo (var&)
136                     {
137                         ...
138                     }
139 
140                     foo ("varID");
141 
142                     varID may need to be prefixed by a namespace ID.
143      */
144 
145 
146     _MathObject*ConstructPolynomial (void);
147 
148     virtual void        Initialize          (void);
149     virtual void        Duplicate           (_Formula const *);
150     void        DuplicateReference          (const _Formula*);
151     virtual BaseRef     makeDynamic         (void) const;
152     virtual BaseRef     toStr               (_hyFormulaStringConversionMode mode, _List* matchNames = nil, bool = false);
153     _StringBuffer const     toRPN               (_hyFormulaStringConversionMode mode, _List* matchNames = nil);
154 
155     virtual long        ObjectClass         (void);
156 
157 
158     virtual void        ScanFForVariables   (_AVLList&l, bool includeGlobals = false, bool includeAll = false, bool includeCateg = true, bool skipMatrixAssignments = false, _AVLListX* tagger = nil, long weight = 0) const;
159     virtual void        ScanFForType        (_SimpleList&,  int);
160     /* SLKP 20100716:
161             A simple utility function to retrieve all variables of a given type
162      */
163 
164     virtual bool        CheckFForDependence (long, bool checkAll = false);
165     virtual bool        CheckFForDependence (_AVLList const & indices, bool checkAll = false);
166 
GetList(void)167     _List&      GetList             (void) {
168         return theFormula;
169     }
170 
171     bool        HasChanged          (bool = false); // does  the formula need recomputing
172     bool        HasChangedSimple    (_SimpleList&);
173     bool        EqualFormula        (_Formula*);
174     bool        IsAConstant         (void); //  does this formula include variables, or is it just a constant?
175     bool        IsConstant          (bool strict = false); //  does this formula depend on something other that constants and fixed parameters?
176     bool        DependsOnVariable   (long);
177     bool        IsArrayAccess       (void); // check to see if this formula performs a matrix access
178     /*
179         SLKP 20090315: added a missing utility function
180         given a variable index as an argument, returns true if
181         the formula depends on a it; false otherwise
182     */
183     _Operation* GetIthTerm          (long) const;
184     /*
185         SLKP 20090315: added a missing utility function
186         given an index (i) as the argument, the function retrieves
187         the i-th term of the formula
188     */
189 
190     _Operation* ItemAt          (long) const;
191     /*
192      Same as GetIthTerm, but no range checking
193      */
194 
Length(void)195     unsigned long Length            (void) const {return theFormula.lLength;}
196 
197     void        Clear               (void);
198     HBLObjectRef   GetTheMatrix        (void);
199 
200     void        PushTerm            (BaseRef);
201 
202     /* 20151008: if the argument is a _List, then treat as a list of _Operations and push them onto this formula (increment reference counters as well)
203                  otherwise assume it's a MathObject and push it to this forumla (+1 reference counter)
204                  dynamic_cast is used to determine what type of object this is
205 
206     */
207 
208     bool        AmISimple           (long& stack_depth, _AVLList& variable_index);
209     long        StackDepth          (long start_at = 0L, long end_at = -1L) const;
210       /**
211         starting at operation 'start_at', counting up to 'end_at' (-1 == the end),
212         evaluate how many values would be on the stack after the execution of these commands
213        */
214     bool        ConvertToSimple     (_AVLList& variableIndex);
215     void        ConvertFromSimple   (_AVLList const& variableIndex);
216     void        ConvertFromSimpleList   (_SimpleList const& variableIndex);
217     void        SimplifyConstants   (void);
218     _Variable * Dereference         (bool, _hyExecutionContext* = _hyDefaultExecutionContext);
219 
220     hyFloat  ComputeSimple       (_SimpleFormulaDatum* stack, _SimpleFormulaDatum* varValues) ;
221 
222     hyFloat  Newton              (_Formula&, _Variable*,  hyFloat, hyFloat, hyFloat);
223     hyFloat  Newton              (_Formula&, hyFloat, hyFloat, hyFloat, _Variable*);
224     hyFloat  Newton              (_Variable*,  hyFloat, hyFloat, hyFloat, hyFloat);
225     hyFloat  Newton              (_Variable*,hyFloat, hyFloat, hyFloat);
226 
227     hyFloat  Brent               (_Variable*, hyFloat, hyFloat, hyFloat = 1.e-7, _List* = nil, hyFloat = 0.);
228 
229     hyFloat  Integral            (_Variable*,hyFloat, hyFloat, bool inifinite = false);
230     hyFloat  MeanIntegral        (_Variable*,hyFloat, hyFloat, bool inifinite = false);
231     _Formula*   Differentiate       (_String const&, bool = true, bool convert_from_tree = true);
232     node<long>* InternalDifferentiate
233     (node<long>*, long,_SimpleList const &, _Formula  * const *, _Formula&);
234 
235     bool        InternalSimplify    (node<long>*);
236 
237     void        LocalizeFormula           (_Formula&, _String& parentName, _SimpleList& iv, _SimpleList& iiv, _SimpleList& dv, _SimpleList& idv);
238     void        ConvertMatrixArgumentsToSimpleOrComplexForm (bool);
239     long        ExtractMatrixExpArguments        (_List*);
240 
241     virtual     _Formula const operator + (const _Formula&);
242     virtual     _Formula const operator - (const _Formula&);
243     virtual     _Formula const operator * (const _Formula&);
244     virtual     _Formula const operator / (const _Formula&);
245     virtual     _Formula const operator ^ (const _Formula&);
246 
247     static      _Formula*        PatchFormulasTogether (const _Formula& op1, const _Formula& op2, const char op_code);
248     static      _Formula*        PatchFormulasTogether (const _Formula& op1, HBLObjectRef op2, const char op_code);
249 
250     void        ScanFormulaForHBLFunctions (_AVLListX& collection , bool recursive, bool simplify = true);
251 
252 
253     /** A compute and forget utility function.
254         Parse an expression, optionally check to see that it's of the right type and return the value
255 
256       @param expression : the string to parse
257       @param use_exceptions : if true, throw const _String exceptions, otherwise handle errors directly
258       @param requested_type: return nil if the computed value is not of this type
259       @param formula parsing contrext
260 
261       @return expression value or nil; the value needs to be managed by the caller
262       Revision history
263           20170921 : SLKP initial implementation
264 
265     */
266 
267     static      HBLObjectRef          ParseAndCompute (_String const& expression, bool use_exceptions = false, long requested_type = HY_ANY_OBJECT, _hyExecutionContext * context = nil);
268 
269 
270 protected:
271 
272     void        SubtreeToString     (_StringBuffer & result, node<long>* top_node, int op_level, _List* match_names, _Operation* this_node_op, _hyFormulaStringConversionMode mode = kFormulaStringConversionNormal);
273     void        ConvertToTree       (bool err_msg = true);
274     void        ConvertFromTree     (void);
275     bool        CheckSimpleTerm     (HBLObjectRef);
276     node<long>* DuplicateFormula    (node<long>*,_Formula&) const;
277 
278 
279 };
280 
281 extern _Formula * current_formula_being_computed;
282 
283 #endif
284