siafun
Version:
A collection of structure induction algorithms
120 lines (119 loc) • 4.96 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const util_1 = require("./util");
class Hierarchizer {
/** assumes that all occurrences of segments are of the same length! */
inferHierarchyFromPatterns(patterns) {
let segments = this.patternsToSegmentations(patterns);
//segments.forEach(s => this.processSegmentPair(s));
segments = this.processOverlaps(segments);
//TODO NOW BUILD HIERARCHY
}
inferHierarchyFromSegmentMatrix(matrix) {
const size = [matrix.length, matrix[0].length];
const hierarchy = this.buildHierarchy(this.matrixToSegmentations(matrix));
return this.segmentationsToMatrix(hierarchy, size);
}
buildHierarchy(segments, minSegLength = 4, divFactor = 2) {
//sort by length and first translation vector
segments = this.filterAndSortSegmentations(segments, minSegLength, divFactor);
const hierarchy = [];
while (segments.length > 0) {
const next = segments.shift();
hierarchy.push(next);
const newBorders = _.uniq(_.flatten([next.p].concat(next.ts.map(t => next.p + t)).map(t => [t, t + next.l])));
segments = newBorders.reduce((segs, b) => _.flatten(segs.map(s => this.divideAtPos(s, b))), segments);
segments = this.filterAndSortSegmentations(segments, minSegLength, divFactor);
}
return hierarchy;
}
filterAndSortSegmentations(segmentations, minSegLength, divFactor) {
segmentations = segmentations.filter(s => s.l >= minSegLength && s.ts.every(t => util_1.modForReal(t, divFactor) == 0));
return _.reverse(_.sortBy(segmentations, s => s.l));
}
patternsToSegmentations(patterns) {
return patterns.map(p => this.toSegmentation(p));
}
matrixToSegmentations(matrix) {
let points = _.flatten(matrix.map((row, i) => row.map((val, j) => [i, j, val])));
points = points.filter(p => p[1] > p[0] && p[2] > 0);
points = _.sortBy(points, p => p[1] - p[0]);
let segments = points.reduce((segs, p) => {
const prev = _.last(_.last(segs)) || [0, 0, 0];
p[0] - prev[0] == 1 && p[1] - prev[1] == 1 ?
_.last(segs).push(p.slice(0, 2)) : segs.push([p.slice(0, 2)]);
return segs;
}, []);
segments = _.reverse(_.sortBy(segments, s => s.length));
return segments.map(s => this.alignmentToSegmentation(s));
}
segmentationsToMatrix(segmentations, size) {
const matrix = _.range(0, size[0]).map(_i => _.range(0, size[1]).map(_j => 0));
segmentations.forEach(s => _.range(0, s.l).forEach(i => s.ts.forEach(t => {
matrix[s.p + i][s.p + t + i] = 1;
matrix[s.p + t + i][s.p + i] = 1;
})));
return matrix;
}
//only keeps full occurrences TODO split off incomplete occurrences
alignmentToSegmentation(a) {
const position = a[0][0];
const interval = a[0][1] - a[0][0];
const length = Math.min(a.length, interval);
const numCopies = Math.floor(a.length / length);
const vectors = _.range(0, numCopies).map(t => ((t + 1) * interval));
return { p: position, l: length, ts: vectors };
}
/*private patternToSegments(segmentPair: number[][]) {
let newSegments = [this.toSegmentation(segmentPair)];
newSegments = this.processOverlaps(newSegments);
this.segmentations.push();
}*/
updateSegmentations() {
//this.processOverlaps();
//this.mergePatterns();
}
toSegmentation(pattern) {
const length = _.last(pattern[0]) - pattern[0][0];
return {
p: pattern[0][0],
l: length,
ts: pattern.slice(1).map(p => p[0] - pattern[0][0])
};
}
processOverlaps(segmentations) {
return _.flatten(segmentations.map(s => this.split(s)));
}
split(s) {
const segs = [];
let ts = _.min(s.ts);
while (s.l > ts) {
const div = this.divide(s, ts);
segs.push(div[0]);
s = div[1];
}
segs.push(s);
return segs;
}
divideAtPos(s, pos) {
const loc = [s.p].concat(s.ts.map(t => s.p + t)).map(p => p < pos && pos < p + s.l - 1 ? pos - p : -1).filter(loc => loc > -1);
return loc.length > 0 ? this.divide(s, loc[0]) : [s];
}
/** divides the segmentation s at position loc */
divide(s, loc) {
if (0 < loc && loc < s.l - 1) {
return [{ p: s.p, l: loc, ts: s.ts }, { p: s.p + loc, l: s.l - loc, ts: s.ts }];
}
return [s];
}
merge(s1, s2) {
if (s1.p == s2.p) {
let minL = Math.min(s1.l, s2.l);
let s1div = this.divide(s1, minL);
let s2div = this.divide(s2, minL);
return [s1div[0]];
}
}
}
exports.Hierarchizer = Hierarchizer;