From a141e1e1448dd1727da362dfd5954ee9f5b2ca32 Mon Sep 17 00:00:00 2001 From: NunoSempere Date: Mon, 11 Apr 2022 15:37:58 -0400 Subject: [PATCH] feat: no reference point any more, better docs --- README.md | 14 ++++----- lib/findPaths.js | 78 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index d78a3da..a3ac475 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,21 @@ ## 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 -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. - -So internally this would look like: +The core structure is json array of objects. Only the "name" attribute is required. If there is a "url", it is displayed nicely. ``` [ { - "id": 1, "name": "Peter Parker", "someOptionalKey": "...", "anotherMoreOptionalKey": "...", - "isReferenceValue": true }, { - "id": 2, "name": "Spiderman", "someOptionalKey": "...", "anotherMoreOptionalKey": "..." @@ -27,4 +24,5 @@ So internally this would look like: ``` ## Netlify + https://github.com/netlify/netlify-plugin-nextjs/#readme diff --git a/lib/findPaths.js b/lib/findPaths.js index 947397f..7e35468 100644 --- a/lib/findPaths.js +++ b/lib/findPaths.js @@ -150,7 +150,7 @@ async function findPaths({ return paths; } -async function findDistance({ +async function findDistancesForElement({ sourceElementId, sourceElementPosition, targetElementId, @@ -199,6 +199,7 @@ async function findDistance({ } 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 // Needs to find the reference point first console.log("findDistancesForAllElements@findPaths.js"); @@ -210,13 +211,13 @@ async function findDistancesForAllElements({ nodes, links }) { console.log(`referenceElement.position: ${referenceElement.position}`); /* Get distances. */ - let distances = nodes.map((node) => { + let distancesArray = nodes.map((node) => { if (node.isReferenceValue || node.id == referenceElement.id) { return [1]; } else { console.log("node"); console.log(node); - let distance = findDistance({ + let distancesForElement = findDistancesForElement({ sourceElementId: referenceElement.id, sourceElementPosition: referenceElement.position, targetElementId: node.id, @@ -224,11 +225,71 @@ async function findDistancesForAllElements({ nodes, links }) { nodes: nodes, links: links, }); - return distance; + return distancesForElement; } }); - distances = await Promise.all(distances); - return distances; + distancesArray = await Promise.all(distancesArray); + 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({ @@ -260,7 +321,10 @@ export async function buildRows({ targetElementPosition: positionDictionary[link.target], })); - let distances = await findDistancesForAllElements({ nodes, links }); + let distances = await findDistancesFromAllElementsToAllReferencePoints({ + nodes, + links, + }); //findDistancesForAllElements({ nodes, links }); rows = nodes.map((element, i) => ({ id: numToAlphabeticalString(element.position), position: element.position,