1LoadFunctionLibrary ("IOFunctions.bf");
2
3/**
4 * @name utility.AssociativeListToJSON
5 * @param associative_list
6 */
7function utility.AssociativeListToJSON(associative_list) {
8
9    // Replace inf and nan with 1+e9999 and null, respectively
10
11    // SW20150122 TODO: Add recursion
12    keys = Rows(associative_list);
13    for (_k = 0; _k < Columns(keys); _k = _k+1) {
14      current_val = associative_list[keys[_k]];
15      if(Type(current_val) == "String") {
16			  current_val = current_val^{{"inf"}{"1e999"}}; /* search and replace */
17			  current_val = current_val^{{"-nan"}{"null"}}; /* search and replace */
18        associative_list[keys[_k]] = current_val;
19      }
20    }
21
22    return associative_list;
23}
24
25/**
26 * @name utility.CallFunction
27 * @param id
28 * @param arguments
29 */
30function utility.CallFunction (id, arguments) {
31
32
33    if (Type (id) == "String") {
34        if (Type (arguments) == "AssociativeList") {
35            return Eval ("`id` (" + Join (",", arguments) + ")");
36        }
37        return Eval ("`id`()");
38    }
39    return None;
40}
41
42function utility.convertToArgumentString (argument) {
43    if (Type (argument) == "String") {
44        return '"' + (argument && 2) + '"';
45    }
46    return argument;
47}
48
49/**
50 * @name utility.Array1D
51 * @param m
52 */
53lfunction utility.Array1D (m) {
54    if (Type (m) == "Matrix") {
55        return Rows (m) * Columns (m);
56    } else {
57        if (Type (m) == "AssociativeList") {
58            return Abs (m);
59        }
60    }
61    return 0;
62}
63
64/**
65 * @name utility.IsFunction
66 * @param id
67 */
68function utility.IsFunction (id) {
69	if (Type (id) == "String" && Abs (id) > 0) {
70		ExecuteCommands ("GetString (__funcInfo, `id`, -1)");
71		if (Type (__funcInfo) == "AssociativeList") {
72			return Type (__funcInfo["ID"]) == "String" && Type (__funcInfo["Arguments"]) == "Matrix" && Type (__funcInfo["Body"]) == "String";
73		}
74	}
75	return FALSE;
76}
77
78function utility.getGlobalValue (val) {
79    return ^val;
80}
81
82function utility.setGlobalValue (id, val) {
83    Eval (id);
84    ^id = val;
85}
86
87/**
88 * @name utility.ToggleEnvVariable
89 * @param var
90 * @param value
91 */
92function utility.ToggleEnvVariable (var, value) {
93	if (None != value) {
94	    if (Type (utility.ToggleEnvVariable.cache) != "AssociativeList") {
95	        utility.ToggleEnvVariable.cache = {};
96	    }
97		utility.ToggleEnvVariable.cache[var] = Eval (var);
98		*var = value;
99	} else {
100		*var = utility.ToggleEnvVariable.cache[var];
101	}
102}
103
104/**
105 * @name utility.GetEnvVariable
106 * @param var
107 */
108function utility.GetEnvVariable (var) {
109	return Eval(var);
110}
111
112/**
113 * @name utility.SetEnvVariable
114 * @param var
115 */
116function utility.SetEnvVariable (var, value) {
117    Eval (var); // this is a hack to make sure the variable exists before assigning to it
118	^var = value;
119}
120
121/**
122 * @name utility.CheckCacheFile
123 * @param data_info
124 */
125lfunction utility.CheckCacheFile (data_info) {
126    cache_info = {};
127    cache_info[utility.getGlobalValue("terms.data.file")] = data_info[utility.getGlobalValue("terms.data.file")] + ".hyphy_cache";
128    if (!(cache_info[utility.getGlobalValue("terms.data.file")])) {
129        fscanf (cache_info[utility.getGlobalValue("terms.data.file")], "Raw", _cache);
130        cache_info[utility.getGlobalValue("terms.data.cache")] = Eval (_cache);
131    } else {
132         cache_info[utility.getGlobalValue("terms.data.cache")] = {};
133    }
134    return cache_info;
135}
136
137/**
138 * Find an element in the array.
139 * @name utility.Find
140 * @param {Matrix} array
141 * @param {String|Number} value
142 * @returns -1 if value is not found, otherwise returns the position
143 */
144lfunction utility.Find (array, value) {
145    for (i, v; in; array) {
146        if (v == value) {
147            return i;
148        }
149    }
150    return -1;
151}
152
153/**
154 * @name utility.SwapKeysAndValues
155 * @param dict
156 */
157lfunction utility.SwapKeysAndValues (dict) {
158    swapped_dict = {};
159    keys         = Rows (dict);
160    items        = Abs (dict);
161
162    for (i = 0; i < items; i+=1) {
163        key = keys[i];
164        swapped_dict [dict[key]] = key;
165    }
166
167    return swapped_dict;
168}
169
170/**
171 * @name utility.ArrayToDict
172 * @param object
173 */
174lfunction utility.ArrayToDict (object) {
175    result = {};
176    utility.ForEach(object, "_value_", "(`&result`)[_value_['key']] = _value_['value']");
177    return result;
178}
179
180/**
181 * Converts a matrix into a lookup dict, of the form value -> index
182 * @name   utility.MatrixToDict
183 * @param  {Matrix} object
184 * @return {Dictionary} lookup table
185 * @example utility.MatrixToDict ({{"a","b","c"}}) => {"a" : 0, "b" : 1, "c" : 2}
186 */
187
188lfunction utility.MatrixToDict (matrix) {
189    result = {};
190    counter = 0;
191    utility.ForEach(matrix, "_value_", "(`&result`)[_value_] = `&counter`; `&counter` += 1;");
192    return result;
193}
194
195/**
196 * @name utility.DictToArray
197 * @param object
198 */
199lfunction utility.DictToArray (object) {
200    result = {1,Abs (object)};
201    for (key,_value_; in; object) {
202        result[+key] = _value_;
203    }
204    return result;
205}
206
207/**
208 * @name utility.DictToSortedArray
209 * @param object
210 */
211lfunction utility.DictToSortedArray (object) {
212    result = {Abs (object),2};
213    utility.ForEachPair(object, "_key_", "_value_", "(`&result`)[+_key_][0] = _value_;(`&result`)[+_key_][1] = +_key_;");
214    return result % 0;
215}
216
217
218/**
219 * @name utility.Range
220 * @param elements
221 * @param from
222 * @param step
223 */
224lfunction utility.Range (elements, from, step) {
225    range = {};
226    for (i = 0; i < elements; i+=1) {
227        range + (from + i * step);
228    }
229    return range;
230}
231
232/**
233 * @name utility.Map
234 * @param {AssociativeList|Matrix} object - object to iterate over
235 * @param {String} lambda_name - variable name for transform
236 * @param {String} transform - function transform
237 */
238function utility.Map (object, lambda_name, transform) {
239
240    Eval ("`lambda_name` = None");
241    utility.Map.return_object = None;
242
243    if (Type (object) == "AssociativeList") {
244        ExecuteCommands ("function  utility.Map.CB (`lambda_name`) {return `transform`;}", enclosing_namespace);
245        utility.Map.return_object = {};
246        utility.Map.keys = Rows (object);
247        for (utility.Map.k = 0; utility.Map.k < Abs (object); utility.Map.k += 1) {
248            //^(lambda_name) = object [utility.Map.keys[utility.Map.k]];
249            //utility.Map.return_object [utility.Map.keys[utility.Map.k]] = Eval (transform);
250            utility.Map.return_object [utility.Map.keys[utility.Map.k]] = Call ("utility.Map.CB", object [utility.Map.keys[utility.Map.k]]);
251        }
252    } else {
253        if (Type (object) == "Matrix") {
254            utility.Map.rows = Rows (object);
255            utility.Map.columns = Columns (object);
256            utility.Map.return_object = {utility.Map.rows,  utility.Map.columns};
257
258            ^(lambda_name) := object [utility.Map.r][utility.Map.c];
259            for (utility.Map.r = 0; utility.Map.r < utility.Map.rows; utility.Map.r += 1) {
260                for (utility.Map.c = 0; utility.Map.c < utility.Map.columns; utility.Map.c += 1) {
261                    utility.Map.temp = Eval (transform);
262                    assert (Type (utility.Map.temp) == "Number" || Type (utility.Map.temp) == "String", "Unsupported object type in call to utility.Map [Matrix]");
263                    utility.Map.return_object [utility.Map.r][utility.Map.c] = utility.Map.temp;
264
265                }
266            }
267
268        }
269    }
270    Eval ("`lambda_name` = None");
271
272    return utility.Map.return_object;
273}
274
275/**
276 * @name utility.MapWithKey
277 * @param {AssociativeList|Matrix} object - object to iterate over
278 * @param {String} lambda_name - variable name for transform
279 * @param {String} transform - function transform
280 */
281function utility.MapWithKey (object, key_name, lambda_name, transform) {
282
283    Eval ("`lambda_name` = None");
284    Eval ("`key_name` = None");
285    utility.MapWithKey.return_object = None;
286
287
288    if (Type (object) == "AssociativeList") {
289        ExecuteCommands ("function  utility.MapWithKey.CB (`key_name`, `lambda_name`) {return `transform`;}", enclosing_namespace);
290        utility.MapWithKey.return_object = {};
291        utility.MapWithKey.keys = Rows (object);
292        for (utility.MapWithKey.k = 0; utility.MapWithKey.k < Abs (object); utility.MapWithKey.k += 1) {
293            utility.MapWithKey.key = utility.MapWithKey.keys[utility.MapWithKey.k];
294            utility.MapWithKey.return_object [utility.MapWithKey.key] = Call ("utility.MapWithKey.CB", utility.MapWithKey.key, object[utility.MapWithKey.key]);
295        }
296    } else {
297        if (Type (object) == "Matrix") {
298            utility.MapWithKey.rows = Rows (object);
299            utility.MapWithKey.columns = Columns (object);
300            utility.MapWithKey.return_object = {utility.MapWithKey.rows,  utility.MapWithKey.columns};
301
302            ^(lambda_name) := object [utility.MapWithKey.r][utility.MapWithKey.c];
303            ^(key_name) := {{utility.MapWithKey.r,utility.MapWithKey.c}};
304            for (utility.MapWithKey.r = 0; utility.MapWithKey.r < utility.MapWithKey.rows; utility.MapWithKey.r += 1) {
305                for (utility.MapWithKey.c = 0; utility.MapWithKey.c < utility.MapWithKey.columns; utility.MapWithKey.c += 1) {
306                    utility.MapWithKey.temp = Eval (transform);
307                    assert (Type (utility.MapWithKey.temp) == "Number" || Type (utility.MapWithKey.temp) == "String", "Unsupported object type in call to utility.MapWithKey [Matrix]");
308                    utility.MapWithKey.return_object [utility.MapWithKey.r][utility.MapWithKey.c] = utility.MapWithKey.temp;
309
310                }
311            }
312
313        }
314    }
315    Eval ("`lambda_name` = None");
316    Eval ("`key_name` = None");
317
318    return utility.MapWithKey.return_object;
319}
320
321/**
322 * @name utility.MatrixToListOfRows
323 * @param {Matrix} object - MxN matrix to convert
324 * @param {Matrix} converted 1 x (M*N) Row vector
325 */
326lfunction utility.MatrixToListOfRows (object) {
327    result = {};
328    rows = Rows (object);
329    cols = Columns (object);
330
331    for (r = 0; r < rows; r += 1) {
332        row = {1, cols};
333        for (c = 0; c < cols; c+=1) {
334            row[c] = object[r][c];
335        }
336        result + row;
337    }
338    return result;
339}
340
341/**
342 * Filters 1xN Matrix or Dictionary
343 * @name utility.Filter
344 * @param {Dictionary|Matrix} object - matrix to convert
345 * @param {String} lambda_name - function to discern whether element is filtered. All elements of iterable object that are false will be removed.
346 * @returns filtered object
347 * @example
348 * _nonnegatives = utility.Filter (_data_vector, "_value_", "_value_ >= 0");
349 */
350function utility.Filter (object, lambda_name, condition) {
351
352    utility.Filter.return_object = None;
353
354    Eval ("`lambda_name` = None");
355
356    utility.Filter.return_object = {};
357    if (Type (object) == "AssociativeList") {
358        utility.Filter.keys = Rows (object);
359        for (utility.Filter.k = 0; utility.Filter.k < Abs (object); utility.Filter.k += 1) {
360           ^(lambda_name) = object [utility.Filter.keys[utility.Filter.k]];
361           if (Eval (condition)) {
362                utility.Filter.return_object [utility.Filter.keys[utility.Filter.k]] = ^(lambda_name);
363            }
364        }
365    } else {
366        if (Type (object) == "Matrix") {
367            utility.Filter.rows = Rows (object);
368            utility.Filter.columns = Columns (object);
369            ^(lambda_name) := object [utility.Filter.r][utility.Filter.c];
370            for (utility.Filter.r = 0; utility.Filter.r < utility.Filter.rows; utility.Filter.r += 1) {
371                for (utility.Filter.c = 0; utility.Filter.c < utility.Filter.columns; utility.Filter.c += 1) {
372                    if (Eval (condition)) {
373                        utility.Filter.return_object + ^(lambda_name);
374                    }
375                }
376            }
377        }
378    }
379    Eval ("`lambda_name` = None");
380    return utility.Filter.return_object;
381}
382
383/**
384 * Find the first element in a matrix or an array that matches the predicate; none otherwise
385 * Keys are traversed alphabetically; matrices, by column - then row
386 * @name utility.First
387 * @param {Dictionary|Matrix} object - matrix to convert
388 * @param {String} lambda_name - function to discern whether element is filtered.
389 * @returns first matched object or none
390 */
391function utility.First (object_utility_first, lambda_name, condition) {
392
393     utility.First.return_object = None;
394
395     Eval ("`lambda_name` = None");
396
397     if (Type (object_utility_first) == "AssociativeList") {
398        utility.First.keys = Rows (object_utility_first);
399        for (utility.First.k = 0; utility.First.k < Abs (object_utility_first); utility.First.k += 1) {
400            ^(lambda_name) = object_utility_first [utility.First.keys[utility.First.k]];
401            if (Eval (condition)) {
402                utility.First.return_object = ^(lambda_name);
403                break;
404            }
405        }
406    }
407
408    if (Type (object_utility_first) == "Matrix") {
409        utility.First.rows = Rows (object_utility_first);
410        utility.First.columns = Columns (object_utility_first);
411        ^(lambda_name) := object_utility_first [utility.First.r][utility.First.c];
412
413        for (utility.First.r = 0; utility.First.r < utility.First.rows; utility.First.r += 1) {
414            for (utility.First.c = 0; utility.First.c < utility.First.columns; utility.First.c += 1) {
415                if (Eval (condition)) {
416                     utility.First.return_object = ^(lambda_name);
417                     break;
418                }
419            }
420        }
421    }
422
423    Eval ("`lambda_name` = None");
424
425    return utility.First.return_object;
426}
427
428/**
429 * @name utility.ForEach
430 * @param {Tree|Dictionary|Matrix} object - matrix to convert
431 * @param {String} lambda_name
432 * @param {String} transform
433 * @returns nothing
434 */
435function utility.ForEach (object, lambda_name, transform) {
436
437    if (Type (object) == "Tree" || Type (object) == "Topology") {
438    	// strip out the root node
439    	utility.ForEach._aux2 = BranchName (object, -1);
440    	utility.ForEach.rows = utility.Array1D (utility.ForEach._aux2) - 1;
441    	utility.ForEach._aux = {utility.ForEach.rows, 1};
442    	for (utility.ForEach.r = 0; utility.ForEach.r < utility.ForEach.rows; utility.ForEach.r += 1) {
443    		utility.ForEach._aux [utility.ForEach.r ] = utility.ForEach._aux2 [utility.ForEach.r ];
444    	}
445
446        DeleteObject (utility.ForEach._aux2);
447        utility.ForEach (utility.ForEach._aux, lambda_name, transform);
448        DeleteObject (utility.ForEach._aux);
449        return;
450    }
451
452    Eval ("`lambda_name` = None");
453
454    if (Type (object) == "AssociativeList") {
455
456
457        utility.ForEach.keys = Rows (object);
458        utility.ForEach.size = Abs (object);
459
460
461        for (utility.ForEach.k = 0; utility.ForEach.k < utility.ForEach.size; utility.ForEach.k += 1) {
462          ^(lambda_name) = object [utility.ForEach.keys[utility.ForEach.k]];
463           ExecuteCommands (transform, enclosing_namespace);
464        }
465    } else {
466
467        if (Type (object) == "Matrix") {
468            utility.ForEach.rows = Rows (object);
469            utility.ForEach.columns = Columns (object);
470
471            if (utility.ForEach.rows && utility.ForEach.columns)  {
472                 ^(lambda_name) := object [utility.ForEach.r][utility.ForEach.c];
473                for (utility.ForEach.r = 0; utility.ForEach.r < utility.ForEach.rows; utility.ForEach.r += 1) {
474                    for (utility.ForEach.c = 0; utility.ForEach.c < utility.ForEach.columns; utility.ForEach.c += 1) {
475                        ExecuteCommands (transform, enclosing_namespace);
476                    }
477                }
478            }
479        }
480    }
481
482    Eval ("`lambda_name` = None");
483}
484
485/**
486 * Checks whether key exists in dictionary
487 * @name utility.KeyExists
488 * @param {Dictionary} dict - dictionary to check
489 * @param {String} key - key to check for existence
490 * @returns {Bool} TRUE if key exists and is of expected type, otherwise FALSE
491 */
492function utility.KeyExists(dict, key) {
493    return dict / key;
494}
495
496/**
497 * Given the lookup string (lookup), maps each character in
498 * string to the index of the same character in lookup (>=0)
499 * or -1 if no such character exists
500 * @name utility.MapStrings
501 * @param {String} string - the string to map
502 * @param {String} lookup - mapping lookup string
503 * @returns {Matrix} the mapping
504 * @example utility.MapStrings ("ABCD","DOBAZ") => {
505 *        "0":3,
506 *        "1":2,
507 *        "2":-1,
508 *        "3":0
509 *       }
510 */
511lfunction utility.MapStrings (string,lookup) {
512
513// source ID -> target ID (-1 means no correspondence)
514
515	mapping 	  = {};
516	targetIndexing = {};
517	_d = Abs(lookup);
518
519	for (_i = 0; _i < _d; _i += 1) {
520		targetIndexing [lookup[_i]] = _i + 1;
521	}
522
523	_d = Abs (string);
524	for (_i = 0; _i < _d; _i += 1) {
525		mapping [_i] = targetIndexing[string[_i]] - 1;
526	}
527
528	return mapping;
529}
530
531/**
532 * Checks whether key is a certain type
533 * @name utility.CheckKey
534 * @param {Dictionary} dict - dictionary to check
535 * @param {String} key - key to check
536 * @param {String} type - check whether key is "Matrix", "AssociativeList", "String", or "Tree"
537 * @returns {Bool} TRUE if key exists and is of expected type, otherwise FALSE
538 */
539function utility.CheckKey (dict, key, type) {
540    if (None != dict) {
541        if (Type (dict[key]) == type) {
542            return TRUE;
543        }
544    }
545    return FALSE;
546}
547
548/**
549 * Adds string or list of strings to a dictionary and sets value to 1
550 * @name utility.AddToSet
551 * @param {AssociativeList} set -
552 * @param {String}, {Matrix}, or {AssociativeList} object
553 * @returns nothing
554 */
555function utility.AddToSet (set, object) {
556
557    if (Type(object) == "String") {
558        set[object] = 1;
559        return;
560    }
561
562    if (Type(object) == "AssociativeList" || Type(object) == "Matrix") {
563        utility.ForEach (object, "_utility.AddToSet.value_", "set[_utility.AddToSet.value_] = 1");
564        return;
565    }
566
567    set ["" + object] = 1;
568
569
570}
571
572/**
573 * Set intersection
574 * @name utility.Intersect
575 * @param {AssociativeList} set - associative list to hold intersection
576 * @param {AssociativeList} set1 - First set to intersect
577 * @param {AssociativeList} set2 - Second set to intersect
578 * @returns nothing
579 */
580function utility.Intersect(set, set1, set2) {
581
582    keys1 = utility.Keys(set1);
583    keys2 = utility.Keys(set2);
584
585    if(Abs(Columns(keys1)) >  Abs(Columns(keys2))) {
586        tmp_keys = keys2;
587        keys2 = keys1;
588        keys1 = tmp_keys;
589    }
590
591    for(k=0; k<Abs(Columns(keys1)); k+=1) {
592        if(utility.Find(keys2, keys1[k]) != -1) {
593            item = keys1[k];
594            set["" + item] = 1;
595        }
596    }
597
598}
599
600
601/**
602 * @name utility.PopulateDict
603 * @param {Number} from
604 * @param {Number} to
605 * @param {Number|AssociativeList|String|Matrix} value
606 * @param {String} lambda
607 * @returns nothing
608 */
609function utility.PopulateDict (from, to, value, lambda) {
610    utility.PopulateDict.result = {};
611    if (Type (lambda) == "String" && Type (value) == "String") {
612        Eval ("`lambda` = None");
613        ^lambda := utility.PopulateDict.k;
614        for (utility.PopulateDict.k = from; utility.PopulateDict.k < to; utility.PopulateDict.k+=1) {
615            utility.PopulateDict.result[utility.PopulateDict.k] = Eval (value);
616        }
617        Eval ("`lambda` = None");
618   }
619    else {
620        for (utility.PopulateDict.k = from; utility.PopulateDict.k < to; utility.PopulateDict.k+=1) {
621            utility.PopulateDict.result[utility.PopulateDict.k] = value;
622        }
623    }
624    return utility.PopulateDict.result;
625}
626
627/**
628 * Iterates over dictionaries
629 * @name utility.ForEachPair
630 * @param {Dictionary} object - the dictionary to iterate over
631 * @param {String} key_name - the variable name for the key in the lambda expression
632 * @param {String} value_name - the variable name for the value in the lambda expression
633 * @param {String} transform - the lambda expression to use
634 * @returns nothing
635 * @example
636 *    utility.ForEachPair (dict, "_key_", "_selection_",
637 *        "fprintf(stdout, _key_);");
638 */
639function utility.ForEachPair(object, key_name, value_name, transform) {
640
641    io.CheckAssertion ("!utility.ForEachPair.warn_non_reentrant", "utility.ForEachPair is non re-entrant");
642    utility.ForEachPair.warn_non_reentrant = TRUE;
643
644    ExecuteCommands ("function  utility.ForEachPair.CB (`key_name`, `value_name`) {`transform`}", enclosing_namespace);
645
646    if (Type (object) == "AssociativeList") {
647        utility.ForEachPair.keys = Rows (object);
648         for (utility.ForEachPair.k = 0; utility.ForEachPair.k < Abs (object); utility.ForEachPair.k += 1) {            //ExecuteCommands (transform, enclosing_namespace);
649            utility.ForEachPair.key = utility.ForEachPair.keys[utility.ForEachPair.k];
650            Call ("utility.ForEachPair.CB",utility.ForEachPair.key , object [utility.ForEachPair.key]);
651        }
652    } else {
653        if (Type (object) == "Matrix") {
654            utility.ForEachPair.rows = Rows (object);
655            utility.ForEachPair.columns = Columns (object);
656
657            if (utility.ForEachPair.rows && utility.ForEachPair.columns) {
658
659                //^(key_name) = {{utility.ForEachPair.r,utility.ForEachPair.c}};
660                //^(value_name) := object [utility.ForEachPair.r][utility.ForEachPair.c];
661                utility.ForEachPair.key = {{utility.ForEachPair.r,utility.ForEachPair.c}};
662                for (utility.ForEachPair.r = 0; utility.ForEachPair.r < utility.ForEachPair.rows; utility.ForEachPair.r += 1) {
663                    for (utility.ForEachPair.c = 0; utility.ForEachPair.c < utility.ForEachPair.columns; utility.ForEachPair.c += 1) {
664                        //ExecuteCommands (transform, enclosing_namespace);
665                        Call ("utility.ForEachPair.CB",utility.ForEachPair.key , object [utility.ForEachPair.r][utility.ForEachPair.c]);
666
667                    }
668                }
669            }
670        }
671    }
672
673    Eval ("`key_name` = None");
674    Eval ("`value_name` = None");
675    // reset bindings here to avoid calls on stale formula in subsequent invocations
676
677    utility.ForEachPair.warn_non_reentrant = FALSE;
678
679}
680
681/**
682 * Returns keys from a dictionary
683 * @name utility.Keys
684 * @param object - {Dictionary} the object to return keys from
685 * @returns {Matrix} List of keys in dictionary
686 * @example
687 *   keys = utility.Keys(absrel.stats);
688 *   keys == {"Count", "Mean", "Median", "Min", "Max", "2.5%", "97.5%", "Sum", "Std.Dev"};
689 */
690lfunction utility.Keys (object) {
691    if (Type (object) == "AssociativeList") {
692        return Rows (object);
693    }
694    return None;
695}
696
697/**
698 * Returns values from a dictionary. Not just unique values and the values aren't coerced to strings.
699 * @name utility.Values
700 * @param object - {Dictionary} the object to return keys from
701 * @returns {Matrix} List of keys in dictionary
702 */
703lfunction utility.Values (object) {
704    if (Type (object) == "AssociativeList") {
705        keys = utility.Keys(object);
706        values = {1,Abs(object)};
707        for(i=0; i<Abs(object); i=i+1) {
708            values[i] = object[keys[i]];
709        }
710        return values;
711    }
712    return None;
713}
714
715/**
716 * Returns values from a dictionary. Only returns unique values
717 * @name utility.UniqueValues
718 * @param object - {Dictionary} the object to return keys from
719 * @returns {Matrix} List of keys in dictionary
720 */
721lfunction utility.UniqueValues (object) {
722    if (Type (object) == "AssociativeList") {
723        return Columns (object);
724    }
725    if (Type (object) == "Matrix") {
726        result = {};
727        utility.ForEach (object, "_value_", "`&result`[_value_] += 1");
728        return Rows (result);
729    }
730    return None;
731}
732
733/**
734 * Ensures a key exists in a dictionary
735 * @name utility.EnsureKey
736 * @param {Dictionary} dict - the object to return keys from
737 * @param {String} key - key to ensure exists
738 * @returns nothing
739 */
740lfunction utility.EnsureKey (dict, key) {
741    if (Type (dict[key]) != "AssociativeList") {
742        dict[key] = {};
743    }
744}
745
746/**
747 * Ensures a key exists in a dictionary
748 * @name utility.Has
749 * @param {Dictionary} d - the object to return keys from
750 * @param {String/Matrix} key - check to see if key is in the dictionary
751 * if the value is a matrix, checks for [key[0]][key[1]][...][key[N]] nested keys
752 * type check is performed on the last level
753 * @param {String/None} type - if specified will further check if the object has the right type
754 * @returns T/F
755 */
756lfunction utility.Has (d, key, type) {
757
758    if (Type (d) == "AssociativeList") {
759        if (Type (key) == "String") {
760            if (d/key) {
761                if (type == None) {
762                    return TRUE;
763                }
764                return Type (d[key]) == type;
765            }
766            return FALSE;
767        }
768
769        if (Type (key) == "Matrix") {
770            depth = utility.Array1D (key);
771            current_check = &d;
772            current_key   = key[0];
773
774            for (i = 1; i < depth; i += 1) {
775                 if (Eval ("`current_check`/'`current_key`'")) {
776                    current_check = "(" + current_check + ")['`current_key`']";
777                    if (Eval ("Type(`current_check`)") != "AssociativeList") {
778                        return FALSE;
779                    }
780                    current_key = key[i];
781                } else {
782                    return FALSE;
783                }
784            }
785
786            if ( Eval ("`current_check`/'`current_key`'") ) {
787                if (type == None) {
788                    return TRUE;
789                }
790                return Eval ("Type((`current_check`)['`current_key`'])") == type;
791            }
792        }
793    }
794    return FALSE;
795}
796
797/**
798 * Ensures a key exists in a dictionary
799 * @name utility.GetByKey
800 * @param {Dictionary} d - the object to return keys from
801 * @param {String/Matrix} key - check to see if key is in the dictionary
802 * if the value is a matrix, checks for [key[0]][key[1]][...][key[N]] nested keys
803 * type check is performed on the last level
804 * @param {String/None} type - if specified will further check if the object has the right type
805 * @returns value mapped to the key or None
806 */
807lfunction utility.GetByKey (d, key, type) {
808
809    if (Type (d) == "AssociativeList") {
810        if (Type (key) == "String") {
811            if (d/key) {
812                if (type == None) {
813                    return d[key];
814                }
815                if (Type (d[key]) == type) {
816                    return d[key];
817                }
818            }
819            return None;
820        }
821
822        if (Type (key) == "Matrix") {
823            depth = utility.Array1D (key);
824            current_check = &d;
825            current_key   = key[0];
826
827            for (i = 1; i < depth; i += 1) {
828                 if (Eval ("`current_check`/'`current_key`'")) {
829                    current_check = "(" + current_check + ")['`current_key`']";
830                    if (Eval ("Type(`current_check`)") != "AssociativeList") {
831                        return FALSE;
832                    }
833                    current_key = key[i];
834                } else {
835                    return FALSE;
836                }
837            }
838
839            if ( Eval ("`current_check`/'`current_key`'") ) {
840                return_value = Eval ("(`current_check`)['`current_key`']");
841                if (type == None) {
842                    return return_value;
843                }
844                if (Type (return_value) == type) {
845                    return return_value;
846                }
847             }
848        }
849    }
850    return None;
851}
852
853/**
854 * Extends a dict with keys from another dict
855 * @name utility.Extend
856 * @param {Dictionary} d - the object to extend
857 * @param {Dictionary} n - the object whose key/value pairs will be added to 'd'
858 * @returns d with new keys added
859 */
860lfunction utility.Extend (d, n) {
861
862    if (Type (d) == "AssociativeList" && Type (n) == "AssociativeList") {
863        nkeys = utility.Keys (n);
864        size = Abs (n);
865        for (i = 0; i < size; i+=1) {
866            if (d/nkeys[i] == FALSE) {
867                d[nkeys[i]] = n[nkeys[i]];
868            }
869        }
870    }
871
872    return d;
873}
874
875
876/**
877 * Returns the list of currently defined variables whose names match a regex
878 * @param selector {String} : reg exp selector; show all if None
879 * @return {MATRIX} : all the selected variables
880 */
881lfunction utility.DefinedVariablesMatchingRegex (selector) {
882    if (Type (selector) == "String") {
883        ExecuteCommands ('GetInformation (`&res`, "`selector`")');
884    } else {
885        GetInformation (res, ".");
886    }
887    return res;
888}
889
890/**
891 * Bin an iterable-type object by value
892 * @param  obj {Dict | Matrix}
893 * @return Dict value->list of keys
894 */
895lfunction utility.BinByValue (obj) {
896    if (Type (obj) == "AssociativeList") {
897        keys  = Rows (obj);
898        count = Abs  (obj);
899        result = {};
900        for (i = 0; i < count; i+=1) {
901            str_value = "" + obj[keys[i]];
902            if (result / str_value) {
903                result [str_value] + keys[i];
904            } else {
905                result [str_value] = {"0" : keys[i]};
906            }
907        }
908        return result;
909    } else {
910        if (Type (obj) == "Matrix") {
911            count = Rows (obj)*Columns (obj);
912            result = {};
913            for (i = 0; i < count; i+=1) {
914                str_value = "" + obj[i];
915                if (result / str_value) {
916                    result [str_value] + i;
917                } else {
918                    result [str_value] = {"0" : i};
919                }
920            }
921        }
922        return result;
923    }
924
925    return None;
926}
927
928
929
930/**
931 * Returns the list of modules loaded with `LoadFunctionLibrary`
932 * param: {String} filter, if provided, will filter the list of library paths via a regexp
933 * @returns a string matrix with (absolute) file paths for loaded modules
934 */
935lfunction utility.GetListOfLoadedModules (filter) {
936    GetString (res, LIST_OF_LOADED_LIBRARIES, -1);
937    if (None != filter) {
938        return utility.UniqueValues (utility.Filter (res, "_path_", "regexp.Find(_path_,`&filter`)"));
939    }
940    return res;
941}
942
943/**
944 * Returns the list of likelihood function IDs that are currently available
945 * param: {String} filter, if provided, will filter the list of library paths via a regexp
946 * @returns a string matrix with (absolute) file paths for loaded modules
947 */
948lfunction utility.GetListOfLoadedLikelihoodFunctions (filter) {
949
950    lf_count = Rows ("LikelihoodFunction");
951
952    res = {lf_count, 1};
953
954    for (k = 0; k < lf_count; k+=1) {
955        GetString (lf_id, LikelihoodFunction, k);
956        res[k] = lf_id;
957    }
958
959    if (None != filter) {
960        return utility.UniqueValues (utility.Filter (res, "_path_", "regexp.Find(_path_,`&filter`)"));
961    }
962    return res;
963}
964
965/**
966 * Execute some commands in the global namespace
967 * @param commands {String} : the commands to execture
968 * @returns None
969 */
970function utility.ExecuteInGlobalNamespace (commands) {
971    ExecuteCommands (commands);
972}
973
974/**
975 * A product function, which takes a list of k variable IDs (dicts)
976 * and returns a dictionary of sets of keys (N1 x N2 x ... Nk)
977 * @param {Dictionary} : a list of variable IDs to scan
978 * @returns {Dictionary} : {"0" : {{"key_11","key_21",...,"key_k1"}}, "1" : {"key_11","key_21",...,"key_k2"}...}
979 * or None if something went wrong
980 */
981lfunction utility.CatersianProduct (arguments) {
982    if (Type (arguments) != "AssociativeList") {
983        return None;
984    }
985
986    arg_count = Abs (arguments);
987
988    if (arg_count == 0) {
989        return None;
990    }
991
992    product = {};
993
994    key_counts = {1,arg_count};
995    arg_keys   = utility.Keys (arguments);
996    key_sets   = {};
997
998    for (k = 0; k < arg_count; k+=1) {
999        this_key = arg_keys[k];
1000        if (Type (arguments[this_key]) != "AssociativeList") {
1001            return None;
1002        }
1003        key_sets   [k] = utility.Keys (arguments[this_key]);
1004        key_counts [k] = Abs (arguments[this_key]);
1005        if (key_counts[k] == 0) {
1006            return None;
1007        }
1008    }
1009
1010    indices = {1,arg_count};
1011    done    = FALSE;
1012
1013    while (1) {
1014        an_item = {};
1015        for (k = 0; k < arg_count; k+=1) {
1016            an_item + (key_sets[k])[indices[k]];
1017        }
1018        product + an_item;
1019
1020        for (k = arg_count - 1; k >= 0; k = k - 1) {
1021            indices [k] += 1;
1022            if (indices[k] == key_counts[k]) {
1023                indices[k] = 0;
1024            } else {
1025                break;
1026            }
1027        }
1028
1029        if (k < 0) {
1030            break;
1031        }
1032
1033    }
1034
1035    return product;
1036}
1037
1038function _sortStringsAux (theKey, theValue) {
1039
1040 	for (_gb_idx2 = 0; _gb_idx2 < theValue; _gb_idx2 += 1) {
1041		_gb_sortedStrings [_gb_idx] = theKey;
1042		_gb_idx += 1;
1043	}
1044	return 0;
1045}
1046
1047function utility.sortStrings (_theList) {
1048	_gb_dim = Rows (_theList)*Columns (_theList);
1049	_toSort = {};
1050	for (_gb_idx = 0; _gb_idx < _gb_dim; _gb_idx = _gb_idx + 1) {
1051		_toSort[_theList[_gb_idx]] = _toSort[_theList[_gb_idx]]+1;
1052	}
1053	_gb_sortedStrings = {_gb_dim,1};
1054	_gb_idx = 0;
1055	_toSort["_sortStringsAux"][""];
1056	return _gb_sortedStrings;
1057}
1058
1059
1060function utility.FinishAndPrintProfile (_hyphy_profile_dump) {
1061    stats  			= _hyphy_profile_dump["STATS"];
1062    _profile_summer = ({1,Rows(stats)}["1"]) * stats;
1063    _instructions   = _hyphy_profile_dump["INSTRUCTION"];
1064    _indices	    = _hyphy_profile_dump["INSTRUCTION INDEX"];
1065
1066    fprintf (stdout, "\nTotal run time (seconds)      : ", Format(_profile_summer[1],15,6),
1067                     "\nTotal number of steps         : ", Format(_profile_summer[0],15,0), "\n\n");
1068
1069    to_sort        =  stats["-_MATRIX_ELEMENT_VALUE_*_MATRIX_ELEMENT_COLUMN_+(_MATRIX_ELEMENT_COLUMN_==0)*_MATRIX_ELEMENT_ROW_"] % 1;
1070
1071    for (k=0; k<Columns(_instructions); k=k+1)
1072    {
1073        k2 = to_sort[k][0];
1074        fprintf (stdout, Format (_indices[k2],6,0), " : ", _instructions[k2], "\n\tCall count: ", stats[k2][0],
1075                                                       "\n\tTime (seconds): ", stats[k2][1], "\n");
1076    }
1077}
1078
1079function utility.TrapAllErrors (command) {
1080
1081    LAST_HBL_EXECUTION_ERROR = "";
1082    ExecuteCommands ("SetParameter(HBL_EXECUTION_ERROR_HANDLING,1,0);" + command);
1083    return LAST_HBL_EXECUTION_ERROR;
1084}
1085
1086