feat: no reference point any more, better docs

This commit is contained in:
NunoSempere 2022-04-11 15:37:58 -04:00
parent 5f9225538c
commit a141e1e144
2 changed files with 77 additions and 15 deletions

View File

@ -1,24 +1,21 @@
## About ## About
This repository creates a react webpage that allows to extract a utility function from possibly inconsistent binary comparisons
This repository creates a react webpage that allows to extract a utility function from possibly inconsistent binary comparisons. It presents the users with a series of elements to compare, using merge-sort in the background to cleverly minimize the number of choices needed. Then, it cleverly aggregates them, by taking each element as a reference point in turn, and computing the possible distances from that reference point to all other points, and taking the geometric mean of these distances. This produces a number representing the value of each element, such that the ratios between elements represent the user's preferences: a utility function!
Initially, users could only input numbers, e.g., "A is `3` times better than B". But now, users can also input distributions, using the [squiggle]() syntax, e.g., "A is `1 to 10` times better than B", or "A is `mm(normal(1, 10), uniform(0,100))` better than B".
## Object structure ## Object structure
The core structure is json array of objects. Only the "name" attribute is required; the (numerical) id is also internally required but it's created on the fly. The reason that ids are needed is that comparing objects is annoying.
The `isReferenceValue` property determines the display at the end, but it is optional. The core structure is json array of objects. Only the "name" attribute is required. If there is a "url", it is displayed nicely.
So internally this would look like:
``` ```
[ [
{ {
"id": 1,
"name": "Peter Parker", "name": "Peter Parker",
"someOptionalKey": "...", "someOptionalKey": "...",
"anotherMoreOptionalKey": "...", "anotherMoreOptionalKey": "...",
"isReferenceValue": true
}, },
{ {
"id": 2,
"name": "Spiderman", "name": "Spiderman",
"someOptionalKey": "...", "someOptionalKey": "...",
"anotherMoreOptionalKey": "..." "anotherMoreOptionalKey": "..."
@ -27,4 +24,5 @@ So internally this would look like:
``` ```
## Netlify ## Netlify
https://github.com/netlify/netlify-plugin-nextjs/#readme https://github.com/netlify/netlify-plugin-nextjs/#readme

View File

@ -150,7 +150,7 @@ async function findPaths({
return paths; return paths;
} }
async function findDistance({ async function findDistancesForElement({
sourceElementId, sourceElementId,
sourceElementPosition, sourceElementPosition,
targetElementId, targetElementId,
@ -199,6 +199,7 @@ async function findDistance({
} }
async function findDistancesForAllElements({ nodes, links }) { async function findDistancesForAllElements({ nodes, links }) {
// legacy. I used to need a somewhat hardcoded reference point. Now that's not necessary.
// Simple wrapper function around findDistance // Simple wrapper function around findDistance
// Needs to find the reference point first // Needs to find the reference point first
console.log("findDistancesForAllElements@findPaths.js"); console.log("findDistancesForAllElements@findPaths.js");
@ -210,13 +211,13 @@ async function findDistancesForAllElements({ nodes, links }) {
console.log(`referenceElement.position: ${referenceElement.position}`); console.log(`referenceElement.position: ${referenceElement.position}`);
/* Get distances. */ /* Get distances. */
let distances = nodes.map((node) => { let distancesArray = nodes.map((node) => {
if (node.isReferenceValue || node.id == referenceElement.id) { if (node.isReferenceValue || node.id == referenceElement.id) {
return [1]; return [1];
} else { } else {
console.log("node"); console.log("node");
console.log(node); console.log(node);
let distance = findDistance({ let distancesForElement = findDistancesForElement({
sourceElementId: referenceElement.id, sourceElementId: referenceElement.id,
sourceElementPosition: referenceElement.position, sourceElementPosition: referenceElement.position,
targetElementId: node.id, targetElementId: node.id,
@ -224,11 +225,71 @@ async function findDistancesForAllElements({ nodes, links }) {
nodes: nodes, nodes: nodes,
links: links, links: links,
}); });
return distance; return distancesForElement;
} }
}); });
distances = await Promise.all(distances); distancesArray = await Promise.all(distancesArray);
return distances; return distancesArray;
}
async function findDistancesFromAllElementsToReferencePoint({
nodes,
links,
referenceElement,
}) {
// Simple wrapper function around findDistance
// Needs to find the reference point first
console.log("findDistancesForAllElements@findPaths.js");
/* Get or build reference element */
let midpoint = Math.round(nodes.length / 2);
referenceElement = referenceElement || nodes[midpoint];
console.log(`referenceElement.position: ${referenceElement.position}`);
/* Get distances. */
let distancesArray = nodes.map((node) => {
if (node.id == referenceElement.id) {
return [1];
} else {
console.log("node");
console.log(node);
let distancesForElement = findDistancesForElement({
sourceElementId: referenceElement.id,
sourceElementPosition: referenceElement.position,
targetElementId: node.id,
targetElementPosition: node.position,
nodes: nodes,
links: links,
});
return distancesForElement;
}
});
distancesArray = await Promise.all(distancesArray);
return distancesArray;
}
async function findDistancesFromAllElementsToAllReferencePoints({
nodes,
links,
}) {
let nodes2 = nodes.map((node) => ({ ...node, isReferenceValue: false }));
let distancesForAllElements = Array(nodes.length);
for (let i = 0; i < nodes.length; i++) {
distancesForAllElements[i] = [];
}
for (let node of nodes2) {
let distancesFromNode = await findDistancesFromAllElementsToReferencePoint({
nodes,
links,
referenceElement: node,
});
// alert(`distancesFromNode.length: ${distancesFromNode.length}`);
distancesForAllElements = distancesForAllElements.map((arr, i) => {
return !!arr && arr.length > 0
? [...arr, ...distancesFromNode[i]]
: distancesFromNode[i];
});
}
return distancesForAllElements;
} }
export async function buildRows({ export async function buildRows({
@ -260,7 +321,10 @@ export async function buildRows({
targetElementPosition: positionDictionary[link.target], targetElementPosition: positionDictionary[link.target],
})); }));
let distances = await findDistancesForAllElements({ nodes, links }); let distances = await findDistancesFromAllElementsToAllReferencePoints({
nodes,
links,
}); //findDistancesForAllElements({ nodes, links });
rows = nodes.map((element, i) => ({ rows = nodes.map((element, i) => ({
id: numToAlphabeticalString(element.position), id: numToAlphabeticalString(element.position),
position: element.position, position: element.position,