siafun
Version:
A collection of structure induction algorithms
92 lines (91 loc) • 3.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const arrayutils_1 = require("arrayutils");
const util_1 = require("./util");
function siatec(points, minPatternLength = 0, removeRedundant = true) {
let vectorTable = getVectorTable(points);
let patterns = calculateSiaPatterns(vectorTable);
//remove short patterns
patterns = patterns.filter(p => p.length >= minPatternLength);
//calculate vectors
const vectors = getVectorMap(points, patterns, vectorTable);
vectorTable = null; //release memory
//calculate occurrences
let occs = [];
for (let i = 0; i < patterns.length; i += 1000) {
occs.push(toOccs(patterns.slice(i, i + 1000), vectors));
}
let occurrences = new Map(_.zip(patterns, _.flatten(occs)));
//remove redundant
if (removeRedundant) {
const reduced = {};
patterns.forEach(p => {
const stringO = JSON.stringify(occurrences.get(p));
if (!reduced[stringO] || vectors.get(p).length > vectors.get(reduced[stringO]).length) {
reduced[stringO] = p;
}
});
//console.log('removed redundant:', patterns.length-_.values(reduced).length, 'of', patterns.length)
patterns = _.values(reduced);
}
//console.log("RETURN")
return {
points: points,
minPatternLength: minPatternLength,
patterns: patterns.map((p, i) => ({
points: p,
vectors: vectors.get(p),
occurrences: occurrences.get(p)
}))
};
}
exports.siatec = siatec;
function toOccs(patterns, vectors) {
return patterns.map(p => vectors.get(p).map(v => p.map(point => point.map((p, k) => p + v[k]))));
}
function getVectorMap(points, patterns, vectorTable) {
const vectors = calculateSiatecOccurrences(points, patterns, vectorTable)
.map(i => i.map(v => v.map(e => _.round(e, 8)))); //eliminate float errors
return new Map(_.zip(patterns, vectors));
}
function getVectorTable(points) {
return points.map(p => points.map(q => [_.zipWith(q, p, _.subtract), p]));
}
//returns a list with the sia patterns detected for the given points
function calculateSiaPatterns(vectorTable) {
//get all the vectors below the diagonal of the translation matrix
var halfTable = vectorTable.map((col, i) => col.slice(i + 1));
//transform into a sorted list by merging the table's columns
var vectorList = arrayutils_1.mergeSortedArrays(halfTable);
//group by translation vectors
var patternMap = groupByKeys(vectorList);
//get the map's values, get rid of duplicates
return _.uniq(_.values(patternMap).map(util_1.toOrderedPointString))
.map(p => JSON.parse(p));
}
//returns a list with the
function calculateSiatecOccurrences(points, pointSets, vectorTable) {
var vectorMap = new Map();
points.forEach((v, i) => vectorMap.set(JSON.stringify(v), i));
//get rid of points of origin in vector table
var fullTable = vectorTable.map(col => col.map(row => row[0]));
var translations = pointSets.map(pat => pat.map(point => fullTable[vectorMap.get(JSON.stringify(point))]));
return translations.map(occ => getIntersection(occ));
}
//takes an array of arrays of vectors and calculates their intersection
function getIntersection(vectors) {
if (vectors.length > 1) {
var isect = vectors.slice(1).reduce((isect, tsls) => arrayutils_1.intersectSortedArrays(isect, tsls), vectors[0]);
return isect;
}
return vectors[0];
}
function groupByKeys(vectors) {
return vectors.reduce((grouped, item) => {
var key = JSON.stringify(item[0]);
grouped[key] = grouped[key] || [];
grouped[key].push(item[1]);
return grouped;
}, {});
}