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