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 <stdlib.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <time.h>
44 #include <float.h>
45 #include <math.h>
46 #include <limits.h>
47
48 #include "batchlan.h"
49 #include "polynoml.h"
50 #include "likefunc.h"
51
52 #include "avllist.h"
53 #include "avllistx.h"
54 #include "avllistxl.h"
55
56 #include "function_templates.h"
57 #include "mersenne_twister.h"
58 #include "global_things.h"
59 #include "string_file_wrapper.h"*/
60
61 #include "global_things.h"
62 #include "global_object_lists.h"
63 #include "associative_list.h"
64 #include "batchlan.h"
65 #include "avllistxl_iterator.h"
66
67
68 using namespace hy_global;
69 using namespace hyphy_global_objects;
70
71 #define kAssociativeListDefaultReturn (new _Constant (0.0));
72
73
74
75
76 //_____________________________________________________________________________________________
77 // AssociativeList
78 //_____________________________________________________________________________________________
79
_AssociativeList(void)80 _AssociativeList::_AssociativeList (void):avl(&theData) {
81 }
82
83 //_____________________________________________________________________________________________
84
makeDynamic(void) const85 BaseRef _AssociativeList::makeDynamic (void) const {
86 _AssociativeList * newAL = new _AssociativeList ();
87 newAL->Duplicate (this);
88 return newAL;
89 }
90
91
92 //bool _debug_memory_leak = false;
93
94 //_____________________________________________________________________________________________
95
ParseStringRepresentation(_String & serialized_form,_FormulaParsingContext & fpc)96 bool _AssociativeList::ParseStringRepresentation (_String& serialized_form, _FormulaParsingContext& fpc ) {
97 _List splitKeys;
98 bool doErrors = fpc.errMsg() == nil,
99 compute_keys_values = fpc.buildComplexObjects();
100 _VariableContainer const* theP = fpc.formulaScope();
101
102 _ElementaryCommand::ExtractConditions (serialized_form, 0, splitKeys, ',' , false);
103
104 try {
105 for (unsigned long k = 0UL; k < splitKeys.countitems(); k ++) {
106 _List key_value_pair;
107 _ElementaryCommand::ExtractConditions (*(_String*)splitKeys(k), 0, key_value_pair, ':' , false);
108 if (key_value_pair.countitems() == 2UL) {
109
110 //_debug_memory_leak = true;
111 _String key (compute_keys_values ? ProcessLiteralArgument((_String*)key_value_pair(0),theP) : *(_String*)key_value_pair(0));
112 //_debug_memory_leak = false;
113
114 if (key.empty()) {
115 key = *(_String*)key_value_pair(0);
116 }
117
118 HBLObjectRef valueC = nil;
119 if (compute_keys_values) {
120 _Formula value (*(_String*)key_value_pair(1),theP, doErrors?nil :fpc.errMsg());
121 valueC = value.Compute();
122 if (valueC) {
123 valueC->AddAReference();
124 }
125 } else {
126 valueC = new _MathObject;
127 }
128
129 if (valueC) {
130 MStore (key, valueC, false);
131 } else {
132 throw (((_String*)key_value_pair(1))->Enquote() & " could not be evaluated");
133
134 }
135 } else {
136 throw (((_String*)splitKeys(k))->Enquote() & " does not appear to specify a valid key:value pair");
137 }
138 }
139 } catch (const _String& err) {
140 if (doErrors) {
141 HandleApplicationError(err);
142 }
143 return false;
144 }
145 return true;
146 }
147
148 //_____________________________________________________________________________________________
149
toStr(unsigned long padding)150 BaseRef _AssociativeList::toStr (unsigned long padding) {
151 return Serialize (padding);
152 }
153
154 //_____________________________________________________________________________________________
155
Duplicate(BaseRefConst br)156 void _AssociativeList::Duplicate (BaseRefConst br) {
157 if (!SingleReference ()) {
158 HandleApplicationError(_String (__PRETTY_FUNCTION__).Enquote() & " called from an object with multiple references");
159 }
160 _AssociativeList const * copyMe = (_AssociativeList const*)br;
161 theData.Duplicate (©Me->theData);
162 avl.leftChild.Duplicate (©Me->avl.leftChild);
163 avl.rightChild.Duplicate (©Me->avl.rightChild);
164 avl.balanceFactor.Duplicate (©Me->avl.balanceFactor);
165 avl.emptySlots.Duplicate (©Me->avl.emptySlots);
166 avl.xtraD.Duplicate (©Me->avl.xtraD);
167 avl.root = copyMe->avl.root;
168 }
169
170 //_____________________________________________________________________________________________
171
MCoord(HBLObjectRef p,HBLObjectRef cache)172 HBLObjectRef _AssociativeList::MCoord (HBLObjectRef p, HBLObjectRef cache) {
173 if (cache && cache->ObjectClass() == STRING) {
174 return ((_FString*)cache)->UpdatePayload ((_String*)p->toStr());
175 }
176 return new _FString ((_String*)p->toStr());
177 }
178
179 //_____________________________________________________________________________________________
MAccess(HBLObjectRef p,HBLObjectRef cache)180 HBLObjectRef _AssociativeList::MAccess (HBLObjectRef p, HBLObjectRef cache) {
181 long f;
182
183 if (p->ObjectClass() == STRING) {
184 f = avl.Find (&((_FString*)p)->get_str());
185 } else {
186 _String s ((_String*)p->toStr());
187 f = avl.Find (&s);
188 }
189 if (f>=0L) {
190 HBLObjectRef res = (HBLObjectRef)avl.GetXtra (f);
191 if (cache != res)
192 res->AddAReference();
193 return res;
194 } else {
195 return kAssociativeListDefaultReturn;
196 }
197 }
198
199 //_____________________________________________________________________________________________
Equal(HBLObjectRef p)200 bool _AssociativeList::Equal (HBLObjectRef p) {
201 if (p->ObjectClass() == ASSOCIATIVE_LIST) {
202 _AssociativeList * rhs = (_AssociativeList*) p;
203 if (countitems() == rhs->countitems()) {
204 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&avl)) {
205 _String const* my_key = key_value.get_key();
206 HBLObjectRef my_object = (HBLObjectRef)key_value.get_object();
207 HBLObjectRef rhs_object = rhs->GetByKey(*my_key, my_object->ObjectClass());
208 if (!rhs_object || !my_object->Equal(rhs_object)) {
209 return false;
210 }
211 }
212 return true;
213 }
214 }
215 return false;
216 }
217
218 //_____________________________________________________________________________________________
Random(HBLObjectRef p,HBLObjectRef cache)219 HBLObjectRef _AssociativeList::Random (HBLObjectRef p, HBLObjectRef cache) {
220 bool with_replacement = false;
221
222 try {
223 if (p->ObjectClass() == NUMBER) {
224 _AssociativeList * result;
225 if (cache && cache->ObjectClass() == ASSOCIATIVE_LIST) {
226 result = (_AssociativeList*)cache;
227 result->Clear();
228 } else {
229 result = new _AssociativeList;
230 }
231 with_replacement = !CheckEqual(0.0, p->Compute()->Value());
232
233 //unsigned long items = countitems();
234 _SimpleList reshuffled (countitems(), 0, 1);
235 if (with_replacement) {
236 reshuffled.PermuteWithReplacement(1);
237 } else {
238 reshuffled.Permute(1);
239 }
240
241 _List copied_values;
242
243 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&avl)) {
244 copied_values << key_value.get_object();
245 }
246
247 long index = 0L;
248 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&avl)) {
249 result->MStore (*(_String*)avl.Retrieve(key_value.get_index()),
250 (HBLObjectRef)copied_values.GetItem(reshuffled.get (index++)),
251 true
252 );
253 }
254
255 return result;
256
257 } else {
258 throw (_String ("Unsupported argument type"));
259 }
260 } catch (const _String& err) {
261 HandleApplicationError (err);
262 }
263 return new _MathObject;
264 }
265
266 //_____________________________________________________________________________________________
MIterator(HBLObjectRef p,HBLObjectRef p2,HBLObjectRef cache)267 HBLObjectRef _AssociativeList::MIterator (HBLObjectRef p, HBLObjectRef p2, HBLObjectRef cache) {
268
269 const _String kAVLIteratorOrder = "INDEXORDER",
270 kAVLIteratorOrderValue = "VALUEINDEXORDER";
271
272 long done = 0;
273
274 _List reference_manager;
275
276 try {
277
278 if (p->ObjectClass() == STRING && p2->ObjectClass() == STRING) {
279
280 long avlRoot = avl.GetRoot();
281
282 if (avlRoot >= 0) {
283
284 _String * callback_id = (_String*)p->toStr(),
285 * filter_id = (_String*)p2->toStr();
286
287 reference_manager < callback_id < filter_id;
288
289 long callback = FindBFFunctionName (*callback_id),
290 filter = FindBFFunctionName (*filter_id);
291
292 if (callback < 0L || GetBFFunctionArgumentCount(callback) != 2L) {
293 throw (_String("The first argument in an iterator call for Associative Arrays must be a valid identifier of a function taking two arguments (key, value)"));
294 } else {
295 if (filter >= 0L && GetBFFunctionArgumentCount (filter) != 1L) {
296 throw (_String("The second argument in an iterator call for Associative Arrays must be either empty or a valid identifier of a function taking a single argument"));
297 }
298
299 _Formula testFormula,
300 actionFormula;
301
302 actionFormula.GetList() < new _Operation()
303 < new _Operation()
304 < new _Operation(kEmptyString,-callback-1L);
305
306
307 if (filter >= 0L) {
308 testFormula.GetList() < new _Operation() < new _Operation(kEmptyString,-filter-1L);
309 }
310
311 _FString * fKey = new _FString;
312 // TODO SLKP 20181113 : this could be a memory leak, but it needs to be allocated dynamically
313 // otherwise if "actionFormula" makes use of "theKey" it may not be properly cleared
314 for (AVLListXLIteratorKeyValue filter_key_value : AVLListXLIterator (&avl)) {
315 _String * current_key = (_String *)avl.Retrieve (filter_key_value.get_index());
316 if (current_key) {
317 fKey->SetStringContent (new _StringBuffer (*current_key));
318 if (filter >= 0L) {
319 testFormula.GetIthTerm(0)->SetNumber(fKey);
320 if (CheckEqual(testFormula.Compute()->Value(),0.0)) {
321 continue;
322 }
323 }
324 actionFormula.GetIthTerm(0)->SetNumber(fKey);
325 actionFormula.GetIthTerm(1)->SetNumber((HBLObjectRef)filter_key_value.get_object());
326 //StringToConsole((_String*)actionFormula.toStr(kFormulaStringConversionNormal)); NLToConsole();
327 actionFormula.Compute();
328 done ++;
329 }
330 }
331
332 actionFormula.GetIthTerm(0)->SetNumber(nil);
333 actionFormula.GetIthTerm(1)->SetNumber(nil);
334 if (filter >= 0L) {
335 testFormula.GetIthTerm(0)->SetNumber(nil);
336 }
337
338 DeleteObject (fKey);
339
340 }
341 }
342 } else if (p->ObjectClass () == STRING && p2->ObjectClass () == NUMBER) {
343 _String * mode = (_String*)p->toStr();
344 reference_manager < mode;
345 HBLObjectRef result = nil;
346
347 if (*mode == kAVLIteratorOrder|| *mode == kAVLIteratorOrderValue) {
348 long index = avl.GetByIndex(p2->Compute()->Value());
349
350 if (index >= 0L) {
351 result = (*mode == kAVLIteratorOrder )? (new _FString(*(_String*)avl.Retrieve(index),false)): ((HBLObjectRef)avl.GetXtra (index)->makeDynamic());
352 } else {
353 throw _String("Index out of bounds in call to AVL iterator (by index)");
354 }
355 }
356
357 if (result) {
358 return result;
359 }
360 } else {
361 throw _String("Both arguments must be Strings (or a String Literal and a number) in an iterator call for Associative Arrays");
362 }
363 } catch (const _String& err) {
364 HandleApplicationError (err);
365 }
366 return _returnConstantOrUseCache(done, cache);
367 }
368
369 //_____________________________________________________________________________________________
GetByKey(_String const & key,long objType) const370 HBLObjectRef _AssociativeList::GetByKey (_String const& key, long objType) const {
371 HBLObjectRef res = GetByKey(key);
372 if (res && ((res->ObjectClass() & objType) > 0L)) {
373 return res;
374 }
375 return nil;
376 }
377
378 //_____________________________________________________________________________________________
GetByKeyException(_String const & key,long objType) const379 HBLObjectRef _AssociativeList::GetByKeyException (_String const& key, long objType) const {
380 HBLObjectRef res = GetByKey(key, objType);
381 if (res) {
382 return res;
383 }
384 throw key.Enquote() & " was not associated with a value of type " & FetchObjectNameFromType (objType).Enquote();
385 }
386
387
388 //_____________________________________________________________________________________________
389
GetNumberByKey(_String const & key) const390 hyFloat _AssociativeList::GetNumberByKey (_String const& key) const {
391 _Constant * c = (_Constant*)GetByKey(key, NUMBER);
392 if (c) {
393 return c->Value();
394 }
395 throw key.Enquote() & " was not associated with a numeric value";
396 }
397
398 //_____________________________________________________________________________________________
GetByKey(_String const & key) const399 HBLObjectRef _AssociativeList::GetByKey (_String const& key) const {
400 return (HBLObjectRef)avl.GetDataByKey(&key);
401 }
402
403 //_____________________________________________________________________________________________
GetByKey(long nKey,long objType) const404 HBLObjectRef _AssociativeList::GetByKey (long nKey, long objType) const {
405 return GetByKey (_String(nKey), objType);
406 }
407
408 //_____________________________________________________________________________________________
Clear(void)409 void _AssociativeList::Clear (void) {
410 avl.Clear(true);
411 }
412
413
414 //_____________________________________________________________________________________________
DeleteByKey(HBLObjectRef p)415 void _AssociativeList::DeleteByKey (HBLObjectRef p) {
416 if (p->ObjectClass() == STRING) {
417 avl.Delete (&((_FString*)p)->get_str(),true);
418 } else {
419 if (p->ObjectClass() == ASSOCIATIVE_LIST) {
420 _List * keys2remove = ((_AssociativeList*)p)->GetKeys();
421 for (long ki = 0; ki < keys2remove->lLength; ki++) {
422 avl.Delete ((_String*)(*keys2remove)(ki),true);
423 }
424 DeleteObject (keys2remove);
425 } else {
426 _String * s = (_String*)p->toStr();
427 avl.Delete (s,true);
428 DeleteObject (s);
429 }
430 }
431 }
432
433 //_____________________________________________________________________________________________
DeleteByKey(_String const & key)434 void _AssociativeList::DeleteByKey (_String const& key) {
435 avl.Delete (&key,true);
436 }
437
438
439 //_____________________________________________________________________________________________
MStore(_String * p,HBLObjectRef inObject,bool repl,long opCode)440 bool _AssociativeList::MStore (_String * p, HBLObjectRef inObject, bool repl, long opCode) {
441 if (!p) {
442 return false;
443 }
444
445 long f = avl.Find (p);
446
447 if (f>=0) { // already exists - replace
448 if (opCode == HY_OP_CODE_ADD) {
449 _List arguments;
450 arguments << inObject;
451
452 HBLObjectRef newObject = ((HBLObjectRef)avl.GetXtra(f))->ExecuteSingleOp(HY_OP_CODE_ADD,&arguments);
453 if (repl == false) {
454 DeleteObject (inObject);
455 } else {
456 repl = false;
457 }
458 inObject = newObject;
459 }
460 avl.xtraD.Replace (f, inObject, repl);
461 return false;
462 } else { // insert new
463 if (repl) {
464 BaseRef br = inObject->makeDynamic();
465 avl.Insert (p,(long)br,false);
466 //br->nInstances--;
467 } else {
468 avl.Insert (p,(long)inObject,false);
469 }
470 return true;
471 }
472 }
473
474 //_____________________________________________________________________________________________
MStore(HBLObjectRef p,HBLObjectRef inObject,bool repl,long opCode)475 void _AssociativeList::MStore (HBLObjectRef p, HBLObjectRef inObject, bool repl, long opCode) {
476 _StringBuffer *sr = ((_FString*)p)->get_str_ref();
477 if (!MStore (sr, inObject, repl, opCode)) {
478 sr->RemoveAReference();
479 }
480 }
481
482 //_____________________________________________________________________________________________
MStore(const _String & obj,HBLObjectRef inObject,bool repl)483 void _AssociativeList::MStore (const _String& obj, HBLObjectRef inObject, bool repl) {
484 _FString f (obj);
485 MStore (&f,inObject, repl);
486 }
487
488 //_____________________________________________________________________________________________
489
operator <<(_associative_list_key_value pair)490 _AssociativeList & _AssociativeList:: operator << (_associative_list_key_value pair) {
491 if (pair.key) {
492 MStore (pair.key, pair.payload, true);
493 } else {
494 _String next_index ((long)Length());
495 MStore (next_index, pair.payload, true);
496 }
497 return *this;
498 }
499
500 //_____________________________________________________________________________________________
501
502
operator <(_associative_list_key_value pair)503 _AssociativeList & _AssociativeList:: operator < (_associative_list_key_value pair) {
504 if (pair.key) {
505 MStore (pair.key, pair.payload, false);
506 } else {
507 _String next_index ((long)Length());
508 MStore (next_index, pair.payload, false);
509 }
510 return *this;
511 }
512
513
514 //_____________________________________________________________________________________________
MStore(const _String & obj,const _String & info)515 void _AssociativeList::MStore (const _String& obj, const _String& info) {
516 _FString * inf = new _FString (info);
517 MStore (obj, inf, false);
518 }
519
520
521 //_____________________________________________________________________________________________
Serialize(unsigned long padding) const522 _StringBuffer * _AssociativeList::Serialize (unsigned long padding) const {
523
524 _StringBuffer * out_string = new _StringBuffer (1024L);
525 _String padder (" ", padding);
526
527
528
529 (*out_string) << "{";
530 bool doComma = false;
531 _List * meKeys = GetKeys();
532 for (long k = 0L; k < meKeys->countitems(); k++) {
533 _String *thisKey = (_String*)(*meKeys)(k);
534 if (thisKey) {
535 if (doComma) {
536 (*out_string) << ',';
537 }
538
539 (*out_string) << '\n' << padder << ' ';
540
541 (*out_string) << '"';
542 out_string->SanitizeAndAppend (*thisKey);
543 (*out_string) << '"';
544
545 HBLObjectRef anObject = GetByKey (*thisKey);
546
547 (*out_string) << ':';
548 if (anObject->ObjectClass() == STRING) {
549 (*out_string) << '"';
550 out_string->SanitizeAndAppend(_String ((_String*)anObject->toStr(padding+2)));
551 (*out_string) << '"';
552 } else {
553 if (anObject->ObjectClass() != HY_UNDEFINED) {
554 out_string->AppendNewInstance((_String*)anObject->toStr(padding+2));
555 } else {
556 (*out_string) << kNullToken;
557 }
558 }
559 doComma = true;
560 }
561 }
562
563 DeleteObject (meKeys);
564
565 (*out_string) << '\n' << padder << "}";
566 out_string->TrimSpace ();
567
568 return out_string;
569 }
570
571
572 //__________________________________________________________________________________
Compute(void)573 HBLObjectRef _AssociativeList::Compute (void) {
574 return this;
575 }
576
577 //__________________________________________________________________________________
GetKeys(void) const578 _List* _AssociativeList::GetKeys (void) const {
579
580 _List * keys = new _List;
581
582 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&avl)) {
583 (*keys) << avl.Retrieve(key_value.get_index());
584 }
585
586 return keys;
587
588 }
589
590 //_____________________________________________________________________________________________
FillInList(_List & fill_me)591 void _AssociativeList::FillInList (_List& fill_me) {
592
593 unsigned long ll = fill_me.countitems();
594 // checkpoint the length of the list
595 try {
596 // try filling in in numerical order first 0, 1, ...
597 // failing that (if the keys are not numeric)
598 // fill in by alphanumeric keys
599 unsigned long my_length = avl.countitems();
600
601 for (long index = 0L; index < my_length; index++) {
602 _String key (index);
603 if (HBLObjectRef value = GetByKey (key)) {
604 fill_me.AppendNewInstance(value->toStr());
605 } else {
606 throw (1);
607 }
608 }
609 } catch (int e) {
610 while (fill_me.countitems () > ll) {
611 fill_me.Delete(fill_me.countitems ()-1);
612 }
613
614 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&avl)) {
615 _String* aKey = (_String*)avl.Retrieve(key_value.get_index());
616 if (aKey) {
617 fill_me.AppendNewInstance(key_value.get_object()->toStr());
618 }
619 }
620 }
621 }
622
623
624 //_____________________________________________________________________________________________
Merge(HBLObjectRef p)625 void _AssociativeList::Merge (HBLObjectRef p) {
626 //SW20111207: I don't think we should ever have to worry about avl traversing
627 //here as long as the other methods are implemented properly
628
629
630 if(p==this){
631 return;
632 }
633
634 if (p && p->ObjectClass() == ASSOCIATIVE_LIST) {
635 _AssociativeList *rhs = (_AssociativeList*) p;
636 if (rhs->avl.countitems()) {
637 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&rhs->avl)) {
638 MStore(*(_String*)rhs->avl.Retrieve (key_value.get_index()),(HBLObjectRef)key_value.get_object(),true);
639 }
640 }
641 }
642 else {
643 HandleApplicationError ("Associative list merge operation requires an associative list argument.");
644 }
645 }
646
647 //_____________________________________________________________________________________________
ExtremeValue(bool do_mimimum,HBLObjectRef cache) const648 HBLObjectRef _AssociativeList::ExtremeValue (bool do_mimimum, HBLObjectRef cache) const {
649 _String const * best_key = nil;
650 hyFloat best_value = do_mimimum ? INFINITY : -INFINITY;
651
652 if (avl.countitems()) {
653 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&avl)) {
654 HBLObjectRef value = (HBLObjectRef)key_value.get_object();
655 switch (value->ObjectClass()){
656 case NUMBER:
657 hyFloat number = ((_Constant*)value)->Value();
658 if (do_mimimum) {
659 if (number < best_value) {
660 best_value = number;
661 best_key = (_String const*)avl.Retrieve (key_value.get_index());
662 }
663 } else {
664 if (number > best_value) {
665 best_value = number;
666 best_key = (_String const*)avl.Retrieve (key_value.get_index());
667 }
668 }
669 break;
670 }
671 }
672 }
673
674
675 _AssociativeList * result = new _AssociativeList;
676 (*result) < _associative_list_key_value {"key", best_key ? new _FString (*best_key, false) : new _MathObject}
677 < _associative_list_key_value {"value", new _Constant (best_value)};
678 return result;
679
680 }
681
682 //_____________________________________________________________________________________________
Sum(HBLObjectRef cache)683 HBLObjectRef _AssociativeList::Sum (HBLObjectRef cache) {
684 hyFloat sum = 0.;
685
686 for (AVLListXLIteratorKeyValue key_value : AVLListXLIterator (&avl)) {
687 HBLObjectRef value = (HBLObjectRef)key_value.get_object();
688 switch (value->ObjectClass()){
689 case NUMBER:
690 sum += ((_Constant*)value)->Value();
691 break;
692 case STRING:
693 sum += ((_FString*)value)->get_str().to_float();
694 break;
695 case MATRIX: {
696 _Constant * sumOfValue = (_Constant*) ((_Matrix*)value->Compute())->Sum(cache);
697 sum += sumOfValue->Value();
698 if (sumOfValue != cache) {
699 DeleteObject (sumOfValue);
700 }
701 break;
702 }
703 case ASSOCIATIVE_LIST: {
704 _Constant * sumOfValue = (_Constant*) ((_AssociativeList*)value->Compute())->Sum(cache);
705 sum += sumOfValue->Value();
706 if (sumOfValue != cache) {
707 DeleteObject (sumOfValue);
708 }
709 break;
710 }
711 }
712 }
713
714 return _returnConstantOrUseCache (sum, cache);
715 }
716
717 //__________________________________________________________________________________
718
719
ExecuteSingleOp(long opCode,_List * arguments,_hyExecutionContext * context,HBLObjectRef cache)720 HBLObjectRef _AssociativeList::ExecuteSingleOp (long opCode, _List* arguments, _hyExecutionContext* context, HBLObjectRef cache) {
721
722 switch (opCode) {
723 case HY_OP_CODE_ABS:
724 return _returnConstantOrUseCache(Length(), cache);
725
726 case HY_OP_CODE_EVAL:
727 return (HBLObjectRef) makeDynamic();
728
729 case HY_OP_CODE_COLUMNS: {
730 // Columns -- get all unique values (as strings)
731 _List unique_values_aux;
732 _AVLList unique_values (&unique_values_aux);
733
734 for (unsigned long k=0UL; k<avl.dataList->lLength; k++) {
735 BaseRef anItem = ((BaseRef*)avl.dataList->list_data)[k];
736 if (anItem) {
737 _String* string_value = (_String*) avl.GetXtra(k)->toStr();
738 if (unique_values.Insert (string_value, 0L, false) < 0) {
739 DeleteObject(string_value);
740 }
741 }
742 }
743 unique_values.ReorderList();
744 return new _Matrix (*(_List*)unique_values.dataList);
745 }
746
747 case HY_OP_CODE_ROWS: {
748 // Rows - get keys
749 if (avl.emptySlots.lLength) {
750 _List dataListCompact;
751 for (long k=0; k<avl.dataList->lLength; k++) {
752 BaseRef anItem = ((BaseRef*)avl.dataList->list_data)[k];
753 if (anItem) {
754 dataListCompact << anItem;
755 }
756 }
757 return new _Matrix (dataListCompact);
758 }
759 return new _Matrix (*(_List*)avl.dataList);
760 }
761
762 case HY_OP_CODE_TYPE: // Type
763 return Type(cache);
764
765 case HY_OP_CODE_MAX: // Max
766 return ExtremeValue (false, cache);
767
768 case HY_OP_CODE_MIN: // Max
769 return ExtremeValue (true, cache);
770
771
772
773 }
774
775 _MathObject * arg0 = _extract_argument (arguments, 0UL, false);
776
777 switch (opCode) { // next check operations without arguments or with one argument
778 case HY_OP_CODE_ADD: // +
779 if (arg0) {
780 _String * new_key = new _String((long)avl.countitems());
781 if (!MStore (new_key, arg0, true)) {
782 DeleteObject (new_key);
783 }
784 return _returnConstantOrUseCache(avl.countitems(), cache);
785 }
786 return Sum (cache);
787 }
788
789
790 if (arg0) {
791 switch (opCode) { // operations that require exactly one argument
792 case HY_OP_CODE_EQ:
793 return _returnConstantOrUseCache (Equal(arg0), cache);
794
795 case HY_OP_CODE_NEQ:
796 return _returnConstantOrUseCache (!Equal(arg0), cache);
797
798 case HY_OP_CODE_MCOORD: // MCoord
799 return MCoord (arg0, cache);
800
801 case HY_OP_CODE_MUL: // merge
802 Merge (arg0);
803 return _returnConstantOrUseCache (avl.countitems(), cache);
804
805 case HY_OP_CODE_SUB:
806 DeleteByKey (arg0);
807 return _returnConstantOrUseCache (avl.countitems(), cache);
808
809 case HY_OP_CODE_RANDOM:
810 return Random (arg0, cache);
811
812 case HY_OP_CODE_DIV:
813
814 if (arg0->ObjectClass () == STRING) {
815 if (avl.Find (&((_FString*)arg0)->get_str()) >= 0L) {
816 return _returnConstantOrUseCache (1., cache);
817 }
818 } else {
819 _String serialized ((_String*)arg0->toStr());
820 if (avl.Find (&serialized) >= 0L) {
821 return _returnConstantOrUseCache (1., cache);
822 }
823 }
824 return _returnConstantOrUseCache (0., cache);
825
826 }
827 _MathObject * arg1 = _extract_argument (arguments, 1UL, false);
828
829 switch (opCode) { // check operations with 1 or 2 arguments
830 case HY_OP_CODE_MACCESS: // MAccess
831 if (arg1) {
832 return MIterator (arg0,arg1, cache);
833 } else {
834 return MAccess (arg0, cache);
835 }
836 }
837 }
838
839
840 switch (opCode) {
841 case HY_OP_CODE_TYPE:
842 case HY_OP_CODE_ADD:
843 case HY_OP_CODE_MCOORD:
844 case HY_OP_CODE_MUL:
845 case HY_OP_CODE_SUB:
846 case HY_OP_CODE_MACCESS:
847 case HY_OP_CODE_DIV:
848 WarnWrongNumberOfArguments (this, opCode,context, arguments);
849 break;
850 default:
851 WarnNotDefined (this, opCode,context);
852 }
853
854 return new _MathObject;
855
856 }
857
858
859