1 /*
2 
3  HyPhy - Hypothesis Testing Using Phylogenies.
4 
5  Copyright (C) 1997-now
6  Core Developers:
7  Sergei L Kosakovsky Pond (sergeilkp@icloud.com)
8  Art FY Poon    (apoon42@uwo.ca)
9  Steven Weaver (sweaver@temple.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 #include "defines.h"
41 #include "variablecontainer.h"
42 #include "operation.h"
43 
44 #include "likefunc.h"
45 #include "parser.h"
46 #include "polynoml.h"
47 #include "batchlan.h"
48 
49 #include "global_object_lists.h"
50 #include "global_things.h"
51 
52 #include "function_templates.h"
53 
54 
55 using namespace hy_global;
56 using namespace hyphy_global_objects;
57 
58 
59 //__________________________________________________________________________________
60 
_VariableContainer(void)61 _VariableContainer::_VariableContainer (void) : theParent(nil), theModel (-1L), iVariables(nil), dVariables(nil), gVariables(nil){
62  }
63 
64 //__________________________________________________________________________________
65 
Duplicate(BaseRefConst theO)66 void    _VariableContainer::Duplicate (BaseRefConst theO) {
67     _Variable::Duplicate (theO);
68     _VariableContainer const *theVC = (_VariableContainer const*)theO;
69     theParent= theVC->theParent;
70     theModel = theVC->theModel;
71     if (theVC->iVariables) {
72         if (iVariables) {
73             iVariables->Clear();
74         } else {
75             iVariables = new _SimpleList;
76         }
77         iVariables->Duplicate (theVC->iVariables);
78     } else {
79         if (iVariables) {
80             delete (iVariables);
81             iVariables = nil;
82         }
83     }
84     if (theVC->dVariables) {
85         if (dVariables) {
86             dVariables->Clear();
87         } else {
88             dVariables = new _SimpleList;
89         }
90         dVariables->Duplicate (theVC->dVariables);
91     } else {
92         if (dVariables) {
93             delete (dVariables);
94             dVariables = nil;
95         }
96     }
97     if (theVC->gVariables) {
98         if (gVariables) {
99             gVariables->Clear();
100         } else {
101             gVariables = new _SimpleList;
102         }
103         gVariables->Duplicate (theVC->gVariables);
104     } else {
105         if (gVariables) {
106             delete (gVariables);
107             gVariables = nil;
108         }
109     }
110 }
111 
112 
113 //__________________________________________________________________________________
114 
TrimMemory()115 void    _VariableContainer::TrimMemory () {
116     _SimpleList* var_arrays [3] = {iVariables,dVariables,gVariables};
117     for (_SimpleList* an_array : var_arrays) {
118         if (an_array) {
119             an_array->TrimMemory();
120         }
121     }
122 }
123 
124 //__________________________________________________________________________________
125 
makeDynamic(void) const126 BaseRef _VariableContainer::makeDynamic (void) const {
127     _VariableContainer * res = new _VariableContainer;
128     res->Duplicate(this);
129     return res;
130 }
131 
132 //__________________________________________________________________________________
133 
toStr(unsigned long)134 BaseRef _VariableContainer::toStr (unsigned long) {
135     _StringBuffer * res = new _StringBuffer (128L);
136 
137     (*res) << "Container Class:" << theName << ":{ Independent Variables:";
138 
139     if (iVariables)
140         for (long i = 0L; i<iVariables->lLength; i+=2L) {
141             res->AppendNewInstance ((_String*)variablePtrs(iVariables->list_data[i])->toStr());
142 
143             if (i<iVariables->lLength-2) {
144                 (*res) << ',';
145             }
146 
147         }
148 
149     (*res) << "; Dependent Variables:";
150 
151     if (dVariables)
152         for (long i2 = 0L; i2<dVariables->lLength; i2+=2L) {
153             res->AppendNewInstance ((_String*)variablePtrs(dVariables->list_data[i2])->toStr());
154             if (i2<dVariables->lLength-2) {
155                 (*res) << ',';
156             }
157         }
158 
159     (*res) << '}';
160     res->TrimSpace();
161     return res;
162 }
163 
164 //__________________________________________________________________________________
165 
_VariableContainer(_String const & theName,_String theTmplt,_VariableContainer * theP)166 _VariableContainer::_VariableContainer (_String const & theName, _String theTmplt, _VariableContainer* theP) : iVariables(nil), dVariables(nil), gVariables(nil) {
167     _VariableContainer::InitializeVarCont (theName, theTmplt,theP);
168 }
169 
170 //__________________________________________________________________________________
171 
HasExplicitFormModel(void) const172 bool _VariableContainer::HasExplicitFormModel (void) const {
173     if (theModel == -1L) {
174         return false;
175     }
176     return (modelTypeList.list_data[theModel]);
177 }
178 
179 //__________________________________________________________________________________
180 
GetExplicitFormModel(void) const181 _Formula* _VariableContainer::GetExplicitFormModel (void) const {
182     if (theModel < 0L) {
183         return nil;
184     }
185     if (modelTypeList.list_data[theModel]) { // an explicit formula based matrix
186         return (_Formula*)modelMatrixIndices.list_data[theModel];
187     }
188     return nil;
189 }
190 
191 //__________________________________________________________________________________
192 
GetModelName(void) const193 _String const* _VariableContainer::GetModelName (void)  const{
194     _String const * res = GetObjectNameByType (HY_BL_MODEL, theModel, false);
195     if (res) {
196         return res;
197     }
198     return &kEmptyString;
199 }
200 
201 //__________________________________________________________________________________
202 
GetModelMatrix(_List * queue,_SimpleList * tags) const203 _Matrix* _VariableContainer::GetModelMatrix (_List* queue, _SimpleList* tags) const {
204     if (theModel < 0L) {
205         return nil;
206     }
207 
208     if (modelTypeList.list_data[theModel]) { // an explicit formula based matrix
209         if (queue && tags) {
210             long currentQueueLength = ((_Formula*)modelMatrixIndices.list_data[theModel])->ExtractMatrixExpArguments (queue);
211             if (currentQueueLength) {
212                 for (unsigned long k = 0; k < currentQueueLength; k++)
213                   (*tags) << currentQueueLength;
214                 return nil;
215             }
216         }
217         _Matrix* result = (_Matrix *)((_Formula *)modelMatrixIndices.list_data[theModel])->Compute();
218         result->CheckIfSparseEnough(true);
219         return result;
220     }
221 
222     return (_Matrix*) (LocateVar(modelMatrixIndices.list_data[theModel])->GetValue());
223 }
224 
225 //__________________________________________________________________________________
226 
GetModelDimension(void)227 long _VariableContainer::GetModelDimension (void) {
228     long matrixDim = 0L;
229     if (theModel >= 0L) {
230         matrixDim = modelTypeList.list_data[theModel];
231         if (matrixDim == 0L) {
232             return GetModelMatrix()->GetHDim();
233         }
234     }
235     return matrixDim;
236 }
237 
238 //__________________________________________________________________________________
239 
GetFreqMatrix(void) const240 _Matrix* _VariableContainer::GetFreqMatrix (void) const  {
241     if (theModel>=0) {
242         long freqID = modelFrequenciesIndices.list_data[theModel];
243         if (freqID>=0) {
244             return (_Matrix*) (LocateVar(freqID)->GetValue());
245         } else {
246             return (_Matrix*) (LocateVar(-freqID-1)->GetValue());
247         }
248     }
249     return nil;
250 }
251 
252 //__________________________________________________________________________________
ScanModelBasedVariables(_String const & fullName,_AVLListXL * varCache)253 void    _VariableContainer::ScanModelBasedVariables (_String const & fullName, _AVLListXL* varCache) {
254     if (theModel!= HY_NO_MODEL) { // build the matrix variables
255         _SimpleList       mVars;
256 
257         {
258 
259             long cachedID = -1;
260             bool doScan   = !varCache || (cachedID = varCache->Find ((BaseRef) theModel)) < 0L ;
261 
262             if (doScan) {
263 
264                 _AVLList                ma (&mVars);
265                 ScanModelForVariables   (GetModelIndex(), ma,true,theModel,false);
266 
267                 long freqID     = modelFrequenciesIndices.list_data[theModel];
268                 if (freqID>=0) {
269                     ((_Matrix*) (LocateVar(freqID)->GetValue()))->ScanForVariables2(ma,true,-1,false);
270                 }
271 
272                 ma.ReorderList();
273 
274                 if (varCache) {
275                     varCache->Insert ((BaseRef)theModel, (long)mVars.makeDynamic(),false);
276                 }
277             } else if (varCache) {
278                 mVars.Duplicate (varCache->GetXtra (cachedID));
279             }
280 
281         }
282 
283         for (long i=0L; i<mVars.lLength; i++) {
284             _Variable * aVar = (_Variable*)variablePtrs (mVars.list_data[i]);
285             if (aVar->IsGlobal()) {
286                 PushGlobalVariable(aVar->get_index());
287             } else {
288                 _StringBuffer var_name (fullName.length() + 1UL + aVar->GetName()->length());
289                 var_name << fullName << '.';
290                 aVar->ContextFreeName(var_name);
291                 //_String           var_name = fullName&'.'&aVar->ContextFreeName();
292                 _Variable * spawnedVar = CheckReceptacle(&var_name, kEmptyString, false, false);
293                 spawnedVar->SetBounds (aVar->GetLowerBound(), aVar->GetUpperBound());
294 
295                 if (aVar->IsIndependent()) {
296                     PushIndVariable(spawnedVar->get_index(), mVars.get(i));
297                 } else {
298                     PushDepVariable(spawnedVar->get_index(), mVars.get(i));
299                 }
300             }
301         }
302     }
303 }
304 
305 //__________________________________________________________________________________
SetModel(long modelID,_AVLListXL * varCache)306 void    _VariableContainer::SetModel (long modelID, _AVLListXL* varCache) {
307     theModel = modelID;
308     ScanModelBasedVariables (*theName, varCache);
309     SortVars();
310 }
311 
312 //__________________________________________________________________________________
InitializeVarCont(_String const & aName,_String & theTmplt,_VariableContainer * theP,_AVLListXL * varCache)313 void    _VariableContainer::InitializeVarCont (_String const& aName, _String& theTmplt, _VariableContainer* theP, _AVLListXL* varCache) {
314 
315     theParent = theP;
316 
317     if (aName.nonempty()) {
318         /*
319             SLKP
320             this entire section may be deprecated, and may actuall
321         */
322         theName = new _String (aName);
323 
324         long f = aName.Find('.');
325 
326         while (theP) {
327             if (f != -1L) {
328                 f = aName.Find('.',f+1L,-1L);
329             } else {
330                 break;
331             }
332             theP = theP->theParent;
333         }
334 
335         if (theP) {
336             *theName = (*(theP->theName))&'.'&*theName;
337         }
338 
339         InsertVar (this);
340     }
341     SetModel (FindModelName(theTmplt), varCache);
342 }
343 
344 //__________________________________________________________________________________
345 
ScanAndAttachVariables(void)346 void _VariableContainer::ScanAndAttachVariables (void) {
347     _Variable* var;
348     _SimpleList travcache;
349 
350     long f = variableNames.Find (theName,travcache);
351 
352     if (f >= 0L) {
353         _StringBuffer theNameAndADot = (_StringBuffer (theName->length() + 1L) << *theName << '.');
354 
355         for (f = variableNames.Next (f, travcache); f>=0; f = variableNames.Next (f, travcache)) {
356             var = FetchVar (f);
357 
358             if (var->theName->BeginsWith(theNameAndADot)) {
359                 if (!var->IsContainer()) {
360                     long   vix = variableNames.GetXtra (f);
361 
362                     if (var->IsIndependent()) {
363                         if ( ! (HasIndVariable(vix) || HasDepVariable(vix))) {
364                             PushIndVariable(vix, -1);
365                         }
366                     } else {
367                         if ( ! (HasIndVariable(vix) || HasDepVariable(vix))) {
368                             PushDepVariable(vix, -1);
369                        }
370                     }
371                 }
372             } else {
373                 break;
374             }
375         }
376     }
377 
378 }
379 //__________________________________________________________________________________
380 
~_VariableContainer(void)381 _VariableContainer::~_VariableContainer(void) {
382     if (iVariables) {
383         delete iVariables;
384     }
385     if (dVariables) {
386         delete dVariables;
387     }
388     if (gVariables) {
389         delete gVariables;
390     }
391 }
392 
393 //__________________________________________________________________________________
394 
HasChanged(bool)395 bool _VariableContainer::HasChanged (bool) {
396 
397     auto has_changed = [] (long var_index, long, unsigned long) -> bool {
398         return LocateVar (var_index) -> HasChanged ();
399     };
400     auto has_changed_global = [=] (long var_index, unsigned long) -> bool {
401         return LocateVar (var_index) -> HasChanged ();
402     };
403 
404     return AnyLocalVariable (iVariables, has_changed) ||
405            gVariables && gVariables->Any(has_changed_global) ||
406            AnyLocalVariable (dVariables, has_changed);
407 }
408 
409 //__________________________________________________________________________________
410 
GetIthIndependent(long index) const411 _Variable* _VariableContainer::GetIthIndependent (long index) const {
412     if (iVariables && (index = index << 1)<iVariables->countitems()) {
413         return LocateVar (iVariables->get(index));
414     } else {
415         return nil;
416     }
417 }
418 
419 
420 //__________________________________________________________________________________
421 
GetIthDependent(long index) const422 _Variable* _VariableContainer::GetIthDependent (long index) const {
423     if (dVariables && (index = index << 1) < dVariables->countitems()) {
424         return LocateVar (dVariables->get(index));
425     } else {
426         return nil;
427     }
428 }
429 
430 //__________________________________________________________________________________
431 
GetIthParameter(long index) const432 _Variable* _VariableContainer::GetIthParameter (long index) const {
433     if (iVariables) {
434         if ( (index = index << 1 ) <iVariables->countitems()) {
435             return LocateVar (iVariables->get(index));
436         } else {
437             if (dVariables) {
438                 index-=iVariables->countitems();
439                 if (index<dVariables->countitems()) {
440                     return LocateVar (dVariables->get(index));
441                 }
442             }
443         }
444     } else {
445         if (dVariables && (index = index << 1) <dVariables->countitems()) {
446             return LocateVar (dVariables->get(index));
447         }
448     }
449     return nil;
450 }
451 
452 //__________________________________________________________________________________
453 
NeedToExponentiate(bool ignoreCats) const454 bool _VariableContainer::NeedToExponentiate (bool ignoreCats) const {
455     if ((HY_VC_NO_CHECK&varFlags) == 0) {
456         auto has_changed = [=] (long var_index, long ref_index, unsigned long) -> bool {
457             if (ref_index >= 0L) {
458                 return LocateVar (var_index) -> HasChanged (ignoreCats);
459                 /*bool haz = LocateVar (var_index) -> HasChanged (ignoreCats);
460                 if (haz) {
461                     _Variable *lv = LocateVar (var_index);
462                     fprintf (stderr, "==> %s HAZ changed in the context of %s (%d, %x, %d)\n", lv->GetName()->get_str(), GetName()->get_str(), lv->varFlags, LocateVar (var_index)->varValue, lv->varValue->IsVariable());
463                 }
464                 return haz;*/
465             }
466             return false;
467         };
468         auto has_changed_global = [=] (long var_index, unsigned long) -> bool {
469             return LocateVar (var_index) -> HasChanged (ignoreCats);
470         };
471 
472 
473         return AnyLocalVariable (iVariables, has_changed) ||
474                gVariables && gVariables->Any(has_changed_global) ||
475                AnyLocalVariable (dVariables, has_changed);
476     }
477     return false;
478 
479 }
480 
481 //__________________________________________________________________________________
SortVars(void)482 void      _VariableContainer::SortVars(void) {
483     // sort independents 1st
484     // use dumb bubble sort
485 
486     auto bubble_sort = [] (_SimpleList * array) -> void {
487         if (array && array->countitems ()>2) {
488             bool        done = false;
489 
490             _String     *s1,
491             *s2;
492             while (!done) {
493                 done = true;
494                 s1 = LocateVar(array->list_data[0])->GetName();
495                 for (long index = 2L; index<array->countitems(); index+=2L) {
496                     s2 = LocateVar(array->list_data[index])->GetName();
497                     if (s2->Compare(*s1) == kCompareLess) {
498                         done = false;
499                         array->Swap (index, index-2);
500                         array->Swap (index+1, index-1);
501                     }
502                 }
503             }
504         }
505     };
506 
507     bubble_sort (iVariables);
508     bubble_sort (dVariables);
509 }
510 //__________________________________________________________________________________
511 
PushGlobalVariable(long var_ref)512 void     _VariableContainer::PushGlobalVariable (long var_ref) {
513     if (gVariables) {
514         *gVariables << var_ref;
515     } else {
516         gVariables = new _SimpleList;
517         *gVariables << var_ref;
518     }
519 }
520 
521 //__________________________________________________________________________________
PushIndVariable(long var_ref,long local_ref)522 void      _VariableContainer::PushIndVariable (long var_ref, long local_ref) {
523     if (iVariables) {
524         *iVariables << var_ref << local_ref;
525     } else {
526         iVariables = new _SimpleList;
527         *iVariables << var_ref << local_ref;
528     }
529 }
530 //__________________________________________________________________________________
531 
PushDepVariable(long var_ref,long local_ref)532 void    _VariableContainer::PushDepVariable (long var_ref, long local_ref) {
533     if (dVariables) {
534         *dVariables << var_ref << local_ref;
535     } else {
536         dVariables = new _SimpleList;
537         *dVariables << var_ref << local_ref;
538     }
539 }
540 //__________________________________________________________________________________
541 
HasIndVariable(long var_ref) const542 bool    _VariableContainer::HasIndVariable  (long var_ref) const {
543     return iVariables && iVariables->FindStepping(var_ref, 2L) >= 0;
544 }
545 //__________________________________________________________________________________
546 
HasDepVariable(long var_ref) const547 bool    _VariableContainer::HasDepVariable  (long var_ref) const {
548     return dVariables && dVariables->FindStepping(var_ref, 2L) >= 0;
549 }
550 //__________________________________________________________________________________
551 
RemoveLocalVariable(_SimpleList * & array,long array_index)552 void    _VariableContainer:: RemoveLocalVariable (_SimpleList*& array, long array_index) {
553     if (array && array->countitems() > 2UL) {
554         array->Delete(array_index);
555         array->Delete(array_index);
556         array->TrimMemory();
557     } else {
558         delete array;
559         array = nil;
560     }
561 }
562 
563 //__________________________________________________________________________________
564 
RemoveGlobalVariable(long array_index)565 void    _VariableContainer:: RemoveGlobalVariable (long array_index) {
566     if (gVariables->countitems() > 1UL) {
567         gVariables->Delete(array_index);
568         gVariables->TrimMemory();
569     } else {
570         delete gVariables;
571         gVariables = nil;
572     }
573 }
574 
575 
576 //__________________________________________________________________________________
RemoveDependance(long varIndex)577 bool      _VariableContainer::RemoveDependance (long varIndex) {
578     if (dVariables) {
579         long array_index = dVariables->FindStepping(varIndex,2L);
580 
581         if (array_index >= 0L) {
582 
583             InsertVariableInSortedList(iVariables,
584                                        *LocateVar (dVariables->list_data[array_index])->GetName(),
585                                        varIndex,
586                                        dVariables->get(array_index+1));
587             RemoveLocalVariable (dVariables, array_index);
588         }
589     }
590     return true;
591 }
592 
593 //__________________________________________________________________________________
RemoveDependance(_AVLList const & list)594 void      _VariableContainer::RemoveDependance (_AVLList const & list) {
595     if (dVariables) {
596 
597         _SimpleList removed;
598 
599         ForEachLocalVariable(dVariables, [&list, &removed, this] (long self, long template_var, unsigned long array_idx) -> void {
600             if (list.FindLong(self) >= 0L) {
601                 InsertVariableInSortedList(this->iVariables,
602                                            *LocateVar (self)->GetName(),
603                                            self,
604                                            template_var);
605                 removed << array_idx;
606 
607             }
608         });
609 
610         removed.Sort();
611         removed.Flip();
612 
613         removed.Each([this] (long idx, unsigned long) -> void {
614             this->RemoveLocalVariable (this->dVariables, idx);
615         });
616 
617     }
618 }
619 
620 //__________________________________________________________________________________
CheckAndAddUserExpression(_String & parameter_name,long start_with)621 long      _VariableContainer::CheckAndAddUserExpression (_String& parameter_name, long start_with) {
622     _String localized_name = WrapInNamespace (parameter_name, theName),
623             unused_name (localized_name);
624 
625     long    k = MAX (start_with, 2L);
626     if (start_with>=2L) {
627         unused_name = localized_name&start_with;
628     }
629 
630     while (LocateVarByName(unused_name)>=0L) {
631         unused_name = localized_name & _String (k++);
632     }
633 
634     if (start_with<0L) {
635         return k>2?k-1:0;
636     }
637 
638     if (start_with<2) {
639         if (k>2) {
640             parameter_name = parameter_name&_String(k-1L);
641         }
642     } else {
643         if (k>start_with) {
644             parameter_name = parameter_name & _String (k-1L);
645         } else {
646             parameter_name = parameter_name & _String (start_with);
647         }
648     }
649 
650     _Variable newVar (unused_name);
651     k =  newVar.get_index();
652 
653     PushDepVariable(k, -1);
654     return k;
655 }
656 
657 //__________________________________________________________________________________
CopyMatrixParameters(_VariableContainer * source,bool match_by_name)658 void      _VariableContainer::CopyMatrixParameters (_VariableContainer* source, bool match_by_name) {
659     if (iVariables && (source->iVariables || source->dVariables)) {
660         if (match_by_name) {
661             _List source_vars, target_vars;
662 
663             _SimpleList model_vars_in_source, model_vars_in_target;
664 
665             ForEachLocalVariable(source->iVariables, [&] (long var_idx, long ref_idx, long array_index) {
666                 if (ref_idx >= 0L) {
667                     source_vars << LocateVar (ref_idx)->GetName();
668                     model_vars_in_source << array_index;
669                 }
670             });
671             ForEachLocalVariable(source->dVariables, [&] (long var_idx, long ref_idx, long array_index) {
672                 if (ref_idx >= 0L) {
673                     source_vars << LocateVar (ref_idx)->GetName();
674                     model_vars_in_source << (-2L-array_index);
675                 }
676             });
677             ForEachLocalVariable(iVariables, [&] (long var_idx, long ref_idx, long array_index) {
678                 if (ref_idx >= 0L) {
679                     target_vars << LocateVar (ref_idx)->GetName();
680                     model_vars_in_target << array_index;
681                 }
682             });
683 
684             _SimpleList the_mapping;
685             target_vars.Map (source_vars, the_mapping);
686             the_mapping.Each ([=] (long source_var, unsigned long index) -> void {
687                 if (source_var >= 0L) {
688                     long which_idx = model_vars_in_source.list_data[source_var];
689                     which_idx = which_idx >= 0 ? source->iVariables->get (which_idx) : source->dVariables->get (-which_idx-2L);
690                     LocateVar (iVariables->get (model_vars_in_target.get(index)))->SetValue (LocateVar (which_idx)->Compute(),true,true,NULL);
691                 }
692             });
693 
694         } else {
695             if (source->iVariables) {
696                 for (unsigned long i=0UL; i<iVariables->lLength && i< source->iVariables->lLength; i+=2UL) {
697                     LocateVar (iVariables->get(i))->SetValue(LocateVar (source->iVariables->get(i))->Compute(),true,true,NULL);
698                 }
699             }
700         }
701     }
702     SetValue (source->Compute(),true,true,NULL);
703 }
704 
705 //__________________________________________________________________________________
KillUserExpression(long varID)706 void      _VariableContainer::KillUserExpression (long varID) {
707     if (dVariables) {
708         long f = dVariables->FindStepping(varID,2);
709         if (f>=0) {
710             DeleteVariable (*LocateVar(varID)->GetName(),true);
711             RemoveLocalVariable(dVariables, f);
712          }
713     }
714 }
715 
716 //__________________________________________________________________________________
717 
InsertVariableInSortedList(_SimpleList * & list,_String const & var_name,long var_idx,long ref_idx)718 long    _VariableContainer::InsertVariableInSortedList (_SimpleList * & list, _String const & var_name, long var_idx, long ref_idx) {
719 
720     long    insert_here = 0L;
721 
722     if (!list) {
723         list = new _SimpleList;
724     } else {
725         unsigned long array_l = list->countitems();
726         while (insert_here< array_l) {
727             _Variable *existing_var = LocateVar (list->get(insert_here));
728             if (!existing_var) {
729                 HandleApplicationError (_String("Internal error in InsertVariableInSortedList()"), false);
730                 return -1;
731             }
732             if (var_name.Compare (*existing_var->GetName()) != kCompareGreater) {
733                 break;
734             }
735             insert_here+=2;
736         }
737     }
738 
739     list->InsertElement ((BaseRef)var_idx, insert_here, false, false);
740     list->InsertElement ((BaseRef)ref_idx, insert_here+1, false, false);
741 
742     return insert_here;
743 }
744 
745 
746 //__________________________________________________________________________________
SetDependance(long varIndex)747 long      _VariableContainer::SetDependance (long varIndex) {
748     if (iVariables) {
749         long f;
750 
751         if (varIndex>=0) {
752             f = iVariables->FindStepping(varIndex,2);
753             if (f<0) {
754                 return -1;
755             }
756         } else {
757             f = -varIndex-1;
758             varIndex = iVariables->list_data[f];
759         }
760 
761 
762         /*printf ("Moving ind->dep for %s from %s\n", LocateVar (varIndex)->GetName()->get_str(),
763                 GetName()->get_str());*/
764 
765         if (iVariables->list_data[f+1]>=0) {
766             //printf ("Local variable %s\n", LocateVar (iVariables->list_data[f+1])->GetName()->sData);
767             if (!LocateVar(iVariables->list_data[f+1])->IsIndependent()) {
768                 return -2;
769             }
770         }
771 
772         InsertVariableInSortedList (dVariables, *LocateVar (iVariables->get(f))->GetName(), varIndex,iVariables->get(f+1));
773         RemoveLocalVariable(iVariables,f);
774         return varIndex;
775     }
776     return -1;
777 }
778 
779 //__________________________________________________________________________________
SetMDependance(_SimpleList const & mDep)780 bool      _VariableContainer::SetMDependance (_SimpleList const & mDep) {
781   if (iVariables) {
782     if (mDep.lLength*2 > iVariables->lLength)
783       for (long k=iVariables->lLength-2; k>=0; k-=2) {
784         long f = mDep.BinaryFind (iVariables->list_data[k]);
785         if (f>=0) {
786           SetDependance (-k-1);
787         }
788       }
789     else
790       for (unsigned long k=0UL; iVariables && k<mDep.lLength; k++) {
791         SetDependance (mDep.list_data[k]);
792       }
793   }
794 
795   return true;
796 }
797 
798 
799 //__________________________________________________________________________________
Clear(void)800 void      _VariableContainer::Clear(void) {
801     theModel = HY_NO_MODEL;
802     if (iVariables) {
803         delete iVariables;
804         iVariables = nil;
805     }
806     if (dVariables) {
807         delete dVariables;
808         dVariables = nil;
809     }
810     if (gVariables) {
811         delete gVariables;
812         gVariables = nil;
813     }
814 }
815 
816 //__________________________________________________________________________________
CountAll(void) const817 long      _VariableContainer::CountAll(void) const {
818     return (iVariables? (iVariables->countitems() >> 1) :0L)+(dVariables?(dVariables->countitems() >> 1):0L);
819 }
820 
821 //__________________________________________________________________________________
CountIndependents(void) const822 long      _VariableContainer::CountIndependents(void) const {
823     return  (iVariables? (iVariables->countitems() >> 1) :0L);
824 }
825 
826 //__________________________________________________________________________________
CountDependents(void) const827 long      _VariableContainer::CountDependents(void) const {
828     return  (dVariables? (dVariables->countitems() >> 1) :0L);
829 }
830 
831 //__________________________________________________________________________________
HasLocals(void)832 bool      _VariableContainer::HasLocals  (void) {
833     return  iVariables && iVariables->countitems() > 0UL || dVariables && dVariables->countitems() > 0UL;
834 }
835 
836 //__________________________________________________________________________________
837 
GetSaveableListOfUserParameters(void)838 _String*    _VariableContainer::GetSaveableListOfUserParameters (void) {
839     _StringBuffer * result = new _StringBuffer (64L);
840 
841     ForEachLocalVariable(dVariables, [&] (long var_index, long ref_index, unsigned long array_index) -> void {
842         if (ref_index < 0) {
843             _Variable * userParm  = (_Variable*) LocateVar (var_index);
844             result->AppendAnAssignmentToBuffer(userParm->GetName(),
845                                                (_String*)userParm->GetFormulaString(kFormulaStringConversionNormal),
846                                                kAppendAnAssignmentToBufferFree | kAppendAnAssignmentToBufferAssignment);
847         }
848     });
849 
850     result->TrimSpace ();
851     return result;
852 }
853 
854 //__________________________________________________________________________________
ClearConstraints(void)855 void      _VariableContainer::ClearConstraints(void) {
856     while (dVariables) {
857         LocateVar(dVariables->list_data[0])->ClearConstraints();
858     }
859 }
860 
861 //#define _UBER_VERBOSE_MX_UPDATE_DUMP
862 
863 //__________________________________________________________________________________
864 
CopyModelParameterValue(long var_idx,long ref_idx,unsigned long)865 void      _VariableContainer::CopyModelParameterValue (long var_idx, long ref_idx, unsigned long) {
866     if (ref_idx >= 0) {
867         _Variable * model_var = LocateVar (ref_idx);
868         if (model_var -> IsIndependent()) {
869             model_var->SetValue (LocateVar (var_idx)->Compute(),true,true,NULL);
870 
871 #ifdef _UBER_VERBOSE_MX_UPDATE_DUMP
872                 fprintf (stderr, "[_CalcNode::RecomputeMatrix] Node %s, var %s, value = %15.12g\n", LocateVar (var_idx)->GetName()->get_str(), model_var->GetName()->get_str(), model_var->Compute()->Value());
873 #endif
874         }
875     }
876 }
877 
878 
879 //__________________________________________________________________________________
880 
CompileListOfDependents(_SimpleList & rec)881 void  _VariableContainer::CompileListOfDependents (_SimpleList& rec) {
882 
883     auto push_var = [&] (long var_idx, long ref_idx, unsigned long index) -> void {
884         LocateVar (var_idx)->CompileListOfDependents(rec);
885     };
886 
887     ForEachLocalVariable(iVariables, push_var);
888     if (gVariables) {
889         gVariables->Each ([&] (long var_idx, unsigned long index) -> void {
890             LocateVar (var_idx)->CompileListOfDependents(rec);
891         });
892     }
893     ForEachLocalVariable(dVariables, push_var);
894     if (dVariables) {
895         for (unsigned long i=0UL; i<dVariables->countitems(); i+=2UL) {
896             long f = rec.Find (dVariables->get (i));
897             if (f>=0L) {
898                 rec.Delete (f);
899             }
900         }
901     }
902 }
903 
904 
905 //__________________________________________________________________________________
906 
MarkDone(void)907 void _VariableContainer::MarkDone (void) {
908 
909     ForEachLocalVariable(iVariables, [] (long var_idx, long ref_idx, unsigned long index) -> void {
910         LocateVar (var_idx)->MarkDone();
911     });
912     if (gVariables) {
913         gVariables->Each ([&] (long var_idx, unsigned long index) -> void {
914             LocateVar (var_idx)->MarkDone();
915         });
916     }
917 }
918 
919 
920 //__________________________________________________________________________________
921 
MatchParametersToList(_List & suffixes,bool doAll,bool indOnly)922 void _VariableContainer::MatchParametersToList (_List& suffixes, bool doAll, bool indOnly) {
923     /** TODO SLKP 20171130; what is this for?? Likely can be deprecated */
924 
925     if (doAll) {
926         for (long i=suffixes.lLength-1; i>=0; i--) {
927             long j;
928             if (!indOnly) {
929                 if (dVariables) {
930                     for (j=0; j<dVariables->lLength; j+=2)
931                         if (LocateVar(dVariables->list_data[j])->GetName()->EndsWith (*(_String*)suffixes.list_data[i])) {
932                             break;
933                         }
934 
935                     if (j<dVariables->lLength) {
936                         continue;
937                     }
938                 }
939             }
940             if (iVariables) {
941                 for (j=0; j<iVariables->lLength; j+=2) {
942                     if (LocateVar(iVariables->list_data[j])->GetName()->EndsWith (*(_String*)suffixes.list_data[i])) {
943                         break;
944                     }
945                 }
946                 if (j==iVariables->lLength) {
947                     suffixes.Delete (i);
948                 }
949             } else {
950                 suffixes.Delete (i);
951             }
952         }
953     } else {
954         for (long i=suffixes.lLength-1; i>=0; i--) {
955             long j;
956             if (dVariables) {
957                 for (j=0; j<dVariables->lLength; j+=2) {
958                     if (dVariables->list_data[j+1]<0) {
959                         if (LocateVar(dVariables->list_data[j])->GetName()->EndsWith (*(_String*)suffixes.list_data[i])) {
960                             break;
961                         }
962                     }
963                 }
964                 if (j==dVariables->lLength) {
965                     suffixes.Delete (i);
966                 }
967             } else {
968                 suffixes.Delete(i);
969             }
970         }
971     }
972 }
973 
974 //__________________________________________________________________________________
975 
IsConstant(void)976 bool _VariableContainer::IsConstant (void) {
977     if (iVariables) {
978         return false;
979     }
980 
981     return ! (AnyLocalVariable(dVariables, [] (long var_idx, long ref_idx, unsigned long) -> bool {
982         return !LocateVar(var_idx)->IsConstant();
983     }) ||
984         gVariables && gVariables->Any ([] (long var_idx,  unsigned long) -> bool {
985         return !LocateVar(var_idx)->IsConstant();
986     }));
987 
988 }
989 
990 //__________________________________________________________________________________
991 
ScanContainerForVariables(_AVLList & l,_AVLList & l2,_AVLListX * tagger,long weight,_AVLListX * map_variables_to_nodes,long track_node)992 void _VariableContainer::ScanContainerForVariables (_AVLList& l,_AVLList& l2, _AVLListX * tagger, long weight, _AVLListX * map_variables_to_nodes, long track_node) {
993 
994     //printf ("_VariableContainer::ScanContainerForVariable %x\n", this);
995     ForEachLocalVariable(iVariables, [&] (long var_idx, long ref_idx, unsigned long) -> void {
996         long insert_location = l.Insert((BaseRef)var_idx);
997         if (tagger) {
998             tagger->UpdateValue ((BaseRef)var_idx, weight, 0);
999         }
1000         if (map_variables_to_nodes) {
1001             //printf ("%ld (%s) -> %ld\n", var_idx, LocateVar (var_idx)->GetName()->get_str(), insert_location);
1002             if (insert_location >= 0) { // was inserted
1003                 map_variables_to_nodes->Insert ((BaseRef)var_idx, track_node, false, false);
1004             } else { // was already there
1005                 map_variables_to_nodes->UpdateValue((BaseRef)var_idx, -1, 1);
1006             }
1007         }
1008     });
1009 
1010     if (dVariables) {
1011         _SimpleList temp;
1012         _AVLList  ta (&temp);
1013 
1014         ForEachLocalVariable(dVariables, [&] (long var_idx, long ref_idx, unsigned long) -> void {
1015             l2.Insert((BaseRef)var_idx);
1016             LocateVar (var_idx)->ScanForVariables(ta, true, tagger, weight);
1017         });
1018 
1019         //ta.ReorderList();
1020         temp.Each([&] (long var_index, unsigned long) -> void {
1021             _Variable * v = LocateVar(var_index);
1022             if (!v->IsGlobal() && v->IsIndependent()) {
1023                 long insert_location = l.Insert ((BaseRef)var_index);
1024                 if (tagger) {
1025                     tagger->UpdateValue ((BaseRef)var_index, weight, 0);
1026                 }
1027                 if (map_variables_to_nodes) {
1028                     if (insert_location >= 0) { // was inserted
1029                         map_variables_to_nodes->Insert ((BaseRef)var_index, track_node, false, false);
1030                     } else { // was already there
1031                         map_variables_to_nodes->UpdateValue((BaseRef)var_index, -1, 1);
1032                     }
1033                 }
1034             }
1035         });
1036     }
1037 }
1038 
1039 //__________________________________________________________________________________
1040 
ScanForDVariables(_AVLList & l,_AVLList &) const1041 void _VariableContainer::ScanForDVariables (_AVLList& l,_AVLList&) const {
1042     ForEachLocalVariable(dVariables, [&] (long var_idx, long ref_idx, unsigned long) -> void {
1043         l.Insert((BaseRef)var_idx);
1044     });
1045 }
1046 
1047 //__________________________________________________________________________________
1048 
GetListOfModelParameters(_List & rec)1049 void _VariableContainer::GetListOfModelParameters (_List& rec) {
1050     ForEachLocalVariable(iVariables, [&] (long var_idx, long ref_idx, unsigned long) -> void {
1051         if (ref_idx >= 0) {
1052             rec << LocateVar(ref_idx)->GetName();
1053         }
1054     });
1055 }
1056 
1057 //__________________________________________________________________________________
1058 
ScanForGVariables(_AVLList & independent,_AVLList & dependent,_AVLListX * tagger,long weight) const1059 void _VariableContainer::ScanForGVariables (_AVLList& independent,_AVLList& dependent, _AVLListX* tagger, long weight) const {
1060 
1061     auto insert_g_var = [&] (_Variable *v, long var_idx) -> void {
1062         if (v->IsIndependent()) {
1063             long insert_location = independent.Insert ((BaseRef)var_idx);
1064             if (tagger) {
1065                 tagger->UpdateValue((BaseRef)var_idx, weight, 0);
1066             }
1067         } else {
1068             dependent.Insert ((BaseRef)var_idx);
1069         }
1070     };
1071 
1072     if (gVariables) {
1073         gVariables->Each([&] (long var_idx, unsigned long) -> void {
1074             insert_g_var (LocateVar (var_idx), var_idx);
1075         });
1076     }
1077 
1078 
1079     // additionally, check to see if there is any implicit dependence on the global variables yet unseen
1080     if (dVariables) {
1081         _SimpleList var_list;
1082         _AVLList  al (&var_list);
1083         ForEachLocalVariable(dVariables, [&] (long var_idx, long ref_idx, unsigned long) -> void {
1084             LocateVar (var_idx)->ScanForVariables(al, true);
1085         });
1086         //al.ReorderList();
1087         var_list.Each ([&] (long var_idx, unsigned long) -> void {
1088             _Variable * v = LocateVar(var_idx);
1089             if (v->IsGlobal()) {
1090                 insert_g_var (LocateVar (var_idx), var_idx);
1091             }
1092         });
1093      }
1094 }
1095