// // Copyright 2022 SenX S.A.S. // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, version 3. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see // { 'desc' 'Returns up to max_n discordant patterns' 'sig' [ [ [ 'profile:GTS' 'max_n:LONG' 'excl_zone:LONG' ] [ 'result:GTS' ] ] ] 'name' 'discords' 'examples' [] } '.info' STORE <% !$.info INFO SAVE 'context' STORE [ 'gts' 'max_n' 'zone' ] STORE // Macro that checks if input GTS has 3 values // and return middle value if it is the strict max (or else return NULL) <% VALUES 'val' STORE $val SIZE 3 == DUP <% $val 1 GET $val 0 GET > && $val 1 GET $val 2 GET > && %> IFT <% $val 1 GET %> <% NULL %> IFTE %> 'isMiddleMax' STORE // Keep local maximums [ $gts <% 0 NaN NaN NaN 5 ROLL @isMiddleMax %> 1 1 0 ] MAP 0 GET 'lmax' STORE $lmax SIZE 0 > <% // Sort ticks by descending value [ $lmax TICKLIST $lmax VALUES ] ZIP <% 1 GET -1 * %> SORTBY 'result' STORE // exlude ticks that are in the exclusion zone of better ones $result 0 REMOVE 'previous' STORE 'remainder' STORE [ $previous ] 'result2' STORE $remainder <% 'current' STORE // current should not be in the zone of each element from result2 true $result2 <% 'toCompare' STORE $current 0 GET $toCompare 0 GET - ABS $zone <= <% ! BREAK %> IFT %> FOREACH <% $result2 $current +! DROP %> IFT %> FOREACH // return gts of best candidates $gts CLONEEMPTY '+:discords' RENAME 1 $max_n $result2 SIZE MIN <% $result2 SWAP 1 - GET ADDVALUE %> FOR SORT %> <% // return empty gts $gts CLONEEMPTY '+:discords' RENAME %> IFTE $context RESTORE %>