mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
cc9fb3b5bf
- Bug 1152454 - Made liveregions responsive to name/value change events. r=yzen (056df463ef) - Bug 1166321 - [AccessFu] adding support for role='switch'. r=eeejay (540831bb6a) - Bug 1179284 - using explicit label for accessible with role 'status' instead of subtree. r=eeejay (919f0b93e7) - Bug 1163374 - Basic MathML Accessibility support in AccessFu. r=yzen (cddbfee120) - Bug 1199884 - Keep match roles empty in BaseTraversalRules that don't provide roles. r=yzen (b80ff3c892) - Bug 1200836 - Land on first atomic object in container traversal. r=yzen (0243a695af) - Bug 1206491 - Fix a JavaScript error in about:cache page. r=mayhemmer (5eaa374c84) - Bug 1142174 - Normalize omni.ja! paths when diffing about:memory reports. r=njn (bf046c4958) - let-var (5e9cf0b098) - Bug 1205364 part 1. Make createAttribute in an HTML document lowercase the passed-in attribute name. r=smaug (0b8a9f0f60) - Bug 647621 - Implement document.charset and update document.inputEncoding to the latest spec. r=bz (e31fd9f567) - Bug 647621 - Remove document.charset from historical.html because it was eventually added to the spec. r=Ms2ger (506ecf3238) - Bug 1201798 part 1 - Move PropagateScrollToViewport() from nsCSSFrameConstructor to nsPresContext as a public method. r=roc (5d33acfa26) - Bug 1201798 part 2 - Update viewport scrollbar override for fullscreen and remove the leagcy css rule. r=roc (852d3d181f) - Bug 1201798 part 3 - Add test for viewport scrollbar on fullscreen. r=roc (88ad5560ae) - Bug 1048622 - Fix 'assignment to undefined variable' warnings in nsBrowserContentHandler.js. r=gavin (55edf093ce) - Bug 1205328: undef min/max at the top of irregexp/RegExpAST.h if they're already defined; r=ehsan (2a5daa48a9) - Bug 773687 - Fix assertion pattern in RegExp with sticky flag. r=till (0f1643690b) - Bug 1084248 - add a cast<> method, remove the casting constructor as requested. r=waldo (3fb0619085) - cleanup (705296cc44) - Bug 1143512 - Remove unused declaration of regexp_flags. r=jandem (79f538a4c8) - bit of 1198193 and pointer styles (6bec08ca9e) - Bug 1146580 - Make FinalizationWitnessService listen for xpcom shutdown. r=bholley (6a4093bf23) - Bug 1199578 - include SharedTypedArray in a type test. r=waldo (94b943eb91) - Bug 1203791 - Fix LazyLink issue with Debugger::onIonCompilation. r=h4writer (3d5c4ee130) - pointer style (f24eb566fd) - Bug 1204726 - Make sure that the MacroAssembler is no longer rooted when onIonCompilation is called. r=h4writer (f697b11f6d) - Bug 1206418 - Fix origin of animations and scissors for preserves3d. r=roc (1813cc2c21)
249 lines
8.4 KiB
JavaScript
249 lines
8.4 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/**
|
|
* Class that can run the hierarchical clustering algorithm with the given
|
|
* parameters.
|
|
*
|
|
* @param distance
|
|
* Function that should return the distance between two items.
|
|
* Defaults to clusterlib.euclidean_distance.
|
|
* @param merge
|
|
* Function that should take in two items and return a merged one.
|
|
* Defaults to clusterlib.average_linkage.
|
|
* @param threshold
|
|
* The maximum distance between two items for which their clusters
|
|
* can be merged.
|
|
*/
|
|
function HierarchicalClustering(distance, merge, threshold) {
|
|
this.distance = distance || clusterlib.euclidean_distance;
|
|
this.merge = merge || clusterlib.average_linkage;
|
|
this.threshold = threshold == undefined ? Infinity : threshold;
|
|
}
|
|
|
|
HierarchicalClustering.prototype = {
|
|
/**
|
|
* Run the hierarchical clustering algorithm on the given items to produce
|
|
* a final set of clusters. Uses the parameters set in the constructor.
|
|
*
|
|
* @param items
|
|
* An array of "things" to cluster - this is the domain-specific
|
|
* collection you're trying to cluster (colors, points, etc.)
|
|
* @param snapshotGap
|
|
* How many iterations of the clustering algorithm to wait between
|
|
* calling the snapshotCallback
|
|
* @param snapshotCallback
|
|
* If provided, will be called as clusters are merged to let you view
|
|
* the progress of the algorithm. Passed the current array of
|
|
* clusters, cached distances, and cached closest clusters.
|
|
*
|
|
* @return An array of merged clusters. The represented item can be
|
|
* found in the "item" property of the cluster.
|
|
*/
|
|
cluster: function HC_cluster(items, snapshotGap, snapshotCallback) {
|
|
// array of all remaining clusters
|
|
let clusters = [];
|
|
// 2D matrix of distances between each pair of clusters, indexed by key
|
|
let distances = [];
|
|
// closest cluster key for each cluster, indexed by key
|
|
let neighbors = [];
|
|
// an array of all clusters, but indexed by key
|
|
let clustersByKey = [];
|
|
|
|
// set up clusters from the initial items array
|
|
for (let index = 0; index < items.length; index++) {
|
|
let cluster = {
|
|
// the item this cluster represents
|
|
item: items[index],
|
|
// a unique key for this cluster, stays constant unless merged itself
|
|
key: index,
|
|
// index of cluster in clusters array, can change during any merge
|
|
index: index,
|
|
// how many clusters have been merged into this one
|
|
size: 1
|
|
};
|
|
clusters[index] = cluster;
|
|
clustersByKey[index] = cluster;
|
|
distances[index] = [];
|
|
neighbors[index] = 0;
|
|
}
|
|
|
|
// initialize distance matrix and cached neighbors
|
|
for (let i = 0; i < clusters.length; i++) {
|
|
for (let j = 0; j <= i; j++) {
|
|
var dist = (i == j) ? Infinity :
|
|
this.distance(clusters[i].item, clusters[j].item);
|
|
distances[i][j] = dist;
|
|
distances[j][i] = dist;
|
|
|
|
if (dist < distances[i][neighbors[i]]) {
|
|
neighbors[i] = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
// merge the next two closest clusters until none of them are close enough
|
|
let next = null, i = 0;
|
|
for (; next = this.closestClusters(clusters, distances, neighbors); i++) {
|
|
if (snapshotCallback && (i % snapshotGap) == 0) {
|
|
snapshotCallback(clusters);
|
|
}
|
|
this.mergeClusters(clusters, distances, neighbors, clustersByKey,
|
|
clustersByKey[next[0]], clustersByKey[next[1]]);
|
|
}
|
|
return clusters;
|
|
},
|
|
|
|
/**
|
|
* Once we decide to merge two clusters in the cluster method, actually
|
|
* merge them. Alters the given state of the algorithm.
|
|
*
|
|
* @param clusters
|
|
* The array of all remaining clusters
|
|
* @param distances
|
|
* Cached distances between pairs of clusters
|
|
* @param neighbors
|
|
* Cached closest clusters
|
|
* @param clustersByKey
|
|
* Array of all clusters, indexed by key
|
|
* @param cluster1
|
|
* First cluster to merge
|
|
* @param cluster2
|
|
* Second cluster to merge
|
|
*/
|
|
mergeClusters: function HC_mergeClus(clusters, distances, neighbors,
|
|
clustersByKey, cluster1, cluster2) {
|
|
let merged = { item: this.merge(cluster1.item, cluster2.item),
|
|
left: cluster1,
|
|
right: cluster2,
|
|
key: cluster1.key,
|
|
size: cluster1.size + cluster2.size };
|
|
|
|
clusters[cluster1.index] = merged;
|
|
clusters.splice(cluster2.index, 1);
|
|
clustersByKey[cluster1.key] = merged;
|
|
|
|
// update distances with new merged cluster
|
|
for (let i = 0; i < clusters.length; i++) {
|
|
var ci = clusters[i];
|
|
var dist;
|
|
if (cluster1.key == ci.key) {
|
|
dist = Infinity;
|
|
} else if (this.merge == clusterlib.single_linkage) {
|
|
dist = distances[cluster1.key][ci.key];
|
|
if (distances[cluster1.key][ci.key] >
|
|
distances[cluster2.key][ci.key]) {
|
|
dist = distances[cluster2.key][ci.key];
|
|
}
|
|
} else if (this.merge == clusterlib.complete_linkage) {
|
|
dist = distances[cluster1.key][ci.key];
|
|
if (distances[cluster1.key][ci.key] <
|
|
distances[cluster2.key][ci.key]) {
|
|
dist = distances[cluster2.key][ci.key];
|
|
}
|
|
} else if (this.merge == clusterlib.average_linkage) {
|
|
dist = (distances[cluster1.key][ci.key] * cluster1.size
|
|
+ distances[cluster2.key][ci.key] * cluster2.size)
|
|
/ (cluster1.size + cluster2.size);
|
|
} else {
|
|
dist = this.distance(ci.item, cluster1.item);
|
|
}
|
|
|
|
distances[cluster1.key][ci.key] = distances[ci.key][cluster1.key]
|
|
= dist;
|
|
}
|
|
|
|
// update cached neighbors
|
|
for (let i = 0; i < clusters.length; i++) {
|
|
var key1 = clusters[i].key;
|
|
if (neighbors[key1] == cluster1.key ||
|
|
neighbors[key1] == cluster2.key) {
|
|
let minKey = key1;
|
|
for (let j = 0; j < clusters.length; j++) {
|
|
var key2 = clusters[j].key;
|
|
if (distances[key1][key2] < distances[key1][minKey]) {
|
|
minKey = key2;
|
|
}
|
|
}
|
|
neighbors[key1] = minKey;
|
|
}
|
|
clusters[i].index = i;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Given the current state of the algorithm, return the keys of the two
|
|
* clusters that are closest to each other so we know which ones to merge
|
|
* next.
|
|
*
|
|
* @param clusters
|
|
* The array of all remaining clusters
|
|
* @param distances
|
|
* Cached distances between pairs of clusters
|
|
* @param neighbors
|
|
* Cached closest clusters
|
|
*
|
|
* @return An array of two keys of clusters to merge, or null if there are
|
|
* no more clusters close enough to merge
|
|
*/
|
|
closestClusters: function HC_closestClus(clusters, distances, neighbors) {
|
|
let minKey = 0, minDist = Infinity;
|
|
for (let i = 0; i < clusters.length; i++) {
|
|
var key = clusters[i].key;
|
|
if (distances[key][neighbors[key]] < minDist) {
|
|
minKey = key;
|
|
minDist = distances[key][neighbors[key]];
|
|
}
|
|
}
|
|
if (minDist < this.threshold) {
|
|
return [minKey, neighbors[minKey]];
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
var clusterlib = {
|
|
hcluster: function hcluster(items, distance, merge, threshold, snapshotGap,
|
|
snapshotCallback) {
|
|
return (new HierarchicalClustering(distance, merge, threshold))
|
|
.cluster(items, snapshotGap, snapshotCallback);
|
|
},
|
|
|
|
single_linkage: function single_linkage(cluster1, cluster2) {
|
|
return cluster1;
|
|
},
|
|
|
|
complete_linkage: function complete_linkage(cluster1, cluster2) {
|
|
return cluster1;
|
|
},
|
|
|
|
average_linkage: function average_linkage(cluster1, cluster2) {
|
|
return cluster1;
|
|
},
|
|
|
|
euclidean_distance: function euclidean_distance(v1, v2) {
|
|
let total = 0;
|
|
for (let i = 0; i < v1.length; i++) {
|
|
total += Math.pow(v2[i] - v1[i], 2);
|
|
}
|
|
return Math.sqrt(total);
|
|
},
|
|
|
|
manhattan_distance: function manhattan_distance(v1, v2) {
|
|
let total = 0;
|
|
for (let i = 0; i < v1.length; i++) {
|
|
total += Math.abs(v2[i] - v1[i]);
|
|
}
|
|
return total;
|
|
},
|
|
|
|
max_distance: function max_distance(v1, v2) {
|
|
let max = 0;
|
|
for (let i = 0; i < v1.length; i++) {
|
|
max = Math.max(max, Math.abs(v2[i] - v1[i]));
|
|
}
|
|
return max;
|
|
}
|
|
};
|