siafun
Version:
A collection of structure induction algorithms
93 lines (92 loc) • 4.87 kB
JavaScript
;
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)));
}