UNPKG

siafun

Version:
93 lines (92 loc) 4.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _ = require("lodash"); const arrayutils_1 = require("arrayutils"); const siatec_1 = require("./siatec"); const heuristics_1 = require("./heuristics"); const util_1 = require("./util"); function cosiatec(points, options = {}, siatecResult) { if (!options.selectionHeuristic) options.selectionHeuristic = heuristics_1.HEURISTICS.COMPACTNESS; points = getSortedCloneWithoutDupes(points); const result = cosiatecLoop(points, options, siatecResult ? siatecResult.patterns : null); if (options.loggingLevel > 1) logResult(result); return result; } exports.cosiatec = cosiatec; /** * returns an array of pairs of patterns along with their transpositions * overlapping false: original cosiatec: performs sia iteratively on remaining points, returns the best patterns of each step * overlapping true: jamie's cosiatec: performs sia only once, returns the best patterns necessary to cover all points * numPatterns defined: returns the n best overlapping cosiatec patterns, plus more if n larger than the number of cosiatec patterns */ function cosiatecLoop(points, options, patterns) { const result = { points: points, patterns: [], scores: [], minPatternLength: options.minPatternLength }; let remainingPoints = points; //IN NON-OVERLAPPING THERE IS NO OPTIMIZATION SO FAR!!!! patterns = patterns || siatec_1.siatec(remainingPoints, options.minPatternLength).patterns; let scores = patterns.map(p => options.selectionHeuristic(p, remainingPoints)); while (patterns.length > 0 && remainingPoints.length > 0 && (!options.numPatterns || result.patterns.length < options.numPatterns)) { const iOfBestScore = arrayutils_1.indexOfMax(scores); const bestPattern = patterns[iOfBestScore]; const previousLength = remainingPoints.length; remainingPoints = getComplement(bestPattern, remainingPoints); //only add to results if the pattern includes points in no other pattern //always true in non-overlapping cosiatec and if numPatterns higher than cosiatec patterns //if ignoreNovelty is true, add anyway if (previousLength > remainingPoints.length || options.ignoreNovelty) { if (options.loggingLevel > 1) logPointsAndPatterns(remainingPoints, patterns); result.patterns.push(bestPattern); result.scores.push(scores[iOfBestScore]); } if (options.overlapping || options.ignoreNovelty) { //remove best pattern and score [patterns, scores].forEach(a => a.splice(iOfBestScore, 1)); } else { //recalculate siatec and heuristics on remaining points patterns = siatec_1.siatec(remainingPoints, options.minPatternLength).patterns; scores = patterns.map(p => options.selectionHeuristic(p, remainingPoints)); } } //add more patterns if necessary, but only ones with differing point sets if (options.numPatterns && result.patterns.length < options.numPatterns) { const patternStrings = result.patterns.map(p => util_1.toOrderedPointString(p.points)); while (patterns.length > 0 && result.patterns.length < options.numPatterns) { const iOfBestScore = arrayutils_1.indexOfMax(scores); const bestPattern = patterns[iOfBestScore]; const bestPatternString = util_1.toOrderedPointString(bestPattern.points); if (patternStrings.indexOf(bestPatternString) < 0) { //console.log(toOrderedPointString(bestPattern))//, patternStrings); result.patterns.push(bestPattern); result.scores.push(scores[iOfBestScore]); patternStrings.push(bestPatternString); } [patterns, scores].forEach(a => a.splice(iOfBestScore, 1)); } } return result; } /** returns the complement of the pattern in points */ function getComplement(pattern, points) { const involvedPoints = new Set(_.flatten(pattern.occurrences) .map(p => JSON.stringify(p))); return points.map(p => JSON.stringify(p)) .filter(p => !involvedPoints.has(p)).map(p => JSON.parse(p)); } function getSortedCloneWithoutDupes(array) { var clone = _.uniq(array); clone.sort(arrayutils_1.compareArrays); return clone; } function logPointsAndPatterns(points, patterns) { console.log("remaining:", points.length, "patterns:", patterns.length, "max length:", _.max(patterns.map(p => p.points.length))); } function logResult(result) { console.log("patterns (length, occurrences, vector, heuristic):"); result.patterns.forEach((p, i) => console.log(" " + p.points.length + ", " + p.occurrences.length + ", " + p.vectors[1] + ", " + _.round(result.scores[i], 2))); }