feat: Get prototype working.

Display still missing, but some core functionality already
works.
This commit is contained in:
NunoSempere 2022-06-24 21:38:07 -04:00
parent d95d5a18fb
commit 6f91849e4e
118 changed files with 684 additions and 10911 deletions

1
.gitignore vendored
View File

@ -18,6 +18,7 @@ packages/webpage/pages/.old
# dependencies
**/node_modules
node_modules/
/.pnp
.pnp.js

114
README.md
View File

@ -1,8 +1,114 @@
## About
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.
<p align="center">
<img width="50%" height="50%" src="./packages/webpage-refactor/public/example-graph.png">
<img width="50%" height="50%" src="./public/example-prompt.png">
</p>
This repository contains the code for the website [utility-function-extractor.quantifieduncertainty.org/](https://utility-function-extractor.quantifieduncertainty.org/) and tools to analyze utility comparisons. For details, see the relevant folders.
Then, it cleverly aggregates them, on the one hand by producing a graphical representation:
- [Webpage repository](https://github.com/quantified-uncertainty/utility-function-extractor/tree/master/packages/webpage-refactor)
- [Tools repository](https://github.com/quantified-uncertainty/utility-function-extractor/tree/master/packages/utility-tools)
<p align="center">
<img width="50%" height="50%" src="./public/example-graph.png">
</p>
and on the other hand doing some fast and clever mean aggregation [^1]:
<p align="center">
<img width="50%" height="50%" src="./public/example-table.png">
</p>
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](https://www.squiggle-language.com/) 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".
**If you want to use the utility function extractor for a project, we are happy to add a page for your project, like `utility-function-extractor.quantifieduncertainty.org/your-project`**.
## Built with
- [Nextjs](https://nextjs.org/)
- [Netlify](https://github.com/netlify/netlify-plugin-nextjs/#readme)
- [React](https://reactjs.org/)
- [Squiggle](https://www.squiggle-language.com/)
- [Utility tools](https://github.com/quantified-uncertainty/utility-function-extractor/tree/master/packages/utility-tools)
## Usage
Navigate to [utility-function-extractor.quantifieduncertainty.org/](https://utility-function-extractor.quantifieduncertainty.org/), and start comparing objects.
You can change the list of objects to be compared by clicking on "advanced options".
After comparing objects for a while, you will get a table and a graph with results. You can also use the [utility tools](https://github.com/quantified-uncertainty/utility-function-extractor/tree/master/packages/utility-tools) package to process these results, for which you will need the json of comparisons, which can be found in "Advanced options" -> "Load comparisons"
## Notes
The core structure is json array of objects. Only the "name" attribute is required. If there is a "url", it is displayed nicely.
```
[
{
"name": "Peter Parker",
"someOptionalKey": "...",
"anotherMoreOptionalKey": "...",
},
{
"name": "Spiderman",
"someOptionalKey": "...",
"anotherMoreOptionalKey": "..."
}
]
```
The core structure for links is as follows:
```
[
{
"source": "Peter Parker",
"target": "Spiderman",
"squiggleString": "1 to 100",
"distance": 26.639800977355474
},
{
"source": "Spiderman",
"target": "Jonah Jameson",
"squiggleString": "20 to 2000",
"distance": 6.76997149080232
},
]
```
A previous version of this webpage had a more complicated structure, but it has since been simplified.
## Contributions and help
We welcome PR requests.
## License
Distributed under the MIT License. See LICENSE.txt for more information.
## To do
- [x] Extract merge, findPath and aggregatePath functionality into different repos
- [x] Send to mongo upon completion
- [x] Push to github
- [x] Push to netlify
- [x] Don't allow further comparisons after completion
- [x] Paths table
- [x] Add paths table
- [x] warn that the paths table is approximate.
- I really don't feel like re-adding this after having worked out the distribution rather than the mean aggregation
- On the other hand, I think it does make it more user to other users.
- [x] Change README.
- [ ] Add functionality like names, etc.
- I also don't feel like doing this
- [ ] Look back at Amazon thing which has been running
- [ ] Simplify Graph and DynamicSquiggleChart components
- [ ] Add squiggle component to initial comparison?
- [ ] Understand why the rewrite doesn't
- Maybe: When two elements are judged to be roughly equal
- Maybe: Slightly different merge-sort algorithm.
[^1]: The program takes 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. However, this isn't perfect; the principled approach woud be to aggregate the distributions rather than their means. But this principled approach is much more slowly. For the principled approach, see the `utility-tools` repository.

View File

@ -23,28 +23,29 @@ const SquiggleChart = dynamic(
const effectButtonStyle =
"bg-transparent m-2 hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5";
export function DynamicSquiggleChart({ link, stopShowing }) {
if (link == null) {
export function DynamicSquiggleChart({ element, stopShowing }) {
if (element == null) {
return "";
} else {
let usefulLink = {
source: link.source,
target: link.target,
squiggleString: link.squiggleString,
let usefulElement = {
name: element.id,
squiggleString: element.fn,
formula: element.formula
};
return (
<div className="">
<h3 className="text-2xl font-bold mb-5">{usefulElement.name}</h3>
<textarea
value={JSON.stringify(usefulLink, null, 4)}
value={JSON.stringify(usefulElement, null, 4)}
//onChange={handleChange}
disabled={true}
rows={JSON.stringify(usefulLink, null, 4).split("\n").length}
rows={JSON.stringify(usefulElement, null, 4).split("\n").length}
cols={37}
className="text-left text-gray-600 bg-white rounded text-normal p-6 border-0 shadow outline-none focus:outline-none focus:ring mb-4"
/>
<SquiggleChart
squiggleString={link.squiggleString}
width={445}
squiggleString={element.squiggleString}
width={500}
height={200}
showSummary={true}
showTypes={true}

View File

@ -0,0 +1,75 @@
import React from "react";
// import { SquiggleChart } from "@quri/squiggle-components";
import dynamic from "next/dynamic";
const SquiggleChart = dynamic(
() => import("@quri/squiggle-components").then((mod) => mod.SquiggleChart),
{
loading: () => <p>Loading...</p>,
ssr: false,
}
);
/*
const SquiggleChart = dynamic(
() => import("@quri/squiggle-components").then((mod) => mod.SquiggleChart),
{
suspense: true,
ssr: false,
}
);
*/
const effectButtonStyle =
"bg-transparent m-2 hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5";
export function DynamicSquiggleChart({ element, stopShowing }) {
if (element == null) {
return "";
} else {
let usefulElement = {
name: element.id,
squiggleString: element.fn,
formula: element.formula
};
return (
<div className="">
<h3 className="text-2xl font-bold mb-5">{usefulElement.name}</h3>
<textarea
value={JSON.stringify(usefulElement, null, 4)}
//onChange={handleChange}
disabled={true}
rows={JSON.stringify(usefulElement, null, 4).split("\n").length}
cols={37}
className="text-left text-gray-600 bg-white rounded text-normal p-6 border-0 shadow outline-none focus:outline-none focus:ring mb-4"
/>
<SquiggleChart
squiggleString={element.squiggleString}
width={500}
height={200}
showSummary={true}
showTypes={true}
/>
{/*
SquiggleChart props:
squiggleString?: string;
sampleCount?: number;
environment?: environment;
chartSettings?: FunctionChartSettings;
onChange?(expr: squiggleExpression): void;
width?: number;
height?: number;
bindings?: bindings;
jsImports?: jsImports;
showSummary?: boolean;
showTypes?: boolean;
showControls?: boolean;
*/}
<button className={effectButtonStyle} onClick={() => stopShowing()}>
Hide chart
</button>
</div>
);
}
}

View File

@ -0,0 +1,257 @@
import { run, runPartial, mergeBindings } from "@quri/squiggle-lang";
function miniReducer(obj, parentName) {
let nodes = []
let edges = []
let bindings = [];
let inputs = obj.inputs
let fn = obj.fn
for (let childName of Object.keys(inputs)) {
if (typeof inputs[childName] == "string") {
// Produce bindings
let childBindingSquiggleStrings = `${childName} = ${inputs[childName]}`;
let childBinding = runPartial(childBindingSquiggleStrings).value;
bindings.push(childBinding);
// Produce value
let childValueSquiggleString = `${childBindingSquiggleStrings}
${childName}`
let childResultValue = run(childValueSquiggleString)
// Process value for node and edges
if (childResultValue.tag == "Error") {
return childResultValue
} else {
// Node
let childNode = ({
tag: 'Ok',
id: childName,
value: childResultValue.value,
fn: inputs[childName]
})
nodes.push(childNode)
// Edge
let edge = ({
id: `${childName}->${parentName}`, // has to be unique
source: `${childName}`,
target: `${parentName}`,
})
edges.push(edge)
}
} else {
// Produce data
let childNodeOutput = miniReducer(inputs[childName], childName);
if (childNodeOutput.tag == "Error") {
return childNodeOutput
} else {
// Bindings
bindings.push(childNodeOutput.binding)
// Nodes from child node
nodes.push(...childNodeOutput.nodes)
// Edges from child node
edges.push(...childNodeOutput.edges)
/* Child node is included in the childNodeOutput.nodes
let childNode = {
tag: 'Ok',
id: input,
value: childNodeOutput.value,
fn: inputs[childName].fn
};
nodes.push(childNode)
*/
// Child edge
let edge = ({
id: `${childName}->${parentName}`, // has to be unique
source: `${childName}`,
target: `${parentName}`,
})
edges.push(edge)
}
}
}
let parentBindingSquiggleString = `${parentName} = {
${fn}
}`;
let parentResultSquiggleString = `${parentName} = {
${fn}
}
${parentName}`;
let parentBinding = runPartial(
parentBindingSquiggleString,
mergeBindings(bindings)
).value;
if (parentBinding.tag == "Error") {
return parentBinding
}
let parentValue = run(parentResultSquiggleString, mergeBindings(bindings));
if (parentValue.tag == "Error") {
// console.log(bindings)
return parentValue
}
let resultNode = ({
tag: 'Ok',
id: parentName,
value: parentValue.value,
fn: fn
})
nodes.push(resultNode)
// console.log("resultNode", resultNode)
let result = {
...resultNode,
value: parentValue,
binding: parentBinding,
nodes: nodes,
edges: edges
};
return (result);
}
export function createGraph() {
let utility = {
inputs: {
productivity: {
inputs: {
hours: `4 to 12`,
efficiency: `0.1 to 10`,
},
fn: `
hours * efficiency
`,
},
},
fn: `
x = 1 to 10
r = productivity * (1 to 10) * x
mean(r)`,
};
let reducerResult = miniReducer(utility, "utility");
if (reducerResult.tag == "Error") {
return reducerResult
} else {
// console.log("reducerResult", reducerResult)
let {nodes, edges} = reducerResult
let nodeElements = nodes.map(node => ({ data: { ...node, name: node.id} }))
let edgeElements = edges.map(edge => ({ data: { ...edge, name: edge.id } }))
let answer = { nodeElements, edgeElements }
return answer
}
// return { nodeElements: [], edgeElements: [] }
/*
*/
// return (resultUtility)
// Then the rest should be doable without all that much work.
// Some duplication of efforts, but I don't really care:
}
export function createGraph0() {
let nodeElements = [
{
data: {
id: "Total utility",
squiggleString: "1 to 1000",
formula: "now + soon + later"
}
},
{
data: {
id: "now",
squiggleString: "1 to 2",
formula: "subjective estimation"
},
},
{
data: {
id: "soon",
squiggleString: "10 to 200",
formula: "subjective estimation"
},
},
{
data: {
id: "later",
squiggleString: "1 to 500",
formula: "subjective estimation"
},
},
{
data: {
id: "discount rate",
squiggleString: "0.001 to 0.03",
formula: "subjective estimation"
},
},
{
data: {
id: "return rate",
squiggleString: "1 to 2"
}
},
]
let edgeElements = [
{
data: {
id: "link-1",
source: "now",
target: "Total utility",
},
},
{
data: {
id: "link-2",
source: "soon",
target: "Total utility",
},
},
{
data: {
id: "link-3",
source: "later",
target: "Total utility",
},
},
{
data: {
id: "link-4",
source: "discount rate",
target: "later",
},
},
{
data: {
id: "link-5",
source: "return rate",
target: "later",
}
},
]
//
let squiggleInJs = ({
displayName: "Total utility",
varName: "utility",
inputs: {
},
fn: ``
})
//
return { nodeElements, edgeElements }
}

203
components/graph/graph.js Normal file
View File

@ -0,0 +1,203 @@
import React, { useRef, useState, useEffect } from "react";
import cytoscape from "cytoscape";
import dagre from 'cytoscape-dagre';
import { DynamicSquiggleChart } from "../dynamicSquiggleChart.js";
import { createGraph } from "./createGraph"
export function Graph({ }) {
const containerRef = useRef("hello-world");
const [cs, setCs] = useState(null); /// useState("invisible");
const [selectedElement, setSelectedElement] = useState(null);
const [selectedElementTimeout, setSelectedElementTimeout] = useState(null);
//let { nodeElements, edgeElements } = createGraph()
const graphInit = createGraph()
const [nodeElements, setNodeElements] = useState(graphInit.nodeElements)
const [edgeElements, setEdgeElements] = useState(graphInit.edgeElements)
cytoscape.use(dagre);
let callEffect = () => {
const cytoscapeStylesheet = [
{
selector: "node",
style: {
padding: "10px",
shape: "round-rectangle",
content: "data(id)",
"background-color": "darkblue",//"data(color)",
"text-wrap": "wrap",
"text-max-width": 40,
"z-index": 1,
},
},
{
selector: "node[id]",
style: {
label: "data(id)",
"font-size": "9",
color: "white",//"data(labelColor)",
"text-halign": "center",
"text-valign": "center",
"z-index": 1,
},
},
{
selector: "edge",
style: {
"curve-style": "unbundled-bezier",
"target-arrow-shape": "vee",
width: 1.5,
"target-arrow-color": "darkblue",
"arrow-scale": 1.3,
"lineColor": "darkblue",
"target-arrow-fill": "filled",
"text-rotation": "autorotate",
"z-index": 0,
},
},
{
selector: "edge[label]",
style: {
label: "data(label)",
"font-size": "9",
"text-background-color": "#f9f9f9",
"text-background-opacity": 1,
"text-background-padding": "3px",
"text-border-color": "black",
"text-border-style": "solid",
"text-border-width": 0.5,
"text-border-opacity": 1,
"z-index": 3,
},
},
];
let { nodeElements, edgeElements } = createGraph();
setNodeElements(nodeElements)
setEdgeElements(edgeElements)
const config = {
container: containerRef.current,
style: cytoscapeStylesheet,
elements: [...nodeElements, ...edgeElements],
layout: {
name: "dagre", // circle, grid, dagre
minDist: 20,
rankDir: "BT",
//prelayout: false,
// animate: false, // whether to transition the node positions
// animationDuration: 250, // duration of animation in ms if enabled
// the cytoscape documentation is pretty good here.
},
userZoomingEnabled: false,
userPanningEnabled: false,
};
let newCs = cytoscape(config);
setCs(newCs);
// cy.layout({ name: 'dagre', rankDir: "BT"}).run()
// setTimeout(() => setVisibility(""), 700);
// necessary for themes like spread, which have
// a confusing animation at the beginning
};
useEffect(() => {
callEffect({
});
}, [selectedElement]);
useEffect(() => {
if (cs != null) {
setTimeout(() => {
/*
cs.edges().on("click", (event) => {
clearTimeout(selectedElementTimeout);
let edge = event.target;
console.log(JSON.stringify(edge.json()));
let newTimeout = setTimeout(() => {
let
setSelectedElement(JSON.parse(JSON.stringify(edge.json())).data)
});
setSelectedElementTimeout(newTimeout)
});*/
cs.nodes().on("click", (event) => {
clearTimeout(selectedElementTimeout);
let node = event.target;
console.log(JSON.stringify(node.json()));
let newTimeout = setTimeout(() => {
let selectedElementIncomplete = (JSON.parse(JSON.stringify(node.json())).data)
let selectedElementName = selectedElementIncomplete.name
let selectedElementInFull = nodeElements.filter(node => node.data.name == selectedElementName)
console.log("selectedElementInFull", selectedElementInFull)
if(selectedElementInFull.length == 1){
let elementToBeSelected = selectedElementInFull[0]
console.log("elementToBeSelected", elementToBeSelected)
setSelectedElement(elementToBeSelected.data)
}
// setSelectedElement()
});
setSelectedElementTimeout(newTimeout)
});
}, 100)
}
}, [cs]);
/*
useEffect(() => {
if (cs != null) {
clearTimeout(selectedElementTimeout);
let newTimeout = setTimeout(() => {
cs.edges().on("mouseover", (event) => {
// on("click",
let edge = event.target;
// alert(JSON.stringify(edge.json()));
console.log(JSON.stringify(edge.json()));
setSelectedElement(JSON.parse(JSON.stringify(edge.json())).data);
});
cs.nodes().on("mouseover", (event) => {
// on("click",
let node = event.target;
// alert(JSON.stringify(edge.json()));
console.log(JSON.stringify(node.json()));
setSelectedElement(JSON.parse(JSON.stringify(node.json())).data);
});
}, 100);
setSelectedElementTimeout(newTimeout);
}
}, [cs]);
*/
return (
<div className="grid place-items-center">
<div
className={
`grid grid-cols-${selectedElement == null ? "1 " : "2"
}
place-items-center place-self-center space-x-0 w-10/12 `
}
>
<div
ref={containerRef}
style={{
height: "900px", // isListOrdered ? "900px" : "500px",
width: "900px", // isListOrdered ? "900px" : "500px",
}}
className=""
/>
<DynamicSquiggleChart
element={selectedElement}
stopShowing={() => setSelectedElement(null)}
/>
</div>
</div>
);
}

15
components/homepage.js Normal file
View File

@ -0,0 +1,15 @@
import React, { useState } from "react";
import { Title } from "./title.js";
import { Graph } from "./graph/graph.js";
export function Homepage({ listOfElementsInit }) {
return (
<div className="block w-full items-center sm:w-full mt-10">
<Title />
<Graph/>
</div>
);
}

5
components/title.js Normal file
View File

@ -0,0 +1,5 @@
import React, { useState } from "react";
export function Title() {
return <h1 className="text-6xl font-bold ">Hierarchical Estimates Visualizer</h1>;
}

View File

Before

Width:  |  Height:  |  Size: 289 KiB

After

Width:  |  Height:  |  Size: 289 KiB

View File

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 294 KiB

View File

Before

Width:  |  Height:  |  Size: 336 KiB

After

Width:  |  Height:  |  Size: 336 KiB

View File

Before

Width:  |  Height:  |  Size: 282 KiB

After

Width:  |  Height:  |  Size: 282 KiB

View File

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 266 KiB

View File

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 294 KiB

View File

@ -1,6 +1,6 @@
{
"name": "utility-function-extractor",
"version": "0.6.1",
"name": "hierarchical-estimates-visualizer",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "next dev",
@ -23,11 +23,8 @@
"path": "^0.12.7",
"react": "^18.0.1",
"react-code-blocks": "^0.0.9-0",
"react-compound-slider": "^3.3.1",
"react-dom": "^18.0.1",
"react-markdown": "^6.0.2",
"remark-gfm": "^1.0.0",
"simple-react-cytoscape": "^1.0.4",
"utility-tools": "^1.0.4"
},
"devDependencies": {

View File

@ -1,62 +0,0 @@
# Utility Tools
This package contains a series of utilities to work with the utility functions produced by [this utility function extractor](https://utility-function-extractor.quantifieduncertainty.org/openphil-2018-ai-risk).
## Built with
- [Squiggle](https://www.squiggle-language.com/)
- [Nodejs](https://nodejs.org/)
- Plain js
## Getting started
### Installation
```sh
yarn add utility-tools
```
then in your file:
```js
import { mergeSort, findPaths, aggregatePaths } from "utility-tools";
```
### Usage
You can find an example how to use and concatenate these functions in `/src/example.js`, as well as an example of the input format needed in the `input` folder.
## Interface
### Merge sort (`mergeSort`)
Given a list of elements and a list of utilitity comparisons, sort the list. If there are not enough comparisons to implement the merge sort algorithm, return one of the missing comparisons.
_Gotcha_: The list of elements has to be the same list, and in the same order, as that produced when initially doing the comparisons. This is because the merge-sort algorithm depends on the initial order of the list.
### Find Paths (`findPaths`)
Given an (ordered) list of elements and a list of utility comparisons, find all possible monotonous paths from each element to each other. A monotonous path is a path that is either all increasing or all decreasing, relative to the ordering given.
_Note_: Some elements will have many more paths than others.
_Note_: The `findPaths.js` file has a few un-used functions which should make it easier to understand the code.
### Aggregate paths (`aggregatePaths`)
Given a list of path, aggregate them to finally produce an estimate of the relative utility of each element.
There are two ways of doing this:
- 1. Aggregate the means (expected values) for each path.
- This method is fast
- But has the disadvantage the expected value aggregation is tricky, particularly if one of the elements is positive and the other one negative (because then one can't)
- 2. Aggregate the distributions given for each path.
## Roadmap
I don't have any additions planned for this repository.
## Contact
Feel free to shoot me any questions at `nuno.semperelh@protonmail.com`

View File

@ -1,241 +0,0 @@
[
{
"source": "Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer",
"target": "Wilson Center — AI Policy Seminar Series",
"distance": 4.039836724233664,
"reasoning": "Jaime's estimates.\nThe Wilson Center seems to not be running the AI Policy Seminar Series anymore, so I am led to believe it was not a great success (?). There could be someone key influenced that will facilitate things later but seems unlikely\nThe ML Security program does not seem to have resulted on anything substantial",
"squiggleString": "1 to 10"
},
{
"source": "Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer",
"target": "Open Phil AI Fellowship — 2018 Class",
"distance": 657.4661082204123,
"reasoning": "The AI fellows have produced work on interpretability and out of distribution learning.\nSeems to have been better for purchasing influence too, though that's a secondary consideration IMO",
"squiggleString": "400 to 1000"
},
{
"source": "Wilson Center — AI Policy Seminar Series",
"target": "Open Phil AI Fellowship — 2018 Class",
"distance": 403.9836724233662,
"reasoning": "The research seems more directly relevant from the AI fellows, the policy seminar has no legible output",
"squiggleString": "100 to 1000"
},
{
"source": "UC Berkeley — AI Safety Research (2018)",
"target": "Machine Intelligence Research Institute — AI Safety Retraining Program",
"distance": 40.39836724233665,
"reasoning": "Seems to support directly people working on the topic, and more counterfactual",
"squiggleString": "10 to 100"
},
{
"source": "Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer",
"target": "UC Berkeley — AI Safety Research (2018)",
"distance": 7.229755173700019,
"reasoning": "AI Safety Research Affects more people, someone might end up doing something cool",
"squiggleString": "5 to 10"
},
{
"source": "Wilson Center — AI Policy Seminar Series",
"target": "UC Berkeley — AI Safety Research (2018)",
"distance": 2.663515640351876,
"reasoning": "Similar value from the outside",
"squiggleString": "0.1 to 10"
},
{
"source": "UC Berkeley — AI Safety Research (2018)",
"target": "Open Phil AI Fellowship — 2018 Class",
"distance": 247.53475654135346,
"reasoning": "AI fellows produced directly relevant research, are more successful",
"squiggleString": "(1/(0.001 to 0.01))"
},
{
"source": "Machine Intelligence Research Institute — AI Safety Retraining Program",
"target": "Open Phil AI Fellowship — 2018 Class",
"distance": 49.50695130827075,
"reasoning": "aI fellows seem to have produced more relevant research, though grant is less counterfactual",
"squiggleString": "(1/(0.005 to 0.05))"
},
{
"source": "Ought — General Support (2018)",
"target": "Oxford University — Research on the Global Politics of AI",
"distance": 403.9836724233662,
"reasoning": "GovAI is doing cool stuff, Ought not so much",
"squiggleString": "100 to 1000"
},
{
"source": "AI Impacts — General Support (2018)",
"target": "Michael Cohen and Dmitrii Krasheninnikov — Scholarship Support (2018)",
"distance": 2.5202870466776885,
"reasoning": "Direct work seems more important, but Ai impacts work is pretty cool",
"squiggleString": "1 to 5"
},
{
"source": "Ought — General Support (2018)",
"target": "AI Impacts — General Support (2018)",
"distance": 109.28343925564944,
"reasoning": "AI impacts work has been more successful \\ useful for my research",
"squiggleString": "50 to 200"
},
{
"source": "AI Impacts — General Support (2018)",
"target": "Oxford University — Research on the Global Politics of AI",
"distance": 39.678020061969825,
"reasoning": "GovAI is doing more work and on a more neglected topic. Both are doing good work, but GOvAI output is bigger",
"squiggleString": "(1/(0.01 to 0.05))"
},
{
"source": "Oxford University — Research on the Global Politics of AI",
"target": "Michael Cohen and Dmitrii Krasheninnikov — Scholarship Support (2018)",
"distance": 2.865987655844147,
"reasoning": "Cohens work seems harder to replace.\nGovAI is doing more work though",
"squiggleString": "0.01 to 10"
},
{
"source": "Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer",
"target": "Ought — General Support (2018)",
"distance": 14.338510859889407,
"reasoning": "At least Ought is trying ",
"squiggleString": "1 to 50"
},
{
"source": "Wilson Center — AI Policy Seminar Series",
"target": "Ought — General Support (2018)",
"distance": 2.663515640351876,
"reasoning": "Unclear",
"squiggleString": "0.1 to 10"
},
{
"source": "UC Berkeley — AI Safety Research (2018)",
"target": "Ought — General Support (2018)",
"distance": 4.039836724233664,
"reasoning": "At least ought is trying",
"squiggleString": "1 to 10"
},
{
"source": "Machine Intelligence Research Institute — AI Safety Retraining Program",
"target": "Ought — General Support (2018)",
"distance": 1.4338510859889406,
"reasoning": "Value more the potential new hire than oughts research",
"squiggleString": "0.1 to 5"
},
{
"source": "Ought — General Support (2018)",
"target": "Open Phil AI Fellowship — 2018 Class",
"distance": 247.53475654135346,
"reasoning": "Fellows seem to have produced more relevant research",
"squiggleString": "(1/(0.001 to 0.01))"
},
{
"source": "AI Impacts — General Support (2018)",
"target": "Open Phil AI Fellowship — 2018 Class",
"distance": 13.831727022205978,
"reasoning": "Fellows produced more relevant research, AI impacts work is cool though",
"squiggleString": "(1/(0.05 to 0.1))"
},
{
"source": "Open Phil AI Fellowship — 2018 Class",
"target": "Oxford University — Research on the Global Politics of AI",
"distance": 32.87330541102063,
"reasoning": "GovAI's grant seems moe counterfactual, their work more directly relevant\n",
"squiggleString": "20 to 50"
}
]

View File

@ -1,47 +0,0 @@
[
{
"name": "Michael Cohen and Dmitrii Krasheninnikov — Scholarship Support (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.jnlrsr63yliq",
"amount": "$159k"
},
{
"name": "AI Impacts — General Support (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.6m6tebpouzt1",
"amount": "$100k"
},
{
"name": "Oxford University — Research on the Global Politics of AI",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.c6r2m7i749ay",
"amount": "$429k"
},
{
"name": "Ought — General Support (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.xnzaj48k3fdb",
"amount": "$525k"
},
{
"name": "Machine Intelligence Research Institute — AI Safety Retraining Program",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.h922w7eh5rq6",
"amount": "$150k"
},
{
"name": "UC Berkeley — AI Safety Research (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.rrsbecbboed8",
"amount": "$1.145M"
},
{
"name": "Open Phil AI Fellowship — 2018 Class",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.p8xd58asz6a2",
"amount": "$1.135M"
},
{
"name": "Wilson Center — AI Policy Seminar Series",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.qiurhycylgi3",
"amount": "$400k"
},
{
"name": "Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.ox8adhpgba86",
"amount": "$100k"
}
]

View File

@ -1,95 +0,0 @@
Sorted output:
[
'Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer',
'Wilson Center — AI Policy Seminar Series',
'UC Berkeley — AI Safety Research (2018)',
'Machine Intelligence Research Institute — AI Safety Retraining Program',
'Ought — General Support (2018)',
'AI Impacts — General Support (2018)',
'Open Phil AI Fellowship — 2018 Class',
'Oxford University — Research on the Global Politics of AI',
'Michael Cohen and Dmitrii Krasheninnikov — Scholarship Support (2018)'
]
Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer
Number of paths: 102
Mean: 0.04340463625937361
90% confidence interval: [
3.102187977841675e-7,
0.10636313508232977
]
3.902 seconds needed for processing
Wilson Center — AI Policy Seminar Series
Number of paths: 52
Mean: 0.23923636834715892
90% confidence interval: [
0.0000012797707857581555,
0.7647175734237982
]
0.855 seconds needed for processing
UC Berkeley — AI Safety Research (2018)
Number of paths: 37
Mean: 0.6148765126821536
90% confidence interval: [
0.0000012857319777641759,
2.4285898907477064
]
0.484 seconds needed for processing
Machine Intelligence Research Institute — AI Safety Retraining Program
Number of paths: 21
Mean: 46.33576477417035
90% confidence interval: [
0.000022241280559831212,
201.37264605399085
]
0.173 seconds needed for processing
Ought — General Support (2018)
Number of paths: 36
Mean: 63.37826067838051
90% confidence interval: [
0.00004411196776834627,
145.5050535108514
]
0.412 seconds needed for processing
AI Impacts — General Support (2018)
Number of paths: 47
Mean: 9862.157135402398
90% confidence interval: [
0.018650934888088284,
22307.090052203544
]
0.635 seconds needed for processing
Open Phil AI Fellowship — 2018 Class
Number of paths: 372
Mean: 86301.01328794319
90% confidence interval: [
26.02179139839112,
115734.18190287006
]
35.203 seconds needed for processing
Oxford University — Research on the Global Politics of AI
Number of paths: 2261
Mean: 785779.6653748289
90% confidence interval: [
114.32195138741375,
960250.7929788446
]
1048.955 seconds needed for processing
Michael Cohen and Dmitrii Krasheninnikov — Scholarship Support (2018)
Number of paths: 5243
Mean: 1482642.2273006735
90% confidence interval: [
8.379381400123396,
330071.1150485886
]
5550.563 seconds needed for processing

View File

@ -1,16 +0,0 @@
{
"name": "utility-tools",
"version": "1.0.5",
"description": "Process the json produced by utility-function-extractor.quantifieduncertainty.org",
"scripts": {
"start": "node --max-old-space-size=8192 src/index.js",
"example": "node --max-old-space-size=8192 src/example.js"
},
"type": "module",
"main": "src/index.js",
"author": "Nuño Sempere",
"license": "MIT",
"dependencies": {
"@quri/squiggle-lang": "^0.2.11"
}
}

View File

@ -1,163 +0,0 @@
// EXPORTS
import { run } from "@quri/squiggle-lang";
export async function aggregatePathsThroughMixtureOfDistributions({
pathsArray,
orderedList,
VERBOSE,
}) {
let print = (x) => {
if (VERBOSE) {
console.log(x);
}
};
let result = pathsArray.map((paths, i) => {
print(orderedList[i].name);
let multipliedDistributions = paths.map(
(path) => path.multipliedDistributionsInPath
);
console.group();
print("Number of paths: ", multipliedDistributions.length);
let squiggleCode = `aggregatePath = mx(${multipliedDistributions
.filter((distributions) => distributions != undefined)
.join(", ")})`;
// Start measuring time
let start = Date.now();
// Get the mean
let squiggleCodeForMean = squiggleCode + "\n" + "mean(aggregatePath)";
let meanAnswer = run(squiggleCodeForMean);
let mean = meanAnswer.value.value;
print(`Mean: ${mean}`);
// Get the 90% CI
let squiggleCodeFor90CI =
squiggleCode +
"\n" +
"[inv(aggregatePath, 0.05), inv(aggregatePath, 0.95)]";
let ci90percentAnswer = run(squiggleCodeFor90CI);
// Display output
let processCI90 = (answer) => {
let value = answer.value.value;
let lower = value[0].value;
let upper = value[1].value;
return [lower, upper];
};
print(
`90% confidence interval: ${JSON.stringify(
processCI90(ci90percentAnswer),
null,
4
)}`
);
// Stop measuring time
let end = Date.now();
print(`${(end - start) / 1000} seconds needed for processing`);
console.groupEnd();
print("");
return {
name: orderedList[i].name,
meanOfAggregatedDistributions: mean,
ninetyPercentileConfidenceIntervalOfAggregatedDistributions:
ci90percentAnswer,
arrayDistributions: squiggleCode,
};
});
return result;
}
const sum = (arr) => arr.reduce((a, b) => a + b, 0);
export const avg = (arr) => sum(arr) / arr.length;
export const geomMean = (arr) => {
let n = arr.length;
let logavg = sum(arr.map((x) => Math.log(x))); // works for low numbers much better
let result = Math.exp(logavg / n);
return result;
};
export function aggregatePathsThroughMixtureOfMeans({
pathsArray,
orderedList,
VERBOSE,
DONT_EXCLUDE_INFINITIES_AND_NANS,
}) {
let print = (x) => {
if (VERBOSE) {
console.log(x);
}
};
let result = pathsArray.map((paths, i) => {
print(orderedList[i].name);
let expectedRelativeValues = paths.map(
(path) => path.expectedRelativeValue
);
let expectedRelativeValuesFiltered = expectedRelativeValues;
if (!DONT_EXCLUDE_INFINITIES_AND_NANS) {
expectedRelativeValuesFiltered = expectedRelativeValues
.filter((x) => x != undefined)
.filter((x) => !isNaN(x))
.filter((x) => isFinite(x))
.filter((x) => x != null);
}
let hasPositive = expectedRelativeValuesFiltered.filter((x) => x > 0);
let hasNegative = expectedRelativeValuesFiltered.filter((x) => x < 0);
let answer;
if (hasPositive.length != 0 && hasNegative.length != 0) {
answer = avg(expectedRelativeValuesFiltered);
} else {
if (hasNegative.length == 0) {
answer = geomMean(expectedRelativeValuesFiltered);
} else {
let arrayAsPositive = expectedRelativeValuesFiltered.map((x) => -x);
answer = -geomMean(arrayAsPositive);
}
}
return {
name: orderedList[i].name,
aggregatedMeans: answer,
arrayMeans: expectedRelativeValuesFiltered,
allPositive: hasNegative.length == 0,
};
});
return result;
}
export async function aggregatePaths({
pathsArray,
orderedList,
aggregationType,
VERBOSE,
}) {
if (aggregationType == "distribution") {
if (VERBOSE == undefined) {
VERBOSE = true;
}
console.log("Warning: this may take a long time");
return await aggregatePathsThroughMixtureOfDistributions({
pathsArray,
orderedList,
VERBOSE,
});
} else if (aggregationType == "mean") {
return aggregatePathsThroughMixtureOfMeans({
pathsArray,
orderedList,
VERBOSE,
});
} else {
return aggregatePathsThroughMixtureOfMeans({
pathsArray,
orderedList,
VERBOSE,
});
}
}

View File

@ -1,56 +0,0 @@
// IMPORTS
import * as fs from "fs";
import { mergeSort } from "./mergeSort.js";
import { findDistances } from "./findPaths.js";
import { aggregatePaths } from "./aggregatePaths.js";
// DEFS
const inputLinksFilePath = "./input/input-links-daniel.json";
const inputListFilePath = "./input/input-list.json";
const outputFilePath = "./output/output.json";
// HELPERS
// MAIN
async function main() {
// Read file
const inputLinksAsString = fs.readFileSync(inputLinksFilePath);
const inputListAsString = fs.readFileSync(inputListFilePath);
const links = JSON.parse(inputLinksAsString);
const list = JSON.parse(inputListAsString);
// Merge sort
let mergeSortOutput = mergeSort({
list,
links,
tryHardWithPermutations: true,
});
if (mergeSortOutput.finishedOrderingList == false) {
console.log("Merge could not proceed");
console.group();
console.log("Elements which need to be compared:");
console.log(mergeSortOutput.uncomparedElements);
console.groupEnd();
} else {
let orderedList = mergeSortOutput.orderedList;
console.log("Sorted output: ");
console.group();
console.log(orderedList.map((x) => x.name));
console.groupEnd();
console.log("");
// find Paths
let paths = await findDistances({ orderedList, links });
// Aggregate paths.
let aggregatedPaths = await aggregatePaths({
pathsArray: paths,
orderedList,
aggregationType: "distribution", // alternatively: aggregationType: "distribution" | "mean"
VERBOSE: true, // optional arg
DONT_EXCLUDE_INFINITIES_AND_NANS: false, // optional arg
});
console.log(aggregatedPaths);
}
}
main();

View File

@ -1,283 +0,0 @@
/* Functions */
const pathPlusLink = (pathSoFar, link) => {
return [...pathSoFar, link];
// previously: pathSoFar.concat(link).flat()
// Note that concat is not destructive
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat
};
const findElementPosition = (name, nodes) => {
let node = nodes.find((node) => node.name == name);
return node.position;
};
async function findPathsWithoutPrunning({
// DO NOT DELETE THIS UN-USED FUNCTION
// USEFUL FOR UNDERSTANDING AGAIN HOW THIS CODE WORKS AFTER A FEW MONTHS
sourceElementName,
targetElementName,
maxLengthOfPath,
pathSoFar,
links,
nodes,
}) {
// This is an un-used function which might make findPaths more understandable
// It uses the same recursive functionality
// but has no path prunning
let paths = [];
/* Path traversing */
if (maxLengthOfPath > 0) {
for (let link of links) {
// vs let link of linksNow in findPaths
if (
(link.source == sourceElementName &&
link.target == targetElementName) ||
(link.source == targetElementName && link.target == sourceElementName)
) {
// direct Path
let newPath = pathPlusLink(pathSoFar, link);
paths.push(newPath);
} else if (link.source == sourceElementName) {
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementName: link.target,
targetElementName,
links: links, // vs let link of linksInner in findPaths
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
} else if (link.target == sourceElementName) {
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementName: link.source,
targetElementName,
links: links, // vs let link of linksInner in findPaths
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
}
}
}
return paths;
}
async function findPaths({
sourceElementName,
sourceElementPosition,
targetElementName,
targetElementPosition,
maxLengthOfPath,
pathSoFar,
links,
nodes,
}) {
// This is the key path finding function
// It finds the path from one element to another, recursively
// It used to be very computationally expensive until I added
// the path prunning step: Instead of traversing all links,
// traverse only those which are between the origin and target links
// this requires us to have a notion of "between"
let paths = [];
/* Path prunning*/
let minPos = Math.min(sourceElementPosition, targetElementPosition);
let maxPos = Math.max(sourceElementPosition, targetElementPosition);
let linksInner = links.filter(
(link) =>
minPos <= link.sourceElementPosition &&
link.sourceElementPosition <= maxPos &&
minPos <= link.targetElementPosition &&
link.targetElementPosition <= maxPos
);
let linksNow = linksInner.filter(
(link) =>
link.source == sourceElementName || link.target == sourceElementName
);
/* Path traversing */
if (maxLengthOfPath > 0) {
for (let link of linksNow) {
if (
(link.source == sourceElementName &&
link.target == targetElementName) ||
(link.source == targetElementName && link.target == sourceElementName)
) {
// We have found a direct path.
let newPath = pathPlusLink(pathSoFar, link);
paths.push(newPath);
} else if (link.source == sourceElementName) {
// Recursively call find Paths
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementPosition: link.sourceElementPosition,
sourceElementName: link.target,
targetElementName,
targetElementPosition,
links: linksInner,
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
} else if (link.target == sourceElementName) {
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementPosition: link.sourceElementPosition,
sourceElementName: link.source,
targetElementPosition,
targetElementName,
links: linksInner,
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
}
}
}
return paths;
}
async function findExpectedValuesAndDistributionsForElement({
sourceElementName,
sourceElementPosition,
targetElementName,
targetElementPosition,
nodes,
links,
}) {
// This function gets all possible paths using findPaths
// then orders them correctly in the for loop
// (by flipping the distance to 1/distance when necessary)
// and then gets the array of weights for the different paths.
let maxLengthOfPath = Math.abs(sourceElementPosition - targetElementPosition);
let paths = await findPaths({
sourceElementName,
sourceElementPosition,
targetElementName,
targetElementPosition,
links,
nodes,
maxLengthOfPath,
pathSoFar: [],
});
let processedPaths = [];
for (let path of paths) {
let currentSource = sourceElementName;
let expectedRelativeValue = 1;
let multipliedDistributionsInPath = 1;
let distances = [];
for (let element of path) {
let distance = 0;
let anotherDistributionInPath = 1;
if (element.source == currentSource) {
distance = element.distance;
anotherDistributionInPath = element.squiggleString;
currentSource = element.target;
} else if (element.target == currentSource) {
distance = 1 / Number(element.distance);
anotherDistributionInPath = `1 / (${element.squiggleString})`;
currentSource = element.source;
}
expectedRelativeValue = expectedRelativeValue * distance;
distances.push(distance);
multipliedDistributionsInPath = `${multipliedDistributionsInPath} * (${anotherDistributionInPath})`;
}
processedPaths.push({
distances,
expectedRelativeValue,
multipliedDistributionsInPath,
// path,
});
}
return processedPaths;
}
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];
/* Get distances. */
let distancesArray = nodes.map((node) => {
if (node.name == referenceElement.name) {
return [1];
} else {
let expectedValuesAndDistributionsForElement =
findExpectedValuesAndDistributionsForElement({
sourceElementName: referenceElement.name,
sourceElementPosition: referenceElement.position,
targetElementName: node.name,
targetElementPosition: node.position,
nodes: nodes,
links: links,
});
return expectedValuesAndDistributionsForElement;
}
});
distancesArray = await Promise.all(distancesArray);
return distancesArray;
}
export 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: nodes2,
links,
referenceElement: node,
});
distancesForAllElements = distancesForAllElements.map((arr, i) => {
return !!arr && arr.length > 0
? [...arr, ...distancesFromNode[i]]
: distancesFromNode[i];
});
}
return distancesForAllElements;
}
export async function findDistances({ orderedList, links }) {
let nodes = orderedList.map((element, i) => ({
...element,
position: i,
}));
const linksWithPosition = links.map((link) => ({
...link,
sourceElementPosition: findElementPosition(link.source, nodes),
targetElementPosition: findElementPosition(link.target, nodes),
}));
let result = await findDistancesFromAllElementsToAllReferencePoints({
nodes,
links: linksWithPosition,
});
return result;
}

View File

@ -1,5 +0,0 @@
import { mergeSort } from "./mergeSort.js";
import { findDistances } from "./findPaths.js";
import { aggregatePaths } from "./aggregatePaths.js";
export { mergeSort, aggregatePaths, findDistances };

View File

@ -1,208 +0,0 @@
const errorMsg = "No link found; unable to proceed";
function isFirstElementGreater(links, element1, element2) {
const relevantComparisons = links.filter(
(link) =>
(link.source == element1.name && link.target == element2.name) ||
(link.source == element2.name && link.target == element1.name)
);
if (relevantComparisons.length == 0) {
let answer = {
foundAnswer: false,
error: errorMsg,
};
return answer;
} else {
const firstLink = relevantComparisons[0];
const firstElementFirst =
firstLink.source == element1.name && firstLink.target == element2.name
? true
: false;
const distanceIsGreaterThanOne = Number(firstLink.distance) > 1;
const isFirstElementFirst =
(firstElementFirst && !distanceIsGreaterThanOne) ||
(!firstElementFirst && distanceIsGreaterThanOne);
let answer = {
foundAnswer: true,
isFirstElementFirst,
errorMsg,
};
return answer;
}
}
function merge(links, left, right) {
let sortedArr = [];
while (left.length && right.length) {
// insert the biggest element to the sortedArr
let getComparisonAnswer = isFirstElementGreater(links, left[0], right[0]);
if (getComparisonAnswer.foundAnswer == false) {
let result = {
finishedMerge: false,
uncomparedElements: [left[0], right[0]],
errorMsg: errorMsg,
};
return result;
} else if (getComparisonAnswer.foundAnswer == true) {
if (getComparisonAnswer.isFirstElementFirst == true) {
// left[0] > right[0]
// note that we can order from smallest to largest or the reverse
// ; I forget which one this is.
sortedArr.push(right.shift());
} else {
sortedArr.push(left.shift());
}
}
}
// use spread operator and create a new array, combining the three arrays
let result = {
finishedMerge: true,
orderedList: [...sortedArr, ...left, ...right],
// if they don't have the same size, the remaining ones will be greater than the ones before
};
return result;
}
export function mergeSortInner({ recursiveInput, links }) {
if (recursiveInput.bottleneckedByComparison == true) {
let result = {
recursiveInput: {
list: recursiveInput.list,
bottleneckedByComparison: true,
uncomparedElements: recursiveInput.uncomparedElements,
},
links: links,
};
return result;
}
const half = recursiveInput.list.length / 2;
// the base case is list length <=1
if (recursiveInput.list.length <= 1) {
let result = {
recursiveInput: {
bottleneckedByComparison: false,
list: recursiveInput.list,
},
links: links,
};
return result;
}
const left = recursiveInput.list.slice(0, half); // the first half of the list
const right = recursiveInput.list.slice(half, recursiveInput.list.length); // Note that splice is destructive, and that slice instead creates a new array.
let orderedFirstHalfAnswer = mergeSortInner({
recursiveInput: { list: left, bottleneckedByComparison: false },
links,
});
let orderedSecondHalfAnswer = mergeSortInner({
recursiveInput: { list: right, bottleneckedByComparison: false },
links,
});
if (
orderedFirstHalfAnswer.recursiveInput.bottleneckedByComparison == false &&
orderedSecondHalfAnswer.recursiveInput.bottleneckedByComparison == false
) {
let mergeStepAnswer = merge(
links,
orderedFirstHalfAnswer.recursiveInput.list,
orderedSecondHalfAnswer.recursiveInput.list
);
if (mergeStepAnswer.finishedMerge == true) {
let result = {
recursiveInput: {
list: mergeStepAnswer.orderedList,
bottleneckedByComparison: false,
},
links,
};
return result;
} else {
let result = {
recursiveInput: {
list: recursiveInput.list,
bottleneckedByComparison: true,
uncomparedElements: mergeStepAnswer.uncomparedElements,
},
links,
};
return result;
}
} else if (
orderedFirstHalfAnswer.recursiveInput.bottleneckedByComparison == true
) {
return orderedFirstHalfAnswer;
} else {
return orderedSecondHalfAnswer;
}
}
export function mergeSort({ list, links, tryHardWithPermutations }) {
// Try normally
let answer = mergeSortInner({
recursiveInput: { list, bottleneckedByComparison: false },
links,
});
if (answer.recursiveInput.bottleneckedByComparison == false) {
let result = {
finishedOrderingList: true,
orderedList: answer.recursiveInput.list,
};
return result;
} else if (tryHardWithPermutations != true) {
let result = {
finishedOrderingList: false,
uncomparedElements: answer.recursiveInput.uncomparedElements,
};
return result;
} else {
// otherwise, test all other permutations:
let permutation = list.slice();
var length = list.length;
// let result = [list.slice()];
let c = new Array(length).fill(0);
let i = 1;
let k;
let p;
let counter = 0;
let errorMsg =
"Error: The original list was wrongly ordered, and trying permutations didn't work";
while (i < length) {
counter++;
if (counter > 10) console.log("permutation #" + counter);
if (c[i] < i) {
k = i % 2 && c[i];
p = permutation[i];
permutation[i] = permutation[k];
permutation[k] = p;
// ++c[i];
c[i] = c[i] + 1;
i = 1;
let answer = mergeSortInner({
recursiveInput: {
list: permutation,
bottleneckedByComparison: false,
},
links,
});
if (answer.recursiveInput.bottleneckedByComparison == false) {
console.log(answer.recursiveInput);
let result = {
finishedOrderingList: true,
orderedList: answer.recursiveInput.list,
};
return result;
}
// result.push(permutation.slice());
} else {
c[i] = 0;
i = i + 1;
// ++i;
}
}
console.log(errorMsg);
return errorMsg;
}
}

View File

@ -1,505 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/runtime@^7.18.3":
version "7.18.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4"
integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==
dependencies:
regenerator-runtime "^0.13.4"
"@quri/squiggle-lang@^0.2.11":
version "0.2.11"
resolved "https://registry.yarnpkg.com/@quri/squiggle-lang/-/squiggle-lang-0.2.11.tgz#fc9df37c1c5537b4da099c71c8249373210cfadf"
integrity sha512-n879EbSS0eWWEl+s38XmB4xDy18wOJSk3t7moCxIGDhUc70aH1kgNhg56M+M57a8f55MbIhhr7kAVb9RbqqhuA==
dependencies:
"@stdlib/stats" "^0.0.13"
jstat "^1.9.5"
lodash "^4.17.21"
mathjs "^10.6.0"
pdfast "^0.2.0"
rescript "^9.1.4"
"@stdlib/array@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/array/-/array-0.0.12.tgz#12f40ab95bb36d424cdad991f29fc3cb491ee29e"
integrity sha512-nDksiuvRC1dSTHrf5yOGQmlRwAzSKV8MdFQwFSvLbZGGhi5Y4hExqea5HloLgNVouVs8lnAFi2oubSM4Mc7YAg==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/blas" "^0.0.x"
"@stdlib/complex" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/symbol" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/assert@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/assert/-/assert-0.0.12.tgz#1648c9016e5041291f55a6464abcc4069c5103ce"
integrity sha512-38FxFf+ZoQZbdc+m09UsWtaCmzd/2e7im0JOaaFYE7icmRfm+4KiE9BRvBT4tIn7ioLB2f9PsBicKjIsf+tY1w==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/complex" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/ndarray" "^0.0.x"
"@stdlib/number" "^0.0.x"
"@stdlib/os" "^0.0.x"
"@stdlib/process" "^0.0.x"
"@stdlib/regexp" "^0.0.x"
"@stdlib/streams" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/symbol" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/bigint@^0.0.x":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@stdlib/bigint/-/bigint-0.0.11.tgz#c416a1d727001c55f4897e6424124199d638f2fd"
integrity sha512-uz0aYDLABAYyqxaCSHYbUt0yPkXYUCR7TrVvHN+UUD3i8FZ02ZKcLO+faKisDyxKEoSFTNtn3Ro8Ir5ebOlVXQ==
dependencies:
"@stdlib/utils" "^0.0.x"
"@stdlib/blas@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/blas/-/blas-0.0.12.tgz#7e93e42b4621fc6903bf63264f045047333536c2"
integrity sha512-nWY749bWceuoWQ7gz977blCwR7lyQ/rsIXVO4b600h+NFpeA2i/ea7MYC680utIbeu2cnDWHdglBPoK535VAzA==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/number" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/buffer@^0.0.x":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@stdlib/buffer/-/buffer-0.0.11.tgz#6137b00845e6c905181cc7ebfae9f7e47c01b0ce"
integrity sha512-Jeie5eDDa1tVuRcuU+cBXI/oOXSmMxUUccZpqXzgYe0IO8QSNtNxv9mUTzJk/m5wH+lmLoDvNxzPpOH9TODjJg==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/process" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/cli@^0.0.x":
version "0.0.10"
resolved "https://registry.yarnpkg.com/@stdlib/cli/-/cli-0.0.10.tgz#28e2fbe6865d7f5cd15b7dc5846c99bd3b91674f"
integrity sha512-OITGaxG46kwK799+NuOd/+ccosJ9koVuQBC610DDJv0ZJf8mD7sbjGXrmue9C4EOh8MP7Vm/6HN14BojX8oTCg==
dependencies:
"@stdlib/utils" "^0.0.x"
minimist "^1.2.0"
"@stdlib/complex@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/complex/-/complex-0.0.12.tgz#3afbc190cd0a9b37fc7c6e508c3aa9fda9106944"
integrity sha512-UbZBdaUxT2G+lsTIrVlRZwx2IRY6GXnVILggeejsIVxHSuK+oTyapfetcAv0FJFLP+Rrr+ZzrN4b9G3hBw6NHA==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/constants@^0.0.x":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@stdlib/constants/-/constants-0.0.11.tgz#78cd56d6c2982b30264843c3d75bde7125e90cd2"
integrity sha512-cWKy0L9hXHUQTvFzdPkTvZnn/5Pjv7H4UwY0WC1rLt+A5CxFDJKjvnIi9ypSzJS3CAiGl1ZaHCdadoqXhNdkUg==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/number" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/fs@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/fs/-/fs-0.0.12.tgz#662365fd5846a51f075724b4f2888ae88441b70d"
integrity sha512-zcDLbt39EEM3M3wJW6luChS53B8T+TMJkjs2526UpKJ71O0/0adR57cI7PfCpkMd33d05uM7GM+leEj4eks4Cw==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/process" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/utils" "^0.0.x"
debug "^2.6.9"
"@stdlib/math@^0.0.x":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@stdlib/math/-/math-0.0.11.tgz#eb6638bc03a20fbd6727dd5b977ee0170bda4649"
integrity sha512-qI78sR1QqGjHj8k/aAqkZ51Su2fyBvaR/jMKQqcB/ML8bpYpf+QGlGvTty5Qdru/wpqds4kVFOVbWGcNFIV2+Q==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/ndarray" "^0.0.x"
"@stdlib/number" "^0.0.x"
"@stdlib/strided" "^0.0.x"
"@stdlib/symbol" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
debug "^2.6.9"
"@stdlib/ndarray@^0.0.x":
version "0.0.13"
resolved "https://registry.yarnpkg.com/@stdlib/ndarray/-/ndarray-0.0.13.tgz#2e8fc645e10f56a645a0ab81598808c0e8f43b82"
integrity sha512-Z+U9KJP4U2HWrLtuAXSPvhNetAdqaNLMcliR6S/fz+VPlFDeymRK7omRFMgVQ+1zcAvIgKZGJxpLC3vjiPUYEw==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/bigint" "^0.0.x"
"@stdlib/buffer" "^0.0.x"
"@stdlib/complex" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/number" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/nlp@^0.0.x":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@stdlib/nlp/-/nlp-0.0.11.tgz#532ec0f7267b8d639e4c20c6de864e8de8a09054"
integrity sha512-D9avYWANm0Db2W7RpzdSdi5GxRYALGAqUrNnRnnKIO6sMEfr/DvONoAbWruda4QyvSC+0MJNwcEn7+PHhRwYhw==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/random" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/number@^0.0.x":
version "0.0.10"
resolved "https://registry.yarnpkg.com/@stdlib/number/-/number-0.0.10.tgz#4030ad8fc3fac19a9afb415c443cee6deea0e65c"
integrity sha512-RyfoP9MlnX4kccvg8qv7vYQPbLdzfS1Mnp/prGOoWhvMG3pyBwFAan34kwFb5IS/zHC3W5EmrgXCV2QWyLg/Kg==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/os" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/os@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/os/-/os-0.0.12.tgz#08bbf013c62a7153099fa9cbac086ca1349a4677"
integrity sha512-O7lklZ/9XEzoCmYvzjPh7jrFWkbpOSHGI71ve3dkSvBy5tyiSL3TtivfKsIC+9ZxuEJZ3d3lIjc9e+yz4HVbqQ==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/process" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/process@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/process/-/process-0.0.12.tgz#123325079d89a32f4212f72fb694f8fe3614cf18"
integrity sha512-P0X0TMvkissBE1Wr877Avi2/AxmP7X5Toa6GatHbpJdDg6jQmN4SgPd+NZNp98YtZUyk478c8XSIzMr1krQ20g==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/buffer" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/streams" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/random@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/random/-/random-0.0.12.tgz#e819c3abd602ed5559ba800dba751e49c633ff85"
integrity sha512-c5yND4Ahnm9Jx0I+jsKhn4Yrz10D53ALSrIe3PG1qIz3kNFcIPnmvCuNGd+3V4ch4Mbrez55Y8z/ZC5RJh4vJQ==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/blas" "^0.0.x"
"@stdlib/buffer" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/process" "^0.0.x"
"@stdlib/stats" "^0.0.x"
"@stdlib/streams" "^0.0.x"
"@stdlib/symbol" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
debug "^2.6.9"
readable-stream "^2.1.4"
"@stdlib/regexp@^0.0.x":
version "0.0.13"
resolved "https://registry.yarnpkg.com/@stdlib/regexp/-/regexp-0.0.13.tgz#80b98361dc7a441b47bc3fa964bb0c826759e971"
integrity sha512-3JT5ZIoq/1nXY+dY+QtkU8/m7oWDeekyItEEXMx9c/AOf0ph8fmvTUGMDNfUq0RetcznFe3b66kFz6Zt4XHviA==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/stats@^0.0.13", "@stdlib/stats@^0.0.x":
version "0.0.13"
resolved "https://registry.yarnpkg.com/@stdlib/stats/-/stats-0.0.13.tgz#87c973f385379d794707c7b5196a173dba8b07e1"
integrity sha512-hm+t32dKbx/L7+7WlQ1o4NDEzV0J4QSnwFBCsIMIAO8+VPxTZ4FxyNERl4oKlS3hZZe4AVKjoOVhBDtgEWrS4g==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/blas" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/ndarray" "^0.0.x"
"@stdlib/random" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/symbol" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/streams@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/streams/-/streams-0.0.12.tgz#07f5ceae5852590afad8e1cb7ce94174becc8739"
integrity sha512-YLUlXwjJNknHp92IkJUdvn5jEQjDckpawKhDLLCoxyh3h5V+w/8+61SH7TMTfKx5lBxKJ8vvtchZh90mIJOAjQ==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/buffer" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
debug "^2.6.9"
readable-stream "^2.1.4"
"@stdlib/strided@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/strided/-/strided-0.0.12.tgz#86ac48e660cb7f64a45cf07e80cbbfe58be21ae1"
integrity sha512-1NINP+Y7IJht34iri/bYLY7TVxrip51f6Z3qWxGHUCH33kvk5H5QqV+RsmFEGbbyoGtdeHrT2O+xA+7R2e3SNg==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/ndarray" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/string@^0.0.x":
version "0.0.13"
resolved "https://registry.yarnpkg.com/@stdlib/string/-/string-0.0.13.tgz#37457ca49e8d1dff0e523c68f5673c655c79eb2d"
integrity sha512-nGMHi7Qk9LBW0+Y+e3pSePQEBqyWH7+7DjFR1APcbsYccJE0p4aCaQdhPhx9Tp7j3uRGBmqPFek8wpcvIuC+CQ==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/nlp" "^0.0.x"
"@stdlib/process" "^0.0.x"
"@stdlib/regexp" "^0.0.x"
"@stdlib/streams" "^0.0.x"
"@stdlib/types" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/symbol@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/symbol/-/symbol-0.0.12.tgz#b9f396b0bf269c2985bb7fe99810a8e26d7288c3"
integrity sha512-2IDhpzWVGeLHgsvIsX12RXvf78r7xBkc4QLoRUv3k7Cp61BisR1Ym1p0Tq9PbxT8fknlvLToh9n5RpmESi2d4w==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/time@^0.0.x":
version "0.0.14"
resolved "https://registry.yarnpkg.com/@stdlib/time/-/time-0.0.14.tgz#ea6daa438b1d3b019b99f5091117ee4bcef55d60"
integrity sha512-1gMFCQTabMVIgww+k4g8HHHIhyy1tIlvwT8mC0BHW7Q7TzDAgobwL0bvor+lwvCb5LlDAvNQEpaRgVT99QWGeQ==
dependencies:
"@stdlib/assert" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/utils" "^0.0.x"
"@stdlib/types@^0.0.x":
version "0.0.14"
resolved "https://registry.yarnpkg.com/@stdlib/types/-/types-0.0.14.tgz#02d3aab7a9bfaeb86e34ab749772ea22f7b2f7e0"
integrity sha512-AP3EI9/il/xkwUazcoY+SbjtxHRrheXgSbWZdEGD+rWpEgj6n2i63hp6hTOpAB5NipE0tJwinQlDGOuQ1lCaCw==
"@stdlib/utils@^0.0.x":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@stdlib/utils/-/utils-0.0.12.tgz#670de5a7b253f04f11a4cba38f790e82393bcb46"
integrity sha512-+JhFpl6l7RSq/xGnbWRQ5dAL90h9ONj8MViqlb7teBZFtePZLMwoRA1wssypFcJ8SFMRWQn7lPmpYVUkGwRSOg==
dependencies:
"@stdlib/array" "^0.0.x"
"@stdlib/assert" "^0.0.x"
"@stdlib/blas" "^0.0.x"
"@stdlib/buffer" "^0.0.x"
"@stdlib/cli" "^0.0.x"
"@stdlib/constants" "^0.0.x"
"@stdlib/fs" "^0.0.x"
"@stdlib/math" "^0.0.x"
"@stdlib/os" "^0.0.x"
"@stdlib/process" "^0.0.x"
"@stdlib/random" "^0.0.x"
"@stdlib/regexp" "^0.0.x"
"@stdlib/streams" "^0.0.x"
"@stdlib/string" "^0.0.x"
"@stdlib/symbol" "^0.0.x"
"@stdlib/time" "^0.0.x"
"@stdlib/types" "^0.0.x"
debug "^2.6.9"
complex.js@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.1.1.tgz#0675dac8e464ec431fb2ab7d30f41d889fb25c31"
integrity sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
decimal.js@^10.3.1:
version "10.3.1"
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
escape-latex@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/escape-latex/-/escape-latex-1.2.0.tgz#07c03818cf7dac250cce517f4fda1b001ef2bca1"
integrity sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==
fraction.js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
javascript-natural-sort@^0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
jstat@^1.9.5:
version "1.9.5"
resolved "https://registry.yarnpkg.com/jstat/-/jstat-1.9.5.tgz#9941741566f683624ddeb56f5ba60ed8c29b374e"
integrity sha512-cWnp4vObF5GmB2XsIEzxI/1ZTcYlcfNqxQ/9Fp5KFUa0Jf/4tO0ZkGVnqoEHDisJvYgvn5n3eWZbd2xTVJJPUQ==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
mathjs@^10.6.0:
version "10.6.1"
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.6.1.tgz#95b34178eed65cbf7a63d35c468ad3ac912f7ddf"
integrity sha512-8iZp6uUKKBoCFoUHze9ydsrSji9/IOEzMhwURyoQXaLL1+ILEZnraw4KzZnUBt/XN6lPJPV+7JO94oil3AmosQ==
dependencies:
"@babel/runtime" "^7.18.3"
complex.js "^2.1.1"
decimal.js "^10.3.1"
escape-latex "^1.2.0"
fraction.js "^4.2.0"
javascript-natural-sort "^0.7.1"
seedrandom "^3.0.5"
tiny-emitter "^2.1.0"
typed-function "^2.1.0"
minimist@^1.2.0:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
pdfast@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/pdfast/-/pdfast-0.2.0.tgz#8cbc556e1bf2522177787c0de2e0d4373ba885c9"
integrity sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
readable-stream@^2.1.4:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
regenerator-runtime@^0.13.4:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
rescript@^9.1.4:
version "9.1.4"
resolved "https://registry.yarnpkg.com/rescript/-/rescript-9.1.4.tgz#1eb126f98d6c16942c0bf0df67c050198e580515"
integrity sha512-aXANK4IqecJzdnDpJUsU6pxMViCR5ogAxzuqS0mOr8TloMnzAjJFu63fjD6LCkWrKAhlMkFFzQvVQYaAaVkFXw==
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
seedrandom@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7"
integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
tiny-emitter@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
typed-function@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.1.0.tgz#ded6f8a442ba8749ff3fe75bc41419c8d46ccc3f"
integrity sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
utility-tools@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/utility-tools/-/utility-tools-0.2.2.tgz#fdea9678d4d3b6e8b76184b35e6ac97e20c6079d"
integrity sha512-Bbp5jZaxPSeALD75A2AGh0rvmuYSXBqZ3h6W5+VJIoRympXYwAJ3k8UmBNCBuM0uLu6XdSeYIfR4sRlgg+jrIA==
dependencies:
"@quri/squiggle-lang" "^0.2.11"

View File

@ -1 +0,0 @@
Deprecated; see webpage-refactor instead.

View File

@ -1,601 +0,0 @@
/* Imports */
import Head from "next/head";
import React, { useState } from "react";
import { DrawGraph, removeOldSvg } from "./labeledGraph";
import { SubmitButton } from "./submitButton";
import { DisplayElement } from "./displayElement";
import { DisplayAsMarkdown } from "./displayAsMarkdown";
import { CreateTable, buildRows } from "./findPaths";
import { DataSetChanger } from "./datasetChanger";
import { ComparisonsChanger } from "./comparisonsChanger";
import { pushToMongo } from "./pushToMongo.js";
import {
increasingList,
maxMergeSortSteps,
expectedNumMergeSortSteps,
conservativeNumMergeSortSteps,
} from "./utils.js";
/* DEFINTIONS */
const DEFAULT_COMPARE = () => "x to y"; // 1/Math.random() - 1 // Useful for testing, cause I can make the default number change.
const estimatedMergeSortSteps = conservativeNumMergeSortSteps; // pander to human biases so that users complain less.
/* Misc. helpers */
let buildLinks = (quantitativeComparisons) =>
quantitativeComparisons.map(
([element1, element2, distance, reasoning, squiggleString]) => ({
source: element1,
target: element2,
distance: distance,
reasoning: reasoning,
squiggleString: squiggleString,
})
);
Array.prototype.containsArray = function (val) {
var hash = {};
for (var i = 0; i < this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
};
let checkIfListIsOrdered = (arr, binaryComparisons) => {
let l = arr.length;
let isOrdered = true;
for (let i = 0; i < l - 1; i++) {
isOrdered =
isOrdered && binaryComparisons.containsArray([arr[i], arr[i + 1]]);
}
return isOrdered;
};
let nicelyFormatLinks = (quantitativeComparisons, listOfElements) =>
quantitativeComparisons.map(
([element1, element2, distance, reasoning, squiggleString]) => ({
source: listOfElements[element1].name,
target: listOfElements[element2].name,
distance: distance,
reasoning: reasoning,
squiggleString: squiggleString,
})
);
// Main react component
export default function ComparisonView({ listOfElementsForView }) {
/* State */
// initial state values
let initialListOfElements = listOfElementsForView.map((element, i) => ({
...element,
id: i,
}));
let initialPosList = increasingList(listOfElementsForView.length); // [0,1,2,3,4]
let initialComparePair = [
initialPosList[initialPosList.length - 2],
initialPosList[initialPosList.length - 1],
];
let initialInputValue = "x to y";
let initialReasoning = "";
let initialBinaryComparisons = [];
let initialQuantitativeComparisons = [];
let initialIsListOdered = false;
let initialOrderedList = [];
let initialShowAdvancedOptions = false;
let initialShowComparisons = false;
let initialShowLoadComparisons = false;
let initialShowChangeDataSet = false;
let initialNumSteps = 0;
let initialMaxSteps = maxMergeSortSteps(listOfElementsForView.length);
let initialExpectedSteps = estimatedMergeSortSteps(
listOfElementsForView.length
);
let initialTableRows = [];
let initialDontPushSubmitButtonAnyMore = false;
// state variables and functions
const [listOfElements, setListOfElements] = useState(initialListOfElements);
const [posList, setPosList] = useState(initialPosList);
const [toComparePair, setToComparePair] = useState(initialComparePair);
const [inputValue, setInputValue] = useState(initialInputValue);
const [reasoning, setReasoning] = useState(initialReasoning);
const [binaryComparisons, setBinaryComparisons] = useState(
initialBinaryComparisons
);
const [quantitativeComparisons, setQuantitativeComparisons] = useState(
initialQuantitativeComparisons
); // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons.
const [isListOrdered, setIsListOrdered] = useState(initialIsListOdered);
const [orderedList, setOrderedList] = useState(initialOrderedList);
const [dontPushSubmitButtonAnyMore, setDontPushSubmitButtonAnyMore] =
useState(initialDontPushSubmitButtonAnyMore);
let [showAdvancedOptions, changeShowAdvanceOptions] = useState(
initialShowAdvancedOptions
);
let [showComparisons, changeShowComparisons] = useState(
initialShowComparisons
);
let [showLoadComparisons, changeShowLoadComparisons] = useState(
initialShowLoadComparisons
);
let [showChangeDataSet, changeshowChangeDataSet] = useState(
initialShowChangeDataSet
);
let [numSteps, changeNumSteps] = useState(initialNumSteps);
let [maxSteps, changeMaxSteps] = useState(initialMaxSteps);
let [expectedSteps, changeExpectedSteps] = useState(initialExpectedSteps);
let [tableRows, setTableRows] = useState(initialTableRows);
/* Convenience utils: restart + changeDataSet */
let restart = (
posList,
initialBinaryComparisons2,
initialQuantitativeComparisons2
) => {
//({posList, initialBinaryComparisons2, initialQuantitativeComparisons2}) => {
setToComparePair([
posList[posList.length - 2],
posList[posList.length - 1],
]);
setInputValue(initialInputValue);
setBinaryComparisons(initialBinaryComparisons2 || initialBinaryComparisons);
setQuantitativeComparisons(
initialQuantitativeComparisons2 || initialQuantitativeComparisons
);
setIsListOrdered(initialIsListOdered);
setOrderedList(initialOrderedList);
changeNumSteps(initialNumSteps);
removeOldSvg();
setTableRows(initialTableRows);
setDontPushSubmitButtonAnyMore(initialDontPushSubmitButtonAnyMore);
};
let changeDataSet = (listOfElementsNew) => {
listOfElementsNew = listOfElementsNew.map((element, i) => ({
...element,
id: i,
}));
let newPosList = increasingList(listOfElementsNew.length);
let newListLength = listOfElementsNew.length;
setListOfElements(listOfElementsNew);
setPosList(increasingList(listOfElementsNew.length));
setToComparePair([
newPosList[newPosList.length - 2],
newPosList[newPosList.length - 1],
]);
changeExpectedSteps(estimatedMergeSortSteps(newListLength));
changeMaxSteps(maxMergeSortSteps(newListLength));
restart(newPosList);
// restart({posList: newPosList})
};
let changeComparisons = async (links) => {
let quantitativeComparisons2 = [];
let binaryComparisons2 = [];
// links.shift();
for (let link of links) {
let { source, target, distance, reasoning, squiggleString } = link;
let searchByName = (name, candidate) => candidate.name == name;
let testForSource = (candidate) => searchByName(source, candidate);
let testForTarget = (candidate) => searchByName(target, candidate);
let element1 = listOfElements.findIndex(testForSource);
let element2 = listOfElements.findIndex(testForTarget);
if (element1 == -1 || element2 == -1) {
console.log("link", link);
console.log(source);
console.log(target);
alert(JSON.stringify(link, null, 4));
throw new Error("Comparisons include unknown elements, please retry");
}
quantitativeComparisons2.push([
element1,
element2,
distance,
reasoning,
squiggleString || distance,
]);
binaryComparisons2.push([element1, element2]);
}
// return ({quantitativeComparisons: quantitativeComparisons2, binaryComparisons: binaryComparisons2})
//restart({posList, initialBinaryComparisons2=initialBinaryComparisons, initialQuantitativeComparisons2=initialQuantitativeComparisons})
// restart(posList, binaryComparisons2, quantitativeComparisons2)
setQuantitativeComparisons(quantitativeComparisons2);
setBinaryComparisons(binaryComparisons2);
};
// Manipulations
let compareTwoElements = (newBinaryComparisons, element1, element2) => {
let element1Greater = newBinaryComparisons.containsArray([
element1,
element2,
]);
let element2Greater = newBinaryComparisons.containsArray([
element2,
element1,
]);
if (element1Greater || element2Greater) {
return element1Greater && !element2Greater;
} else {
setToComparePair([element1, element2]);
//console.log(`No comparison found between ${element1} and ${element2}`)
//console.log(`Comparisons:`)
//console.log(JSON.stringify(newBinaryComparisons, null, 4));
return "No comparison found";
}
};
function merge(newBinaryComparisons, left, right) {
let sortedArr = []; // the sorted elements will go here
while (left.length && right.length) {
// insert the biggest element to the sortedArr
let comparison = compareTwoElements(
newBinaryComparisons,
left[0],
right[0]
);
if (comparison == "No comparison found") {
return "No comparison found; unable to proceed";
} else if (comparison) {
// left[0] > right[0]
sortedArr.push(left.shift());
} else {
sortedArr.push(right.shift());
}
}
// use spread operator and create a new array, combining the three arrays
return [...sortedArr, ...left, ...right]; // if they don't have the same size, the remaining ones will be greater than the ones before
}
function mergeSort({ array, comparisons }) {
console.log("mergesort");
console.log({ array, comparisons });
console.log("/console");
if (array == "No comparison found; unable to proceed") {
return "No comparison found; unable to proceed";
}
const half = array.length / 2;
// the base case is array length <=1
if (array.length <= 1) {
return array;
}
const left = array.slice(0, half); // the first half of the array
const right = array.slice(half, array.length); // Note that splice is destructive.
let orderedFirstHalf = mergeSort({ array: left, comparisons });
let orderedSecondHalf = mergeSort({ array: right, comparisons });
if (
orderedFirstHalf != "No comparison found; unable to proceed" &&
orderedSecondHalf != "No comparison found; unable to proceed"
) {
let result = merge(comparisons, orderedFirstHalf, orderedSecondHalf);
return result;
} else {
return "No comparison found; unable to proceed";
}
}
let nextStepSimple = (posList, binaryComparisons, element1, element2) => {
//console.log("Binary comparisons: ")
//console.log(JSON.stringify(binaryComparisons, null, 4));
let newComparison = [element1, element2]; // [element1, element2]
let newBinaryComparisons = [...binaryComparisons, newComparison];
//console.log("New binaryComparisons: ")
//console.log(JSON.stringify(newBinaryComparisons, null, 4));
setBinaryComparisons(newBinaryComparisons);
let result = mergeSort({
array: posList,
comparisons: newBinaryComparisons,
});
//console.log(result)
if (
result != "No comparison found; unable to proceed" &&
checkIfListIsOrdered(result, newBinaryComparisons)
) {
// console.log(`isListOrdered: ${isListOrdered}`)
console.log("poslist@nextStepSimple");
console.log(posList);
console.log("result@nextStepSimple");
console.log(result);
return [true, result];
} else {
return [false, result];
}
};
let nextStepInput = async ({
posList,
binaryComparisons,
inputValue,
reasoning,
element1,
element2,
squiggleString,
}) => {
if (!dontPushSubmitButtonAnyMore) {
if (inputValue < 1 && inputValue > 0) {
let inverse = 1 / inputValue;
if (squiggleString == inputValue) {
inputValue = inverse;
squiggleString = inverse;
} else {
inputValue = inverse;
squiggleString = `(${squiggleString})^(-1)`;
}
[element1, element2] = [element2, element1];
}
console.log(`posList@nextStepInput:`);
console.log(posList);
let [successStatus, result] = nextStepSimple(
posList,
binaryComparisons,
element1,
element2
);
let newQuantitativeComparison = [
element1,
element2,
inputValue,
reasoning,
squiggleString || inputValue,
];
let newQuantitativeComparisons = [
...quantitativeComparisons,
newQuantitativeComparison,
];
setQuantitativeComparisons(newQuantitativeComparisons);
setInputValue(DEFAULT_COMPARE());
setReasoning("");
changeNumSteps(numSteps + 1);
if (successStatus) {
setDontPushSubmitButtonAnyMore(true);
let jsObject = nicelyFormatLinks(
quantitativeComparisons,
listOfElements
);
await pushToMongo(jsObject);
console.log(jsObject);
alert(
"Comparisons completed. Background work might take a while, or straight-out fail"
);
setIsListOrdered(true);
setOrderedList(result);
await buildRows({
isListOrdered: true,
orderedList: result,
listOfElements,
links: buildLinks(newQuantitativeComparisons),
rows: tableRows,
setTableRows,
});
/*
setTimeout(async () => {
// Make sure to do this after the
}, 100);
*/
}
}
};
// Html
return (
<div className="flex flex-col items-center justify-center min-h-screen py-2">
{/* Webpage name & favicon */}
<div className="mt-20">
<Head>
<title>Utility Function Extractor</title>
<link rel="icon" href="/favicon.ico" />
</Head>
</div>
<main className="flex flex-col items-center w-full flex-1 px-20 text-center">
{/* Heading */}
<h1 className="text-6xl font-bold">Utility Function Extractor</h1>
{/* Approximate progress indicator */}
<p>{`${numSteps} out of ~${expectedSteps} (max ${maxSteps}) comparisons`}</p>
{/* Comparison section */}
<div className={isListOrdered ? "hidden" : ""}>
<div className="flex flex-wrap items-center max-w-4xl sm:w-full mt-10">
{/* Element 1 */}
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
<div className="block m-auto text-center">
<DisplayElement
element={listOfElements[toComparePair[0]]}
></DisplayElement>
</div>
</div>
{/* Comparison actuator (text, previously number) */}
<div className="flex m-auto w-72">
<div className="block m-auto text-center">
<br />
<label>
{`... is `}
<br />
<input
type="text"
className="text-center text-blueGray-600 bg-white rounded text-lg border-0 shadow outline-none focus:outline-none focus:ring w-8/12 h-10 m-2"
value={inputValue}
onChange={(event) => {
//console.log(event)
//console.log(event.target.value)
setInputValue(event.target.value);
}}
/>
<br />
{`times as valuable as ...`}
</label>
<br />
<SubmitButton
posList={posList}
binaryComparisons={binaryComparisons}
inputValue={inputValue}
reasoning={reasoning}
toComparePair={toComparePair}
nextStepInput={nextStepInput}
dontPushSubmitButtonAnyMore={dontPushSubmitButtonAnyMore}
/>
</div>
</div>
{/* Element 2 */}
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
<div className="block m-auto text-center">
<DisplayElement
element={listOfElements[toComparePair[1]]}
></DisplayElement>
</div>
</div>
</div>
<br />
<label className="">
{"Notes and reasoning:"}
<textarea
className="mt-2 px-3 py-4 placeholder-blueGray-300 text-blueGray-600 relative bg-white bg-white rounded text-base border-0 shadow outline-none focus:outline-none focus:ring w-full"
placeholder={
numSteps == 0
? "Please write your name here if you want QURI to be able to identify your answers later"
: ""
}
value={reasoning}
onChange={(event) => setReasoning(event.target.value)}
/>
</label>
<br />
</div>
{/* Results section */}
<div className={isListOrdered ? "" : "hidden"}>
{/* Graph */}
<div className="flex items-center text-center">
<DrawGraph
isListOrdered={isListOrdered}
orderedList={orderedList}
listOfElements={listOfElements}
links={buildLinks(quantitativeComparisons)}
></DrawGraph>
</div>
{/* Comparison table */}
<div className="flex items-center text-center ">
<CreateTable
isListOrdered={isListOrdered}
orderedList={orderedList}
listOfElements={listOfElements}
links={buildLinks(quantitativeComparisons)}
tableRows={tableRows}
setTableRows={setTableRows}
></CreateTable>
</div>
</div>
{/* Convenience functions */}
<div className="w-2/12 flex justify-center mt-10">
<button
className="text-gray-500 text-sm"
onClick={() => changeShowAdvanceOptions(!showAdvancedOptions)}
>
Advanced options
</button>
</div>
<div
className={
showAdvancedOptions
? "flex flex-wrap -mx-4 overflow-hidden"
: "hidden"
}
>
{/* Button: Restart */}
<div className="my-4 px-4 w-1/4 overflow-hidden">
<button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick={() => restart(posList)}
>
{/* onClick={() => restart({posList})}> */}
Restart
</button>
</div>
{/* Button: Show comparisons */}
<div className="my-4 px-4 w-1/4 overflow-hidden">
<button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick={() => changeShowComparisons(!showComparisons)}
>
Show comparisons
</button>
</div>
{/* Button: Load comparisons */}
<div className="my-4 px-4 w-1/4 overflow-hidden">
<button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick={() => changeShowLoadComparisons(!showLoadComparisons)}
>
Load comparisons
</button>
</div>
{/* Button: Change dataset */}
<div className="my-4 px-4 w-1/4 overflow-hidden">
<button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick={() => changeshowChangeDataSet(!showChangeDataSet)}
>
Use your own data
</button>
</div>
</div>
{/* Change dataset section */}
<div className={showChangeDataSet ? "inline mt-5" : "hidden"}>
<DataSetChanger handleSubmit={changeDataSet} />
</div>
{/* Show comparisons section */}
<div className={showComparisons ? "inline mt-5" : "hidden"}>
<div className="text-left">
<DisplayAsMarkdown
markdowntext={`
${
"" /*
## Comparisons
### Binary comparisons
${JSON.stringify(binaryComparisons, null, 4)}
*/
}
### Numerical comparisons
${JSON.stringify(
nicelyFormatLinks(quantitativeComparisons, listOfElements),
null,
4
)}
`}
className={""}
></DisplayAsMarkdown>
</div>
</div>
{/* Load comparisons section */}
<div className={showLoadComparisons ? "inline mt-5" : "hidden"}>
<ComparisonsChanger handleSubmit={changeComparisons} />
{/*<ComparisonsChanger handleSubmit={changeComparisons} />*/}
</div>
</main>
</div>
);
}

View File

@ -1,99 +0,0 @@
import React, { useState } from "react";
export function ComparisonsChanger({ handleSubmit }) {
// let defaultText=JSON.stringify(nicelyFormatLinks(quantitativeComparisons, listOfElements), null, 4)
let [value, setValue] = useState(``);
const [displayingDoneMessage, setDisplayingDoneMessage] = useState(false);
const [displayingDoneMessageTimer, setDisplayingDoneMessageTimer] =
useState(null);
let handleChange = (event) => {
setValue(event.target.value);
};
let handleSubmitInner = (event) => {
clearTimeout(displayingDoneMessageTimer);
event.preventDefault();
//console.log(event)
console.log("value@handleSubmitInner@ComparisonsChanger");
//console.log(typeof(value));
console.log(value);
try {
let newData = JSON.parse(value);
//console.log(typeof(newData))
//console.log(newData)
handleSubmit(newData);
/*
if(!newData.length || newData.length < 2){
throw Error("Not enough objects")
}
*/
setDisplayingDoneMessage(true);
let timer = setTimeout(() => setDisplayingDoneMessage(false), 3000);
setDisplayingDoneMessageTimer(timer);
} catch (error) {
setDisplayingDoneMessage(false);
//alert(error)
//console.log(error)
let substituteText = `Error: ${error.message}
Try something like:
[
{
"source": "x",
"target": "y",
"distance": 99999.99999999999,
"reasoning": "blah blah"
},
{
"source": "y",
"target": "z",
"distance": 1,
"reasoning": "blah blah"
},
{
"source": "x",
"target": "z",
"distance": 10,
"reasoning": "blah blah"
}
]
Your old input was: ${value}`;
setValue(substituteText);
}
};
return (
<form onSubmit={handleSubmitInner} className="inline">
<p>Load comparisons in the same style as in "Show comparisons".</p>
<p>These will override your current comparisons.</p>
<br />
<textarea
value={value}
onChange={handleChange}
rows="10"
cols="50"
className=""
/>
<br />
<button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5 p-10"
onClick={handleSubmitInner}
>
Change comparisons
</button>
&nbsp;
<button
className={
displayingDoneMessage
? "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5 p-10"
: "hidden"
}
>
Done!
</button>
</form>
);
}

View File

@ -1,280 +0,0 @@
import React, { useState, useEffect } from "react";
import * as d3 from "d3";
export function drawChart(height, width) {
d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height)
.style("border", "1px solid black")
.append("text")
.attr("fill", "green")
.attr("x", 50)
.attr("y", 50)
.text("Hello D3");
}
export function drawCircles() {
var svg = d3
.select("#circles")
.append("svg")
.attr("width", 960)
.attr("height", 500)
.attr("bgcolor", "blue");
var background = svg
.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "blue");
var ball = svg
.append("circle")
.attr("r", 73)
.attr("cx", 480)
.attr("cy", 250)
.style("fill", "#ffe41e");
}
export function drawGraph() {
let margin = { top: 20, right: 30, bottom: 20, left: 30 };
let width = 900 - margin.left - margin.right;
let height = 600 - margin.top - margin.bottom;
var svg = d3
.select("#graph")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
let data = {
nodes: [
{
id: 1,
name: "A",
},
{
id: 2,
name: "B",
},
{
id: 3,
name: "C",
},
{
id: 4,
name: "D",
},
{
id: 5,
name: "E",
},
{
id: 6,
name: "F",
},
{
id: 7,
name: "G",
},
{
id: 8,
name: "H",
},
{
id: 9,
name: "I",
},
{
id: 10,
name: "J",
},
],
links: [
{
source: 1,
target: 2,
},
{
source: 1,
target: 5,
},
{
source: 1,
target: 6,
},
{
source: 2,
target: 3,
},
{
source: 2,
target: 7,
},
{
source: 3,
target: 4,
},
{
source: 8,
target: 3,
},
{
source: 4,
target: 5,
},
{
source: 4,
target: 9,
},
{
source: 5,
target: 10,
},
],
};
console.log(data);
// List of node names
var allNodes = data.nodes.map(function (d) {
return d.name;
});
// A linear scale to position the nodes on the X axis
var x = d3.scalePoint().range([0, width]).domain(allNodes);
// Add the circle for the nodes
svg
.selectAll("mynodes")
.data(data.nodes)
.enter()
.append("circle")
.attr("cx", function (d) {
return x(d.name);
})
.attr("cy", height - 30)
.attr("r", 8)
.style("fill", "#69b3a2");
// And give them a label
svg
.selectAll("mylabels")
.data(data.nodes)
.enter()
.append("text")
.attr("x", function (d) {
return x(d.name);
})
.attr("y", height - 10)
.text(function (d) {
return d.name;
})
.style("text-anchor", "middle");
// Add links between nodes. Here is the tricky part.
// In my input data, links are provided between nodes -id-, NOT between node names.
// So I have to do a link between this id and the name
var idToNode = {};
data.nodes.forEach(function (n) {
idToNode[n.id] = n;
});
// Cool, now if I do idToNode["2"].name I've got the name of the node with id 2
// Add the links
svg
.selectAll("mylinks")
.data(data.links)
.enter()
.append("path")
.attr("d", function (d) {
let start = x(idToNode[d.source].name);
// X position of start node on the X axis
let end = x(idToNode[d.target].name);
// X position of end node
return (
[
"M",
start,
height - 30,
// the arc starts at the coordinate x=start, y=height-30 (where the starting node is)
"A",
// This means we're gonna build an elliptical arc
(start - end) / 2,
",",
// Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance
(start - end) / 2,
0,
0,
",",
start < end ? 1 : 0,
end,
",",
height - 30,
]
// We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down.
.join(" ")
);
})
.style("fill", "none")
.attr("stroke", "black");
// labels for links
svg
.selectAll("mylinks")
.data(data.links)
.enter()
.append("text")
.attr("x", function (d) {
let start = x(idToNode[d.source].name);
// X position of start node on the X axis
let end = x(idToNode[d.target].name);
// X position of end node
return start + (end - start) / 2;
})
.attr("y", function (d) {
let start = x(idToNode[d.source].name);
// X position of start node on the X axis
let end = x(idToNode[d.target].name);
// X position of end node
return height - 30 - Math.abs(start - end) / 2; //height-30
})
.text(function (d) {
return `${idToNode[d.source].name}-${idToNode[d.target].name}`;
})
.style("text-anchor", "top");
svg
.selectAll("text")
.data(data.links)
.enter()
.append("text")
.attr("x", function (d) {
return d.source.x + (d.target.x - d.source.x) / 2;
})
.attr("y", function (d) {
return d.source.y + (d.target.y - d.source.y) / 2;
})
.text(function (d) {
return d.something;
});
}
export function D3Experiment() {
useEffect(() => {
drawGraph();
}, []);
return (
<div>
<div id="chart"></div>
<div id="circles"></div>
<div id="graph"></div>
</div>
);
}
export default D3Experiment;

View File

@ -1,109 +0,0 @@
import React, { useState } from "react";
export function DataSetChanger({ handleSubmit }) {
let [value, setValue] = useState(`[
{
"name": "Some element. The name field is necessary",
"url": "http://www.example.com",
"somethirdfield": "a"
},
{
"name": "Another element",
"url": "http://www.example1.com",
"somethirdfield": "b"
},
{
"name": "A third element",
"url": "http://www.example2.com",
"isReferenceValue": true,
"somethirdfield": "c"
}
]`);
const [displayingDoneMessage, setDisplayingDoneMessage] = useState(false);
const [displayingDoneMessageTimer, setDisplayingDoneMessageTimer] =
useState(null);
let handleChange = (event) => {
setValue(event.target.value);
};
let handleSubmitInner = (event) => {
clearTimeout(displayingDoneMessageTimer);
event.preventDefault();
//console.log(event)
console.log("value@handleSubmitInner@DataSetChanger");
//console.log(typeof(value));
console.log(value);
try {
let newData = JSON.parse(value);
//console.log(typeof(newData))
//console.log(newData)
handleSubmit(newData);
if (!newData.length || newData.length < 2) {
throw Error("Not enough objects");
}
setDisplayingDoneMessage(true);
let timer = setTimeout(() => setDisplayingDoneMessage(false), 3000);
setDisplayingDoneMessageTimer(timer);
} catch (error) {
setDisplayingDoneMessage(false);
//alert(error)
//console.log(error)
let substituteText = `Error: ${error.message}
Try something like:
[
{
"name": "Some element. The name field is necessary",
"url": "http://www.example.com",
"somethirdfield": "a"
},
{
"name": "Another element",
"url": "http://www.example1.com",
"somethirdfield": "b"
},
{
"name": "Another element",
"url": "http://www.example2.com",
"isReferenceValue": true,
"somethirdfield": "c"
}
]
Your old input was: ${value}`;
setValue(substituteText);
}
};
return (
<form onSubmit={handleSubmitInner} className="inline">
<br />
<br />
<textarea
value={value}
onChange={handleChange}
rows="10"
cols="50"
className=""
/>
<br />
<button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5 p-10"
onClick={handleSubmitInner}
>
Change dataset
</button>
&nbsp;
<button
className={
displayingDoneMessage
? "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5 p-10"
: "hidden"
}
>
Done!
</button>
</form>
);
}

View File

@ -1,30 +0,0 @@
import React from "react";
import ReactMarkdown from "react-markdown";
import gfm from "remark-gfm";
if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function (str, newStr) {
// If a regex pattern
if (
Object.prototype.toString.call(str).toLowerCase() === "[object regexp]"
) {
return this.replace(str, newStr);
}
// If a string
return this.replace(new RegExp(str, "g"), newStr);
};
}
export function DisplayAsMarkdown({ markdowntext, className }) {
//console.log(markdowntext)
markdowntext = markdowntext.replaceAll("\n", "\n\n");
return (
<ReactMarkdown
plugins={[gfm]}
children={markdowntext}
className={className}
/>
);
}

View File

@ -1,44 +0,0 @@
import React from "react";
let capitalizeFirstLetter = (string) =>
string.charAt(0).toUpperCase() + string.slice(1);
export function DisplayElement({ element }) {
let otherkeys = Object.keys(element).filter(
(key) =>
key != "name" && key != "url" && key != "id" && key != "isReferenceValue"
);
let othervalues = otherkeys.map((key) => element[key]);
let otherpairs = otherkeys.map((key, i) => ({
key: capitalizeFirstLetter(key),
value: othervalues[i],
}));
if (element.url) {
return (
<div>
{/*<a href={element.url} target="_blank">*/}
<h2>{`${element.name}`}</h2>
{/*</a>*/}
{otherpairs.map((pair) => (
<p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>
))}
<p>
<a href={element.url} target="_blank">
More info
</a>
</p>
</div>
);
} else {
return (
<div>
<h2>{`${element.name}`}</h2>
{otherpairs.map((pair) => (
<p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>
))}
</div>
);
}
}

View File

@ -1,415 +0,0 @@
/* Imports*/
import React from "react";
import {
numToAlphabeticalString,
formatLargeOrSmall,
avg,
hackyGeomMean,
getCoefficientOfVariation,
} from "../lib/utils.js";
/* Functions */
const pathPlusLink = (pathSoFar, link) => {
return [...pathSoFar, link];
// previously: pathSoFar.concat(link).flat()
// Note that concat is not destructive
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat
};
async function findPathsWithoutPrunning({
sourceElementId,
targetElementId,
maxLengthOfPath,
pathSoFar,
links,
nodes,
}) {
// This is an un-used function which might make findPaths more understandable
// It uses the same recursive functionality
// but has no path prunning
let paths = [];
/* Path traversing */
if (maxLengthOfPath > 0) {
for (let link of links) {
// vs let link of linksNow in findPaths
if (
(link.source == sourceElementId && link.target == targetElementId) ||
(link.source == targetElementId && link.target == sourceElementId)
) {
// direct Path
let newPath = pathPlusLink(pathSoFar, link);
paths.push(newPath);
} else if (link.source == sourceElementId) {
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementId: link.target,
targetElementId,
links: links, // vs let link of linksInner in findPaths
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
} else if (link.target == sourceElementId) {
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementId: link.source,
targetElementId,
links: links, // vs let link of linksInner in findPaths
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
}
}
}
return paths;
}
async function findPaths({
sourceElementId,
sourceElementPosition,
targetElementId,
targetElementPosition,
maxLengthOfPath,
pathSoFar,
links,
nodes,
}) {
// This is the key path finding function
// It finds the path from one element to another, recursively
// It used to be very computationally expensive until I added
// the path prunning step: Instead of traversing all links,
// traverse only those which are between the origin and target links
// this requires us to have a notion of "between"
let paths = [];
/* Path prunning*/
let minPos = Math.min(sourceElementPosition, targetElementPosition);
let maxPos = Math.max(sourceElementPosition, targetElementPosition);
let linksInner = links.filter(
(link) =>
minPos <= link.sourceElementPosition &&
link.sourceElementPosition <= maxPos &&
minPos <= link.targetElementPosition &&
link.targetElementPosition <= maxPos
);
let linksNow = linksInner.filter(
(link) => link.source == sourceElementId || link.target == sourceElementId
);
/* Path traversing */
if (maxLengthOfPath > 0) {
for (let link of linksNow) {
if (
(link.source == sourceElementId && link.target == targetElementId) ||
(link.source == targetElementId && link.target == sourceElementId)
) {
// direct Path
let newPath = pathPlusLink(pathSoFar, link);
paths.push(newPath);
} else if (link.source == sourceElementId) {
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementPosition: link.sourceElementPosition,
sourceElementId: link.target,
targetElementId,
targetElementPosition,
links: linksInner,
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
} else if (link.target == sourceElementId) {
let newPaths = await findPaths({
pathSoFar: pathPlusLink(pathSoFar, link),
maxLengthOfPath: maxLengthOfPath - 1,
sourceElementPosition: link.sourceElementPosition,
sourceElementId: link.source,
targetElementPosition,
targetElementId,
links: linksInner,
nodes,
});
if (newPaths.length != 0) {
paths.push(...newPaths);
}
}
}
}
return paths;
}
async function findDistancesForElement({
sourceElementId,
sourceElementPosition,
targetElementId,
targetElementPosition,
nodes,
links,
}) {
// This function gets all possible paths using findPaths
// then orders them correctly in the for loop
// (by flipping the distance to 1/distance when necessary)
// and then gets the array of weights for the different paths.
console.log(
`findDistance@findPaths.js from ${sourceElementPosition} to ${targetElementPosition}`
);
let maxLengthOfPath = Math.abs(sourceElementPosition - targetElementPosition);
let paths = await findPaths({
sourceElementId,
sourceElementPosition,
targetElementId,
targetElementPosition,
links,
nodes,
maxLengthOfPath,
pathSoFar: [],
});
let weights = [];
for (let path of paths) {
let currentSource = sourceElementId;
let weight = 1;
for (let element of path) {
let distance = 0;
if (element.source == currentSource) {
distance = element.distance;
currentSource = element.target;
} else if (element.target == currentSource) {
distance = 1 / Number(element.distance);
currentSource = element.source;
}
weight = weight * distance;
}
weights.push(weight);
}
return weights;
}
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");
/* Get or build reference element */
let referenceElements = nodes.filter((x) => x.isReferenceValue);
let midpoint = Math.round(nodes.length / 2);
let referenceElement =
referenceElements.length > 0 ? referenceElements[0] : nodes[midpoint];
console.log(`referenceElement.position: ${referenceElement.position}`);
/* Get distances. */
let distancesArray = nodes.map((node) => {
if (node.isReferenceValue || 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 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({
isListOrdered,
orderedList,
listOfElements,
links,
rows,
setTableRows,
}) {
console.log("buildRows@findPaths.js");
// This function is used in pages/comparisonView.js to create the rows that will be displayed.
// it is in there because it needs to be deployed after isListOrdered becomes true,
// and using an useEffect inside CreateTable was too messy.
if (
isListOrdered &&
!(orderedList.length < listOfElements.length) &&
rows.length == 0
) {
let nodes = [];
let positionDictionary = {};
orderedList.forEach((id, pos) => {
nodes.push({ ...listOfElements[id], position: pos });
positionDictionary[id] = pos;
});
links = links.map((link) => ({
...link,
sourceElementPosition: positionDictionary[link.source],
targetElementPosition: positionDictionary[link.target],
}));
let distances = await findDistancesFromAllElementsToAllReferencePoints({
nodes,
links,
}); //findDistancesForAllElements({ nodes, links });
rows = nodes.map((element, i) => ({
id: numToAlphabeticalString(element.position),
position: element.position,
name: element.name,
distances: distances[i],
}));
console.log(rows);
setTableRows(rows);
}
}
export function CreateTable({ tableRows }) {
/* This function receives a list of rows, and displays them nicely. */
function abridgeArrayAndDisplay(array) {
let newArray;
let formatForDisplay;
if (array.length > 10) {
newArray = array.slice(0, 9);
formatForDisplay = newArray.map((d) => formatLargeOrSmall(d));
formatForDisplay[9] = "...";
} else {
newArray = array;
formatForDisplay = newArray.map((d) => formatLargeOrSmall(d));
}
let result = JSON.stringify(formatForDisplay, null, 2).replaceAll(`"`, "");
return result;
}
return (
<div className="w-full">
<table className="table-auto">
<thead>
<tr>
<th>Id</th>
<th>&nbsp;&nbsp;&nbsp;</th>
<th>Position</th>
<th>&nbsp;&nbsp;&nbsp;</th>
<th>Element</th>
<th> &nbsp;&nbsp;&nbsp;</th>
<th>Possible relative values</th>
<th> &nbsp;&nbsp;&nbsp;</th>
<th>geomMean(relative values)</th>
<th>Coefficient of variation</th>
</tr>
</thead>
<tbody>
{tableRows.map((row) => (
<tr key={row.id}>
<td className="">{row.id}</td>
<td>&nbsp;&nbsp;&nbsp;</td>
<td className="">{row.position}</td>
<td>&nbsp;&nbsp;&nbsp;</td>
<td className="">{row.name}</td>
<td>&nbsp;&nbsp;&nbsp;</td>
<td className="">{abridgeArrayAndDisplay(row.distances)}</td>
<td>&nbsp;&nbsp;&nbsp;</td>
<td className="">
{formatLargeOrSmall(hackyGeomMean(row.distances))}
</td>
<td className="">
{formatLargeOrSmall(getCoefficientOfVariation(row.distances))}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
/* Testing */
//import fs from 'fs';
//import path from 'path';
/*
const directory = path.join(process.cwd(),"pages")
let links = JSON.parse(fs.readFileSync(path.join(directory, 'distancesExample.json'), 'utf8'));
let nodes = JSON.parse(fs.readFileSync(path.join(directory, 'listOfPosts.json'), 'utf8'));
let paths = findPaths({sourceElementId:2, targetElementId:0, pathSoFar: [], links, nodes, maxLengthOfPath: 2})
console.log(JSON.stringify(paths, null, 2))
*/
/*
let paths = findPaths({sourceElementId:2, targetElementId:0, links, nodes})
console.log(JSON.stringify(paths, null, 2))
*/
/*
let distances = findDistance({sourceElementId:2, targetElementId:4, links, nodes})
console.log(distances)
*/

View File

@ -1,186 +0,0 @@
import React, { useState, useEffect } from "react";
import * as d3 from "d3";
import {
toLocale,
truncateValueForDisplay,
numToAlphabeticalString,
formatLargeOrSmall,
} from "./utils.js";
const displayWidthPercentage = 0.85; // 0.85; // 0.7
let getlength = (number) => number.toString().length;
export function removeOldSvg() {
d3.select("#graph").select("svg").remove();
}
function drawGraphInner({ nodes, links }) {
// List of node ids for convenience
var nodeids = nodes.map((node) => node.id);
var positionById = {};
nodeids.forEach((nodeid, i) => (positionById[nodeid] = i));
console.log("NodeIds/positionById");
console.log(nodeids);
console.log(positionById);
// Calculate the dimensions
// let margin = { top: 0, right: 30, bottom: 20, left: 30 };
// let width = 900 - margin.left - margin.right;
let initialWindowWidth = window.innerWidth;
let margin = { top: 0, right: 10, bottom: 20, left: 10 };
let width =
initialWindowWidth * displayWidthPercentage - margin.left - margin.right;
var x = d3.scalePoint().range([0, width]).domain(nodeids);
let heights = links.map((link) => {
let start = x(positionById[link.source]);
let end = x(positionById[link.target]);
return Math.abs(start - end) / 2 + 70; // Magic constant.
});
console.log(heights);
let maxheight = Math.max(...heights);
let height = maxheight - margin.top - margin.bottom;
console.log(`height: ${height}`);
// Build the d3 graph
removeOldSvg();
let svg = d3
.select("#graph")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// A linear scale to position the nodes on the X axis
// Add the circle for the nodes
svg
.selectAll("mynodes")
.data(nodes)
.enter()
.append("circle")
.attr("cx", function (d) {
return x(d.id);
})
.attr("cy", height - 30)
.attr("r", 8)
.style("fill", "#69b3a2");
// And give them a label
svg
.selectAll("mylabels")
.data(nodes)
.enter()
.append("text")
.attr("x", function (d) {
return x(d.id);
})
.attr("y", height - 10)
.text(function (d) {
return numToAlphabeticalString(d.position);
})
.style("text-anchor", "middle");
// Add the links
svg
.selectAll("mylinks")
.data(links)
.enter()
.append("path")
.attr("d", function (d) {
let start = x(d.source);
// X position of start node on the X axis
let end = x(d.target);
// X position of end node
return (
[
"M",
start,
height - 30,
// the arc starts at the coordinate x=start, y=height-30 (where the starting node is)
"A",
// This means we're gonna build an elliptical arc
(start - end) / 2,
",",
// Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance
(start - end) / 2,
0,
0,
",",
start < end ? 1 : 0,
end,
",",
height - 30,
]
// We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down.
.join(" ")
);
})
.style("fill", "none")
.attr("stroke", "green"); // black
// labels for links
// smaller font.
svg
.selectAll("mylinks")
.data(links)
.enter()
.append("text")
.attr("x", function (d) {
let start = x(d.source);
// X position of start node on the X axis
let end = x(d.target);
// X position of end node
return start + (end - start) / 2; //-4*getlength(d.distance)
})
.attr("y", function (d) {
let start = x(d.source);
// X position of start node on the X axis
let end = x(d.target);
// X position of end node
return height - 36 - Math.abs(start - end) / 2; //height-30
})
.text(function (d) {
let distanceFormatted = formatLargeOrSmall(Number(d.distance));
return distanceFormatted;
if (d.distance == d.squiggleString || !d.squiggleString) {
return distanceFormatted;
} else {
// return `${d.squiggleString} → ${distanceFormatted}`;
return `(${d.squiggleString})`;
}
// return (truncateValueForDisplay(Number(d.distance)))
//return(Number(d.distance).toPrecision(2).toString())
})
.style("text-anchor", "middle");
// background
}
export function DrawGraph({
isListOrdered,
orderedList,
listOfElements,
links,
}) {
if (isListOrdered) {
let nodes = orderedList.map((id, pos) => ({
...listOfElements[id],
position: pos,
}));
drawGraphInner({ nodes, links });
}
return (
<div className="flex w-full items-center ">
<div
id="graph"
className="mx-auto flex justify-center w-full bg-red"
></div>
</div>
);
}

View File

@ -1,17 +0,0 @@
import axios from "axios";
const CONNECTION_IS_ACTIVE = true;
export async function pushToMongo(data) {
if (CONNECTION_IS_ACTIVE) {
let response = await axios.post(
"https://server.loki.red/utility-function-extractor",
{
data: data,
}
);
console.log(response);
}
}
// pushToMongo()

View File

@ -1,337 +0,0 @@
import axios from "axios";
let data = [
{
source: "Thinking Fast and Slow",
target: "The Mathematical Theory of Communication",
distance: 99999.99999999999,
reasoning:
"TFS: Not original work. 1 million buyers, 0.3m readers, 0.03m did anything with it long-term. Debiasing doesn't work that much. But maybe some general sanity effects.\nMTC: foundational to half of good fields. Direct applications key to telecoms and internet, AI. Is very natural and probably invented anyway, but let's ignore replaceability. ",
},
{
source: "The Global Priorities Institute's Research Agenda",
target: "Superintelligence",
distance: 100,
reasoning:
"GPI: good stuff but v v hard questions read by ~200.\nSuperintelligence: Maybe 50,000 copies? associated interview tour transformed the field.",
},
{
source: "Thinking Fast and Slow",
target: "The Global Priorities Institute's Research Agenda",
distance: "100",
reasoning: "",
},
{
source: "The Global Priorities Institute's Research Agenda",
target: "The Mathematical Theory of Communication",
distance: 1000,
reasoning: "",
},
{
source: "Superintelligence",
target: "The Mathematical Theory of Communication",
distance: 10,
reasoning: "",
},
{
source: "Categorizing Variants of Goodhart's Law",
target: "The Vulnerable World Hypothesis",
distance: 10,
reasoning: "",
},
{
source: "Shallow evaluations of longtermist organizations",
target: "The motivated reasoning critique of effective altruism",
distance: 10,
reasoning: "",
},
{
source: "Shallow evaluations of longtermist organizations",
target: "Categorizing Variants of Goodhart's Law",
distance: 100,
reasoning: "",
},
{
source: "The motivated reasoning critique of effective altruism",
target: "Categorizing Variants of Goodhart's Law",
distance: 10,
reasoning: "",
},
{
source: "Shallow evaluations of longtermist organizations",
target: "Thinking Fast and Slow",
distance: 10,
reasoning: "",
},
{
source: "Thinking Fast and Slow",
target: "The motivated reasoning critique of effective altruism",
distance: 1,
reasoning: "",
},
{
source: "The motivated reasoning critique of effective altruism",
target: "The Global Priorities Institute's Research Agenda",
distance: 1000,
reasoning: "",
},
{
source: "Categorizing Variants of Goodhart's Law",
target: "The Global Priorities Institute's Research Agenda",
distance: 100,
reasoning: "",
},
{
source: "The Vulnerable World Hypothesis",
target: "The Global Priorities Institute's Research Agenda",
distance: 10,
reasoning: "",
},
{
source: "Reversals in Psychology",
target: "A Model of Patient Spending and Movement Building",
distance: 10,
reasoning:
"RiP: Cleaning up 10,000 people's brains a bit.\nMPS: far more important topic",
},
{
source: "Database of orgs relevant to longtermist/x-risk work",
target:
"What are some low-information priors that you find practically useful for thinking about the world?",
distance: "5",
reasoning:
"\nDatabase just saves a bit of time, maybe 100 counterfactual applications",
},
{
source: "Reversals in Psychology",
target: "Database of orgs relevant to longtermist/x-risk work",
distance: 1,
reasoning: "",
},
{
source: "Database of orgs relevant to longtermist/x-risk work",
target: "A Model of Patient Spending and Movement Building",
distance: 10,
reasoning: "",
},
{
source:
"What are some low-information priors that you find practically useful for thinking about the world?",
target: "A Model of Patient Spending and Movement Building",
distance: 2,
reasoning: "",
},
{
source: "Center for Election Science EA Wiki stub",
target:
"Extinguishing or preventing coal seam fires is a potential cause area",
distance: 1000,
reasoning: "",
},
{
source: "A comment on setting up a charity",
target: "Center for Election Science EA Wiki stub",
distance: 10,
reasoning: "",
},
{
source: "A comment on setting up a charity",
target: "Reversals in Psychology",
distance: 200,
reasoning: "",
},
{
source: "Center for Election Science EA Wiki stub",
target: "Reversals in Psychology",
distance: 20,
reasoning: "",
},
{
source: "Reversals in Psychology",
target:
"Extinguishing or preventing coal seam fires is a potential cause area",
distance: "50",
reasoning: "",
},
{
source: "Database of orgs relevant to longtermist/x-risk work",
target:
"Extinguishing or preventing coal seam fires is a potential cause area",
distance: "50",
reasoning: "",
},
{
source:
"What are some low-information priors that you find practically useful for thinking about the world?",
target:
"Extinguishing or preventing coal seam fires is a potential cause area",
distance: "10",
reasoning: "",
},
{
source: "A Model of Patient Spending and Movement Building",
target:
"Extinguishing or preventing coal seam fires is a potential cause area",
distance: 1,
reasoning: "",
},
{
source: "A comment on setting up a charity",
target: "Shallow evaluations of longtermist organizations",
distance: 1000,
reasoning: "",
},
{
source: "Center for Election Science EA Wiki stub",
target: "Shallow evaluations of longtermist organizations",
distance: 100,
reasoning: "",
},
{
source: "Reversals in Psychology",
target: "Shallow evaluations of longtermist organizations",
distance: 100,
reasoning: "",
},
{
source: "Database of orgs relevant to longtermist/x-risk work",
target: "Shallow evaluations of longtermist organizations",
distance: 100,
reasoning: "",
},
];
async function pushToMongoManually() {
let response = await axios.post(
"http://metaforecast-twitter-bot.herokuapp.com/utility-function-extractor",
{
data: data,
}
);
console.log(response);
}
pushToMongoManually();

View File

@ -1,23 +0,0 @@
import axios from "axios";
export async function squiggleWrapper(input) {
let response = await axios.post("https://server.loki.red/squiggle", {
model: `mean(${input})`,
});
if (response.status == 200) {
try {
console.log(response.data);
if (!!response.data && !!response.data.value) {
// console.log(response.data.value);
let result = response.data.value.value; //hd.VAL;
console.log(result);
return result;
}
} catch (error) {
console.log(error);
return null;
}
}
return null;
}
// squiggle("1 to 4");

View File

@ -1,66 +0,0 @@
/* Imports */
import React, { useState } from "react";
import { squiggleWrapper } from "./squiggleWrapper";
export function SubmitButton({
posList,
binaryComparisons,
inputValue,
reasoning,
toComparePair,
nextStepInput,
dontPushSubmitButtonAnyMore,
}) {
// This element didn't necessarily have to exist, but it made it easier for debugging purposes
let onClick = async (event) => {
if (!dontPushSubmitButtonAnyMore) {
//event.preventDefault();
let obj = {
posList,
binaryComparisons,
inputValue,
squiggleString: inputValue,
reasoning,
element1: toComparePair[1],
element2: toComparePair[0],
};
//
console.log("input@SubmitInputButton");
console.log(obj);
if (!!Number(inputValue) && inputValue >= 0) {
nextStepInput(obj);
} else if (!!Number(inputValue) && inputValue < 0) {
alert("Suport for negative numbers experimental");
nextStepInput({
...obj,
inputValue: inputValue,
squiggleString: inputValue,
});
} else {
let potentialSquiggleOutput = await squiggleWrapper(inputValue);
if (!!Number(potentialSquiggleOutput)) {
nextStepInput({
...obj,
inputValue: potentialSquiggleOutput,
squiggleString: inputValue,
});
} else {
alert("Your input is not a number or a valid distribution");
}
}
}
};
return (
<button
className={
!dontPushSubmitButtonAnyMore
? "bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
: "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5"
}
onClick={onClick}
>
Submit
</button>
);
}

View File

@ -1,163 +0,0 @@
import crypto from "crypto";
export const hashString = (string) =>
crypto.createHash("md5").update(string).digest("hex");
const id = (x) => x;
export const transformSliderValueToActualValue = id;
export const transformSliderValueToPracticalValue = id;
export const _transformSliderValueToActualValue = (value) => 10 ** value; //>= 2 ? Math.round(10 ** value) : Math.round(10 * 10 ** value) / 10
export const toLocale = (x) => Number(x).toLocaleString();
export const truncateValueForDisplay = (value) => {
if (value > 10) {
return Number(Math.round(value).toPrecision(2));
} else if (value > 1) {
return Math.round(value * 10) / 10;
} else if (value <= 1) {
return value;
}
};
export const _transformSliderValueToPracticalValue = (value) =>
truncateValueForDisplay(transformSliderValueToActualValue(value));
export function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export function numToAlphabeticalString(num) {
// https://stackoverflow.com/questions/45787459/convert-number-to-alphabet-string-javascript/45787487
num = num + 1;
var s = "",
t;
while (num > 0) {
t = (num - 1) % 26;
s = String.fromCharCode(65 + t) + s;
num = ((num - t) / 26) | 0;
}
return `#${s}` || undefined;
}
let topOutAt100AndValidate = (x) => {
// return 10;
if (x == x) {
return x > 99 ? 99 : x < 0 ? 2 : x;
} else {
return 10;
}
};
export function formatLargeOrSmall(num) {
let result;
if (num >= 1) {
result = toLocale(truncateValueForDisplay(num));
} else if (num > 0) {
let candidateNumSignificantDigits =
-Math.floor(Math.log(num) / Math.log(10)) + 1;
let numSignificantDigits = topOutAt100AndValidate(
candidateNumSignificantDigits
);
result = num.toFixed(numSignificantDigits);
} else if (-1 < num) {
let candidateNumSignificantDigits =
-Math.floor(Math.log(Math.abs(num)) / Math.log(10)) + 1;
let numSignificantDigits = topOutAt100AndValidate(
candidateNumSignificantDigits
);
result = num.toFixed(numSignificantDigits);
} else if (num <= -1) {
result = "-" + toLocale(truncateValueForDisplay(-num));
} else {
result = toLocale(num); //return "~0"
}
console.log(`${num} -> ${result}`);
return result;
}
const firstFewMaxMergeSortSequence = [
0, 0, 1, 3, 5, 8, 11, 14, 17, 21, 25, 29, 33, 37, 41, 45, 49, 54, 59, 64, 69,
74, 79, 84, 89, 94, 99, 104, 109, 114, 119, 124, 129, 135, 141, 147, 153, 159,
165, 171, 177, 183, 189, 195, 201, 207, 213, 219, 225, 231, 237, 243, 249,
255, 261, 267, 273, 279, 285,
];
export function maxMergeSortSteps(n) {
if (n < firstFewMaxMergeSortSequence.length) {
return firstFewMaxMergeSortSequence[n];
} else {
return (
maxMergeSortSteps(Math.floor(n / 2)) +
maxMergeSortSteps(Math.ceil(n / 2)) +
n -
1
);
}
}
export function expectedNumMergeSortSteps(n) {
// https://cs.stackexchange.com/questions/82862/expected-number-of-comparisons-in-a-merge-step
// n-2 for each step, so (n-2) + (n-2)/2 + (n-2)/4 + ...
// ~ 2*(n-2) -1 = 2*n - 3
if (n == 0) {
return 0;
} else if (n == 1) {
return 0;
} else if (n == 2) {
return 1;
} else if (n == 3) {
return 2;
} else {
return (
Math.ceil(n ** 2 / (n + 2)) + expectedNumMergeSortSteps(Math.ceil(n / 2))
);
}
}
const sum = (arr) => arr.reduce((a, b) => a + b, 0);
export const avg = (arr) => sum(arr) / arr.length;
export const geomMean = (arr) => {
let n = arr.length;
let logavg = sum(arr.map((x) => Math.log(x))); // works for low numbers much better
let result = Math.exp(logavg / n);
return result;
};
export const hackyGeomMean = (arr) => {
let nonPositiveNumbers = arr.filter((x) => x <= 0);
if (nonPositiveNumbers.length == 0) {
return geomMean(arr);
} else {
return avg(arr);
}
};
export function conservativeNumMergeSortSteps(n) {
return Math.ceil((expectedNumMergeSortSteps(n) + maxMergeSortSteps(n)) / 2);
}
// export const geomMean = (arr) => arr.reduce((a, b) => a * b, 1); // ^ (1 / arr.length); // didn't work so well for low numbers.
export const increasingList = (n) => Array.from(Array(n).keys());
function getStdev(arr) {
if (Array.isArray(arr) && arr.length > 0) {
const n = arr.length;
const mean = arr.reduce((a, b) => a + b) / n;
return Math.sqrt(
arr.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n
);
} else {
return 0;
}
}
export const getCoefficientOfVariation = (arr) => {
let nonPositiveNumbers = arr.filter((x) => x <= 0);
if (nonPositiveNumbers.length == 0) {
let gm = geomMean(arr);
let stdev = getStdev(arr);
return stdev / gm;
} else {
return getStdev(arr) / avg(arr);
}
};

View File

@ -1,27 +0,0 @@
{
"name": "utility-function-extractor",
"version": "0.6.1",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"axios": "^0.21.4",
"d3": "^6.7.0",
"next": "latest",
"path": "^0.12.7",
"react": "^17.0.1",
"react-compound-slider": "^3.3.1",
"react-dom": "^17.0.1",
"react-markdown": "^6.0.2",
"remark-gfm": "^1.0.0"
},
"devDependencies": {
"@netlify/plugin-nextjs": "^4.2.1",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.4",
"tailwindcss": "^2.2.19"
}
}

View File

@ -1,9 +0,0 @@
// import 'tailwindcss/tailwind.css'
import 'tailwindcss/tailwind.css'
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp

View File

@ -1,5 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default function helloAPI(req, res) {
res.status(200).json({ name: 'John Doe' })
}

View File

@ -1,32 +0,0 @@
/* Notes */
// This function is just a simple wrapper around lib/comparisonView.
// Most of the time, I'll want to edit that instead
/* Imports */
import React from "react";
import fs from "fs";
import path from "path";
import ComparisonView from "../lib/comparisonView.js";
/* Definitions */
const elementsDocument = "../data/listOfMoralGoods.json";
/* React components */
export async function getStaticProps() {
const directory = path.join(process.cwd(), "pages");
let listOfElementsForView = JSON.parse(
fs.readFileSync(path.join(directory, elementsDocument), "utf8")
);
return {
props: {
listOfElementsForView,
},
};
}
// Main react component
export default function Home({ listOfElementsForView }) {
return <ComparisonView listOfElementsForView={listOfElementsForView} />;
}

View File

@ -1,31 +0,0 @@
/* Notes */
// This function is just a simple wrapper around lib/comparisonView.
// Most of the time, I'll want to edit that instead
/* Imports */
import React from "react";
import fs from "fs";
import path from "path";
import ComparisonView from "../lib/comparisonView.js";
/* Definitions */
const elementsDocument = "../data/listOfOpenPhil2018AIRiskGrants.json";
/* React components */
export async function getStaticProps() {
const directory = path.join(process.cwd(), "pages");
let listOfElementsForView = JSON.parse(
fs.readFileSync(path.join(directory, elementsDocument), "utf8")
);
return {
props: {
listOfElementsForView,
},
};
}
// Main react component
export default function Home({ listOfElementsForView }) {
return <ComparisonView listOfElementsForView={listOfElementsForView} />;
}

View File

@ -1,29 +0,0 @@
/* Notes */
// This function is just a simple wrapper around lib/comparisonView.
// Most of the time, I'll want to edit that instead
/* Imports */
import React from "react";
import fs from 'fs';
import path from 'path';
import ComparisonView from '../lib/comparisonView.js'
/* Definitions */
const elementsDocument = '../data/listOfResearchOutputs.json'
/* React components */
export async function getStaticProps() {
const directory = path.join(process.cwd(), "pages")
let listOfElementsForView = JSON.parse(fs.readFileSync(path.join(directory, elementsDocument), 'utf8'));
return {
props: {
listOfElementsForView
},
};
}
// Main react component
export default function Home({ listOfElementsForView }) {
return(<ComparisonView listOfElementsForView={listOfElementsForView}/>)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
Copyright 2022 NUÑO SEMPERE
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,114 +0,0 @@
## About
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.
<p align="center">
<img width="50%" height="50%" src="./public/example-prompt.png">
</p>
Then, it cleverly aggregates them, on the one hand by producing a graphical representation:
<p align="center">
<img width="50%" height="50%" src="./public/example-graph.png">
</p>
and on the other hand doing some fast and clever mean aggregation [^1]:
<p align="center">
<img width="50%" height="50%" src="./public/example-table.png">
</p>
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](https://www.squiggle-language.com/) 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".
**If you want to use the utility function extractor for a project, we are happy to add a page for your project, like `utility-function-extractor.quantifieduncertainty.org/your-project`**.
## Built with
- [Nextjs](https://nextjs.org/)
- [Netlify](https://github.com/netlify/netlify-plugin-nextjs/#readme)
- [React](https://reactjs.org/)
- [Squiggle](https://www.squiggle-language.com/)
- [Utility tools](https://github.com/quantified-uncertainty/utility-function-extractor/tree/master/packages/utility-tools)
## Usage
Navigate to [utility-function-extractor.quantifieduncertainty.org/](https://utility-function-extractor.quantifieduncertainty.org/), and start comparing objects.
You can change the list of objects to be compared by clicking on "advanced options".
After comparing objects for a while, you will get a table and a graph with results. You can also use the [utility tools](https://github.com/quantified-uncertainty/utility-function-extractor/tree/master/packages/utility-tools) package to process these results, for which you will need the json of comparisons, which can be found in "Advanced options" -> "Load comparisons"
## Notes
The core structure is json array of objects. Only the "name" attribute is required. If there is a "url", it is displayed nicely.
```
[
{
"name": "Peter Parker",
"someOptionalKey": "...",
"anotherMoreOptionalKey": "...",
},
{
"name": "Spiderman",
"someOptionalKey": "...",
"anotherMoreOptionalKey": "..."
}
]
```
The core structure for links is as follows:
```
[
{
"source": "Peter Parker",
"target": "Spiderman",
"squiggleString": "1 to 100",
"distance": 26.639800977355474
},
{
"source": "Spiderman",
"target": "Jonah Jameson",
"squiggleString": "20 to 2000",
"distance": 6.76997149080232
},
]
```
A previous version of this webpage had a more complicated structure, but it has since been simplified.
## Contributions and help
We welcome PR requests.
## License
Distributed under the MIT License. See LICENSE.txt for more information.
## To do
- [x] Extract merge, findPath and aggregatePath functionality into different repos
- [x] Send to mongo upon completion
- [x] Push to github
- [x] Push to netlify
- [x] Don't allow further comparisons after completion
- [x] Paths table
- [x] Add paths table
- [x] warn that the paths table is approximate.
- I really don't feel like re-adding this after having worked out the distribution rather than the mean aggregation
- On the other hand, I think it does make it more user to other users.
- [x] Change README.
- [ ] Add functionality like names, etc.
- I also don't feel like doing this
- [ ] Look back at Amazon thing which has been running
- [ ] Simplify Graph and DynamicSquiggleChart components
- [ ] Add squiggle component to initial comparison?
- [ ] Understand why the rewrite doesn't
- Maybe: When two elements are judged to be roughly equal
- Maybe: Slightly different merge-sort algorithm.
[^1]: The program takes 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. However, this isn't perfect; the principled approach woud be to aggregate the distributions rather than their means. But this principled approach is much more slowly. For the principled approach, see the `utility-tools` repository.

View File

@ -1,63 +0,0 @@
import React, { useState } from "react";
export function ComparisonActuator({
listOfElements,
pairCurrentlyBeingCompared,
moveToNextStep,
isListOrdered,
}) {
const initialComparisonString = "";
const [comparisonString, setComparisonString] = useState(
initialComparisonString
);
const onChangeComparisonString = async (event) => {
if (!isListOrdered) {
await setComparisonString(event.target.value);
}
};
const onClickSubmitEvent = (event) => {
if (!isListOrdered) {
moveToNextStep({
listOfElements,
pairCurrentlyBeingCompared,
comparisonString,
});
setComparisonString(initialComparisonString);
}
};
return (
<div className="flex m-auto w-72">
<div className="block m-auto text-center">
<br />
<label>
{`... is `}
<br />
<input
disabled={isListOrdered ? true : false}
placeholder={"x to y"}
type="text"
className="text-center text-blueGray-600 bg-white rounded text-lg border-0 shadow outline-none focus:outline-none focus:ring w-8/12 h-10 m-2"
value={comparisonString}
onChange={onChangeComparisonString}
/>
<br />
{`times as valuable as ...`}
</label>
<br />
<button
className={
!true
? "bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
: "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5"
}
onClick={onClickSubmitEvent}
>
Submit
</button>
</div>
</div>
);
}

View File

@ -1,51 +0,0 @@
import React from "react";
let capitalizeFirstLetter = (string) =>
string.charAt(0).toUpperCase() + string.slice(1);
export function DisplayElementForComparison({ element }) {
let otherkeys = Object.keys(element).filter(
(key) =>
key != "name" && key != "url" && key != "id" && key != "isReferenceValue"
);
let othervalues = otherkeys.map((key) => element[key]);
let otherpairs = otherkeys.map((key, i) => ({
key: capitalizeFirstLetter(key),
value: othervalues[i],
}));
if (element.url) {
return (
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
<div className="block m-auto text-center">
<div>
{/*<a href={element.url} target="_blank">*/}
<h2>{`${element.name}`}</h2>
{/*</a>*/}
{otherpairs.map((pair) => (
<p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>
))}
<p>
<a href={element.url} target="_blank">
More info
</a>
</p>
</div>
</div>
</div>
);
} else {
return (
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
<div className="block m-auto text-center">
<div>
<h2>{`${element.name}`}</h2>
{otherpairs.map((pair) => (
<p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>
))}
</div>
</div>
</div>
);
}
}

View File

@ -1,260 +0,0 @@
import React, { useEffect, useState, useRef } from "react";
import colormap from "colormap";
import cytoscape from "cytoscape";
import { DynamicSquiggleChart } from "../dynamicSquiggleChart.js";
import {
resolveToNumIfPossible,
getSquiggleSparkline,
} from "../../lib/squiggleCalculations.js";
import { truncateValueForDisplay } from "../../lib/truncateNums.js";
import { cutOffLongNames } from "../../lib/stringManipulations.js";
// import spread from "cytoscape-spread";
// import dagre from "cytoscape-dagre";
// import cola from "cytoscape-cola";
// import fcose from "cytoscape-fcose";
// import avsdf from "cytoscape-avsdf";
const effectButtonStyle =
"bg-transparent m-2 hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5";
const getEdgeLabel = async (squiggleString) => {
let sparkline = await getSquiggleSparkline(squiggleString);
let num = await resolveToNumIfPossible(squiggleString);
let sparklineConcat = "";
if (false && sparkline.success) {
console.log(sparkline);
sparklineConcat =
sparklineConcat + " →" + sparkline.sparkline.replace("▁▁▁▁▁▁▁▁▁▁▁▁▁", "");
//alert("▁▁▁▁▁▁▁▁▁▁▁");
}
if (num.asNum) {
sparklineConcat =
sparklineConcat + " ⇾ " + truncateValueForDisplay(num.num);
//alert("▁▁▁▁▁▁▁▁▁▁▁");
}
return squiggleString + sparklineConcat;
};
const getColors = (n) => {
let colors;
if (n >= 9) {
colors = colormap({
colormap: "viridis",
nshades: n,
format: "hex",
alpha: 1,
});
} else {
colors = colormap({
colormap: "greys", // other themes: hot, winter, etc.
nshades: n,
format: "hex",
alpha: 1,
});
}
return colors;
};
export function Graph({
listOfElements,
links,
isListOrdered,
listAfterMergeSort,
}) {
const containerRef = useRef("hello-world");
const [visibility, setVisibility] = useState(""); /// useState("invisible");
const [cs, setCs] = useState(null); /// useState("invisible");
const [selectedLink, setSelectedLink] = useState(null);
const [selectedLinkTimeout, setSelectedLinkTimeout] = useState(null);
const callEffect = async ({
listOfElements,
links,
isListOrdered,
listAfterMergeSort,
}) => {
//setVisibility("invisible");
let layoutName = "circle"; //
// cytoscape.use(spread); // necessary for non-default themes,
let listOfElementsForGraph = isListOrdered
? listAfterMergeSort
: listOfElements;
let colors = new Array(listOfElements.length);
if (isListOrdered) {
colors = getColors(listOfElements.length);
}
let nodeElements = listOfElements.map((element, i) => {
return {
data: {
id: cutOffLongNames(element.name),
color: colors[i] || "darkgreen",
labelColor: isListOrdered
? i >= listOfElementsForGraph.length - 2
? "black"
: "white"
: "white",
},
};
});
let linkElements = await Promise.all(
links.map(async (link, i) => {
return {
data: {
id: `link-${i}`,
source: cutOffLongNames(link.source),
target: cutOffLongNames(link.target),
label: await getEdgeLabel(link.squiggleString),
squiggleString: link.squiggleString,
},
};
})
);
const cytoscapeStylesheet = [
{
selector: "node",
style: {
padding: "30px",
shape: "round-rectangle",
content: "data(id)",
"background-color": "data(color)",
"text-wrap": "wrap",
"text-max-width": 70,
"z-index": 1,
},
},
{
selector: "node[id]",
style: {
label: "data(id)",
"font-size": "13",
color: "data(labelColor)",
"text-halign": "center",
"text-valign": "center",
"z-index": 1,
},
},
{
selector: "edge",
style: {
"curve-style": "unbundled-bezier",
"target-arrow-shape": "vee",
width: 1.5,
"target-arrow-color": "green",
"arrow-scale": 3,
"target-arrow-fill": "filled",
"text-rotation": "autorotate",
"z-index": 0,
},
},
{
selector: "edge[label]",
style: {
label: "data(label)",
"font-size": "12",
"text-background-color": "#f9f9f9",
"text-background-opacity": 1,
"text-background-padding": "4px",
"text-border-color": "black",
"text-border-style": "solid",
"text-border-width": 0.5,
"text-border-opacity": 1,
"z-index": 3,
},
},
];
const config = {
container: containerRef.current,
style: cytoscapeStylesheet,
elements: [...nodeElements, ...linkElements],
layout: {
name: layoutName, // circle, grid, dagre
minDist: 10,
//prelayout: false,
// animate: false, // whether to transition the node positions
// animationDuration: 250, // duration of animation in ms if enabled
// the cytoscape documentation is pretty good here.
},
userZoomingEnabled: false,
userPanningEnabled: false,
};
let newCs = cytoscape(config);
setCs(newCs);
// setTimeout(() => setVisibility(""), 700);
// necessary for themes like spread, which have
// a confusing animation at the beginning
};
useEffect(() => {
callEffect({
listOfElements,
links,
isListOrdered,
listAfterMergeSort,
});
}, [listOfElements, links, isListOrdered, listAfterMergeSort, selectedLink]);
useEffect(() => {
if (cs != null) {
clearTimeout(selectedLinkTimeout);
let newTimeout = setTimeout(() => {
cs.edges().on("mouseover", (event) => {
// on("click",
let edge = event.target;
// alert(JSON.stringify(edge.json()));
console.log(JSON.stringify(edge.json()));
setSelectedLink(JSON.parse(JSON.stringify(edge.json())).data);
});
}, 100);
setSelectedLinkTimeout(newTimeout);
}
}, [cs]);
return (
<div className="grid place-items-center">
<div
className={
visibility +
`grid grid-cols-${
selectedLink == null ? "1 " : "2"
} place-items-center place-self-center space-x-0 w-10/12 `
}
>
<div
ref={containerRef}
style={{
height: "900px", // isListOrdered ? "900px" : "500px",
width: "900px", // isListOrdered ? "900px" : "500px",
}}
className=""
/>
<DynamicSquiggleChart
link={selectedLink}
stopShowing={() => setSelectedLink(null)}
/>
</div>
<button
className={effectButtonStyle}
onClick={() =>
callEffect({
listOfElements,
links,
isListOrdered,
listAfterMergeSort,
})
}
>
{"Redraw graph"}
</button>
</div>
);
}

View File

@ -1,171 +0,0 @@
import React, { useState } from "react";
import { mergeSort } from "utility-tools";
import { Title } from "./title.js";
import { ProgressIndicator } from "./progressIndicator.js";
import { DisplayElementForComparison } from "./displayElementForComparison.js";
import { ComparisonActuator } from "./comparisonActuator.js";
import { Separator } from "./separator.js";
import { ResultsTable } from "./resultsTable.js";
import { AdvancedOptions } from "./advancedOptions/advancedOptions.js";
import { Graph } from "./graph/graph.js";
import { pushToMongo } from "../lib/pushToMongo.js";
import { resolveToNumIfPossible } from "../lib/squiggleCalculations.js";
export function Homepage({ listOfElementsInit }) {
const SLICE = false;
/* Statefull elements */
// list of elements
const [listOfElements, setListOfElements] = useState(
SLICE ? listOfElementsInit.slice(0, 4) : listOfElementsInit
);
// number of steps
const numStepsInit = 0;
const [numStepsNow, setNumStepsNow] = useState(numStepsInit);
// is list ordered?
const [isListOrdered, setIsListOrdered] = useState(false);
const [listAfterMergeSort, setListAfterMergeSort] = useState([]);
// list of comparisons
const [links, setLinks] = useState([]);
const addLink = (link, links) => setLinks([...links, link]);
// paired being currently compared
const pairCurrentlyBeingComparedInit = [
listOfElementsInit[0],
listOfElementsInit[1],
];
const [pairCurrentlyBeingCompared, setPairCurrentlyBeingCompared] = useState(
pairCurrentlyBeingComparedInit
);
/* Effects */
// dataset changer
const onChangeOfDataset = (newListOfElements) => {
setListOfElements(newListOfElements);
setLinks([]);
setPairCurrentlyBeingCompared([newListOfElements[0], newListOfElements[1]]);
setNumStepsNow(0);
setIsListOrdered(false);
setListAfterMergeSort([]);
};
// process next step
const mergeSortStep = ({ list, links }) => {
let mergeSortOutput = mergeSort({
list: list,
links: links,
});
setNumStepsNow(numStepsNow + 1);
if (mergeSortOutput.finishedOrderingList == false) {
let newPairToCompare = mergeSortOutput.uncomparedElements;
setIsListOrdered(false);
setPairCurrentlyBeingCompared(newPairToCompare);
} else {
setListAfterMergeSort(mergeSortOutput.orderedList);
pushToMongo({ mergeSortOutput, links });
setIsListOrdered(true); // should be at the end, because some useEffects are triggered by it.
}
};
// Main mergesort step
const moveToNextStep = async ({
listOfElements,
pairCurrentlyBeingCompared,
comparisonString,
whileChangingStuff,
newLinksFromChangingStuff,
}) => {
if (!whileChangingStuff) {
// In the normal course of things:
let newLink = {
source: pairCurrentlyBeingCompared[0].name,
target: pairCurrentlyBeingCompared[1].name,
squiggleString: comparisonString,
};
let numOption = await resolveToNumIfPossible(comparisonString);
if (numOption.asNum == false) {
alert(JSON.stringify(numOption.errorMsg));
} else if (numOption.asNum == true) {
newLink = { ...newLink, distance: numOption.num };
addLink(newLink, links);
let newLinks = [...links, newLink];
console.log("links: ", links);
mergeSortStep({ list: listOfElements, links: newLinks });
}
} else {
// When changing comparisons:
mergeSortStep({
list: listOfElements,
links: newLinksFromChangingStuff,
});
setNumStepsNow(0); // almost no guarantees of how many left.
}
};
return (
<div className="block w-full items-center sm:w-full mt-10">
<Title />
<ProgressIndicator
numStepsNow={numStepsNow}
numElements={listOfElements.length}
/>
{/* Comparisons section */}
<div
className={"grid place-items-center" /*isListOrdered ? "hidden" : ""*/}
>
<div className="grid grid-rows-1 grid-cols-3 place-items-center w-6/11 mt-10">
<DisplayElementForComparison
element={pairCurrentlyBeingCompared[0]}
></DisplayElementForComparison>
<ComparisonActuator
listOfElements={listOfElements}
pairCurrentlyBeingCompared={pairCurrentlyBeingCompared}
moveToNextStep={moveToNextStep}
isListOrdered={isListOrdered}
/>
<DisplayElementForComparison
element={pairCurrentlyBeingCompared[1]}
></DisplayElementForComparison>
</div>
</div>
{/* <Results table /> */}
<ResultsTable
isListOrdered={isListOrdered}
listAfterMergeSort={listAfterMergeSort}
links={links}
/>
{/* <Graph /> */}
<Separator />
<Graph
listOfElements={listOfElements}
links={links}
isListOrdered={isListOrdered}
listAfterMergeSort={listAfterMergeSort}
/>
{/* Advanced options section */}
<Separator />
<AdvancedOptions
links={links}
setLinks={setLinks}
listOfElements={listOfElements}
moveToNextStep={moveToNextStep}
onChangeOfDataset={onChangeOfDataset}
/>
</div>
);
}

View File

@ -1,48 +0,0 @@
import React, { useState } from "react";
function expectedNumMergeSortSteps(n) {
// https://cs.stackexchange.com/questions/82862/expected-number-of-comparisons-in-a-merge-step
// n-2 for each step, so (n-2) + (n-2)/2 + (n-2)/4 + ...
// ~ 2*(n-2) -1 = 2*n - 3
if (n == 0) {
return 0;
} else if (n == 1) {
return 0;
} else if (n == 2) {
return 1;
} else if (n == 3) {
return 2;
} else {
return (
Math.ceil(n ** 2 / (n + 2)) + expectedNumMergeSortSteps(Math.ceil(n / 2))
);
}
}
const firstFewMaxMergeSortSequence = [
0, 0, 1, 3, 5, 8, 11, 14, 17, 21, 25, 29, 33, 37, 41, 45, 49, 54, 59, 64, 69,
74, 79, 84, 89, 94, 99, 104, 109, 114, 119, 124, 129, 135, 141, 147, 153, 159,
165, 171, 177, 183, 189, 195, 201, 207, 213, 219, 225, 231, 237, 243, 249,
255, 261, 267, 273, 279, 285,
];
function maxMergeSortSteps(n) {
if (n < firstFewMaxMergeSortSequence.length) {
return firstFewMaxMergeSortSequence[n];
} else {
return (
maxMergeSortSteps(Math.floor(n / 2)) +
maxMergeSortSteps(Math.ceil(n / 2)) +
n -
1
);
}
}
export function ProgressIndicator({ numStepsNow, numElements }) {
const expectedNumSteps = expectedNumMergeSortSteps(numElements);
const maxSteps = maxMergeSortSteps(numElements);
return (
<p>{`${numStepsNow} out of ~${expectedNumSteps} (max ${maxSteps}) comparisons`}</p>
);
}

View File

@ -1,140 +0,0 @@
import React, { useState, useEffect } from "react";
import { findDistances, aggregatePaths } from "utility-tools";
import { Separator } from "./separator.js";
import { truncateValueForDisplay } from "../lib/truncateNums.js";
import { cutOffLongNames } from "../lib/stringManipulations.js";
import { getCoefficientOfVariation } from "../lib/coefficientOfVariation.js";
async function fullResultsTable({ listAfterMergeSort, links }) {
console.log("listAfterMergeSort", listAfterMergeSort);
console.log(links);
let pathsArray = await findDistances({
orderedList: listAfterMergeSort,
links: links,
});
let aggregatedPaths = await aggregatePaths({
pathsArray: pathsArray,
orderedList: listAfterMergeSort,
aggregationType: "mean",
// VERBOSE: false,
});
return aggregatedPaths;
}
function abridgeArrayAndDisplay(array) {
let newArray;
let formatForDisplay;
if (array.length > 10) {
newArray = array.slice(0, 9);
formatForDisplay = newArray.map((d) => truncateValueForDisplay(d));
formatForDisplay[9] = "...";
} else {
newArray = array;
formatForDisplay = newArray.map((d) => truncateValueForDisplay(d));
}
let result = JSON.stringify(formatForDisplay, null, 2).replaceAll(`"`, "");
return result;
}
function getRow(row, i) {
return (
<tr
className="border-b dark:bg-gray-800 dark:border-gray-700 odd:bg-white even:bg-gray-50 odd:dark:bg-gray-800 even:dark:bg-gray-700"
key={`row-display-${i}`}
>
<td className="px-6 py-4 pt-7">{i}</td>
<td className="px-6 py-4">{cutOffLongNames(row.name)}</td>
<td className="text-center px-6 py-4">
{abridgeArrayAndDisplay(row.arrayMeans)}
</td>
<td className="text-center px-6 py-4">
{truncateValueForDisplay(row.aggregatedMeans)}
</td>
<td className="text-center px-6 py-4">
{truncateValueForDisplay(getCoefficientOfVariation(row.arrayMeans))}
</td>
</tr>
);
}
function reactTableContents(tableContents) {
return tableContents.map((row, i) => getRow(row, i));
}
export function ResultsTable({ isListOrdered, listAfterMergeSort, links }) {
const [isTableComputed, setIsTableComputed] = useState(false);
const [tableContents, setTableContents] = useState([]);
useEffect(() => {
let iAsync = async () => {
if (isListOrdered && listAfterMergeSort.length > 0) {
// both comparisons aren't strictly necessary,
// but it bit me once, so I'm leaving it
let tableContentsResult = await fullResultsTable({
listAfterMergeSort,
links,
});
console.log(tableContentsResult);
setTableContents(tableContentsResult);
setIsTableComputed(true);
}
return () => console.log("cleanup");
};
iAsync();
}, [isListOrdered, listAfterMergeSort, links]);
return !(isListOrdered && isTableComputed) ? (
""
) : (
<div>
<div>
<Separator />
<div className="relative overflow-x-auto shadow-md sm:rounded-lg mt-10">
<table className="w-full text-sm text-left text-gray-800 dark:text-gray-400">
<thead className=" text-xs text-gray-700 bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="px-6 py-3">
Position
</th>
<th scope="col" className="px-6 py-3">
Element
</th>
<th scope="col" className="text-center px-6 py-3">
Possible relative values
</th>
<th scope="col" className="text-center px-6 py-3">
Aggregated Means*
</th>
<th scope="col" className="text-center px-6 py-3">
Coefficient of variation
</th>
</tr>
</thead>
<tbody>{reactTableContents(tableContents)}</tbody>
</table>
</div>
</div>
<div className="grid w-full place-items-center text-center ">
<p className="mt-8 max-w-5xl">
*This is the geometric mean of all means of paths if all elements are
either all positive or all negative, and the arithmetic mean
otherwise. Paths with a non-numeric mean (e.g., resulting from
dividing by a mean of 0) are ignored. For a principled aggregation
which is able to produce meaningfull 90% confidence intervals, see the{" "}
<a
href="https://github.com/quantified-uncertainty/utility-function-extractor/tree/master/packages/utility-tools"
target="_blank"
>
utility-tools package
</a>{" "}
in npm or Github
</p>
</div>
</div>
);
}

View File

@ -1,9 +0,0 @@
import React from "react";
export function Separator() {
return (
<div className="py-4">
<div className="w-full border-t border-4 border-gray-300 mt-10"></div>
</div>
);
}

View File

@ -1,5 +0,0 @@
import React, { useState } from "react";
export function Title() {
return <h1 className="text-6xl font-bold ">Utility Function Extractor</h1>;
}

View File

@ -1,37 +0,0 @@
[
{
"name": "Doubling consumption for one person for one year",
"note": "at fairly low levels of wealth",
"isReferenceValue": true,
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A5:E5"
},
{
"name": "Averting the death of an individual under 5 from malaria",
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A8:T8"
},
{
"name": "Averting the death of an individual 5 or older from malaria",
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A9:T9"
},
{
"name": "Averting the death of a 6- to 59-month-old child",
"note": "through Vitamin A Supplementation",
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A10:T10"
},
{
"name": "Averting the death of an individual under 5 from vaccine-preventable diseases",
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A11:T11"
},
{
"name": "Averting the death of an individual 5-14 years old from vaccine-preventable diseases",
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A12:T12"
},
{
"name": "Averting the death of an individual 15-49 years old from vaccine-preventable diseases",
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A13:T13"
},
{
"name": "Averting the death of an individual 50-74 years old from vaccine-preventable diseases",
"url": "https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801&range=A14:T14"
}
]

View File

@ -1,47 +0,0 @@
[
{
"name": "Michael Cohen and Dmitrii Krasheninnikov — Scholarship Support (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.jnlrsr63yliq",
"amount": "$159k"
},
{
"name": "AI Impacts — General Support (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.6m6tebpouzt1",
"amount": "$100k"
},
{
"name": "Oxford University — Research on the Global Politics of AI",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.c6r2m7i749ay",
"amount": "$429k"
},
{
"name": "Ought — General Support (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.xnzaj48k3fdb",
"amount": "$525k"
},
{
"name": "Machine Intelligence Research Institute — AI Safety Retraining Program",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.h922w7eh5rq6",
"amount": "$150k"
},
{
"name": "UC Berkeley — AI Safety Research (2018)",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.rrsbecbboed8",
"amount": "$1.145M"
},
{
"name": "Open Phil AI Fellowship — 2018 Class",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.p8xd58asz6a2",
"amount": "$1.135M"
},
{
"name": "Wilson Center — AI Policy Seminar Series",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.qiurhycylgi3",
"amount": "$400k"
},
{
"name": "Stanford University — Machine Learning Security Research Led by Dan Boneh and Florian Tramer",
"url": "https://docs.google.com/document/d/1VlN6I4Jauarx-0Fp7AC1ggeQ02AITsN7S56ffAO9NTU/edit#heading=h.ox8adhpgba86",
"amount": "$100k"
}
]

View File

@ -1,63 +0,0 @@
[
{
"name": "A comment on setting up a charity",
"url": "https://forum.effectivealtruism.org/posts/3PjNiLLkCMzAN2BSz/when-setting-up-a-charity-should-you-employ-a-lawyer?commentId=YNKNcp6nKqxqkZgCu"
},
{
"name": "Center for Election Science EA Wiki stub",
"url": "https://forum.effectivealtruism.org/tag/center-for-election-science"
},
{
"name": "Extinguishing or preventing coal seam fires is a potential cause area",
"url": "https://forum.effectivealtruism.org/posts/2nrx8GdtobScoAZF8/extinguishing-or-preventing-coal-seam-fires-is-a-potential"
},
{
"name": "What are some low-information priors that you find practically useful for thinking about the world?",
"url": "https://forum.effectivealtruism.org/posts/SBbwzovWbghLJixPn/what-are-some-low-information-priors-that-you-find"
},
{
"name": "Database of orgs relevant to longtermist/x-risk work",
"url": "https://forum.effectivealtruism.org/posts/twMs8xsgwnYvaowWX/database-of-orgs-relevant-to-longtermist-x-risk-work"
},
{
"name": "Reversals in Psychology",
"url": "https://www.gleech.org/psych"
},
{
"name": "A Model of Patient Spending and Movement Building",
"url": "https://forum.effectivealtruism.org/posts/FXPaccMDPaEZNyyre/a-model-of-patient-spending-and-movement-building"
},
{
"name": "Shallow evaluations of longtermist organizations",
"url": "https://forum.effectivealtruism.org/posts/xmmqDdGqNZq5RELer/shallow-evaluations-of-longtermist-organizations"
},
{
"name": "The motivated reasoning critique of effective altruism",
"url": "https://forum.effectivealtruism.org/posts/pxALB46SEkwNbfiNS/the-motivated-reasoning-critique-of-effective-altruism"
},
{
"name": "Categorizing Variants of Goodhart's Law",
"url": "https://arxiv.org/abs/1803.04585",
"isReferenceValue": true
},
{
"name": "The Vulnerable World Hypothesis",
"url": "https://nickbostrom.com/papers/vulnerable.pdf"
},
{
"name": "The Global Priorities Institute's Research Agenda",
"url": "https://globalprioritiesinstitute.org/research-agenda/"
},
{
"name": "Superintelligence",
"url": "https://en.wikipedia.org/wiki/Superintelligence%3A_Paths%2C_Dangers%2C_Strategies"
},
{
"name": "Thinking Fast and Slow",
"url": "https://en.wikipedia.org/wiki/Thinking%2C_Fast_and_Slow"
},
{
"name": "The Mathematical Theory of Communication",
"url": "https://en.wikipedia.org/wiki/A_Mathematical_Theory_of_Communication"
}
]

View File

@ -1,483 +0,0 @@
[
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 5,
"reasoning": "Seems like both sets of ideas would've happened eventually, my guess is that information theory was more important and counterfactual sped up by more"
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Superintelligence",
"distance": 20,
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Thinking Fast and Slow",
"distance": 3.3333333333333335,
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "Superintelligence",
"distance": "200",
"reasoning": "Yeah yeah I know I'm contradicting myself"
},
{
"source": "The Mathematical Theory of Communication",
"target": "Superintelligence",
"distance": "60",
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Vulnerable World Hypothesis",
"distance": 10,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Shallow evaluations of longtermist organizations",
"distance": "4",
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 2,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "Shallow evaluations of longtermist organizations",
"distance": "4",
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The Vulnerable World Hypothesis",
"distance": 200,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 10,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 5,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 2.5,
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Vulnerable World Hypothesis",
"distance": "10",
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "The Vulnerable World Hypothesis",
"distance": "2",
"reasoning": ""
},
{
"source": "The Vulnerable World Hypothesis",
"target": "The Mathematical Theory of Communication",
"distance": 5,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "A Model of Patient Spending and Movement Building",
"distance": 2.5,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 2.5,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Reversals in Psychology",
"distance": 1.4285714285714286,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": "4",
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": "2",
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 10,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "A comment on setting up a charity",
"distance": "3",
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 2,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": 2,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": 2,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "4",
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "5",
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "3",
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "2",
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "The motivated reasoning critique of effective altruism",
"distance": 5,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "The motivated reasoning critique of effective altruism",
"distance": 1.6666666666666667,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "5",
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 5,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 3.3333333333333335,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "A Model of Patient Spending and Movement Building",
"distance": "8",
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Shallow evaluations of longtermist organizations",
"distance": 5,
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Shallow evaluations of longtermist organizations",
"distance": 2.5,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 1,
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 2,
"reasoning": ""
}
]

View File

@ -1,534 +0,0 @@
[
{
"source": "Thinking Fast and Slow",
"target": "The Global Priorities Institute's Research Agenda",
"distance": "100",
"reasoning": "",
"squiggleString": "100"
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Mathematical Theory of Communication",
"distance": 1000,
"reasoning": "",
"squiggleString": 1000
},
{
"source": "Superintelligence",
"target": "The Mathematical Theory of Communication",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Vulnerable World Hypothesis",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The motivated reasoning critique of effective altruism",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 100,
"reasoning": "",
"squiggleString": 100
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Thinking Fast and Slow",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "Thinking Fast and Slow",
"target": "The motivated reasoning critique of effective altruism",
"distance": 1,
"reasoning": "",
"squiggleString": 1
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 1000,
"reasoning": "",
"squiggleString": 1000
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 100,
"reasoning": "",
"squiggleString": 100
},
{
"source": "The Vulnerable World Hypothesis",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "Reversals in Psychology",
"target": "A Model of Patient Spending and Movement Building",
"distance": 10,
"reasoning": "RiP: Cleaning up 10,000 people's brains a bit.\nMPS: far more important topic",
"squiggleString": 10
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "5",
"reasoning": "\nDatabase just saves a bit of time, maybe 100 counterfactual applications",
"squiggleString": "5"
},
{
"source": "Reversals in Psychology",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 1,
"reasoning": "",
"squiggleString": 1
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "A Model of Patient Spending and Movement Building",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "A Model of Patient Spending and Movement Building",
"distance": 2,
"reasoning": "",
"squiggleString": 2
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 1000,
"reasoning": "",
"squiggleString": 1000
},
{
"source": "A comment on setting up a charity",
"target": "Center for Election Science EA Wiki stub",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "A comment on setting up a charity",
"target": "Reversals in Psychology",
"distance": 200,
"reasoning": "",
"squiggleString": 200
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Reversals in Psychology",
"distance": 20,
"reasoning": "",
"squiggleString": 20
},
{
"source": "Reversals in Psychology",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "50",
"reasoning": "",
"squiggleString": "50"
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "50",
"reasoning": "",
"squiggleString": "50"
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "10",
"reasoning": "",
"squiggleString": "10"
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 1,
"reasoning": "",
"squiggleString": 1
},
{
"source": "A comment on setting up a charity",
"target": "Shallow evaluations of longtermist organizations",
"distance": 1000,
"reasoning": "",
"squiggleString": 1000
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": "",
"squiggleString": 100
},
{
"source": "Reversals in Psychology",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": "",
"squiggleString": 100
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": "",
"squiggleString": 100
},
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 99999.99999999999,
"reasoning": "",
"squiggleString": 99999.99999999999
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": "",
"squiggleString": 100
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "A Model of Patient Spending and Movement Building",
"distance": 1,
"reasoning": "",
"squiggleString": 1
},
{
"source": "Thinking Fast and Slow",
"target": "A Model of Patient Spending and Movement Building",
"distance": "1000",
"reasoning": "",
"squiggleString": "1000"
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "A Model of Patient Spending and Movement Building",
"distance": "5",
"reasoning": "",
"squiggleString": "5"
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 10,
"reasoning": "",
"squiggleString": 10
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 10000,
"reasoning": "",
"squiggleString": 10000
},
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 99999.99999999999,
"reasoning": "",
"squiggleString": 99999.99999999999
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Superintelligence",
"distance": 100,
"reasoning": "",
"squiggleString": 100
}
]

View File

@ -1,372 +0,0 @@
[
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Superintelligence",
"distance": 100,
"reasoning": "GPI: good stuff but v v hard questions read by ~200.\nSuperintelligence: Maybe 50,000 copies? associated interview tour transformed the field."
},
{
"source": "Thinking Fast and Slow",
"target": "The Global Priorities Institute's Research Agenda",
"distance": "100",
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Mathematical Theory of Communication",
"distance": 1000,
"reasoning": ""
},
{
"source": "Superintelligence",
"target": "The Mathematical Theory of Communication",
"distance": 10,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Vulnerable World Hypothesis",
"distance": 10,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The motivated reasoning critique of effective altruism",
"distance": 10,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 100,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 10,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Thinking Fast and Slow",
"distance": 10,
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "The motivated reasoning critique of effective altruism",
"distance": 1,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 1000,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 100,
"reasoning": ""
},
{
"source": "The Vulnerable World Hypothesis",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 10,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "A Model of Patient Spending and Movement Building",
"distance": 10,
"reasoning": "RiP: Cleaning up 10,000 people's brains a bit.\nMPS: far more important topic"
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "5",
"reasoning": "\nDatabase just saves a bit of time, maybe 100 counterfactual applications"
},
{
"source": "Reversals in Psychology",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 1,
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "A Model of Patient Spending and Movement Building",
"distance": 10,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "A Model of Patient Spending and Movement Building",
"distance": 2,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 1000,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Center for Election Science EA Wiki stub",
"distance": 10,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Reversals in Psychology",
"distance": 200,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Reversals in Psychology",
"distance": 20,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "50",
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "50",
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "10",
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 1,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Shallow evaluations of longtermist organizations",
"distance": 1000,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 99999.99999999999,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "A Model of Patient Spending and Movement Building",
"distance": 1,
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "A Model of Patient Spending and Movement Building",
"distance": "1000",
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "A Model of Patient Spending and Movement Building",
"distance": "5",
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 10,
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 10000,
"reasoning": ""
}
]

View File

@ -1,224 +0,0 @@
[
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 1000,
"reasoning": "Jaime Sevilla\nThinking Fast and Slow is a recounting of the evidence about cogsci at the time, and large parts are already outdated.\nTMToC is an enduring piece of theory that kickstarted a new field "
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Superintelligence",
"distance": 20,
"reasoning": "Jaime Sevilla\nI am unsure about the quality difference, but Superintelligence has had a far wider reach"
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Thinking Fast and Slow",
"distance": 20,
"reasoning": "Thinking Fast and Slow has had wider reach, and is a good synthesis of the field."
},
{
"source": "Thinking Fast and Slow",
"target": "Superintelligence",
"distance": "1.1",
"reasoning": "Jaime Sevilla\nSuperintelligence gave prominence to the AI Safety field, possibly bringing forward research timelines a few years.\nThinking Fast and Slow made CogSci available to many people.\nLarge parts of both books are now outdated"
},
{
"source": "Superintelligence",
"target": "The Mathematical Theory of Communication",
"distance": 1000,
"reasoning": "Jaime Sevilla\nTMToC has stood the test of time"
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Vulnerable World Hypothesis",
"distance": 33.333333333333336,
"reasoning": "TVWH has had wider reach"
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Shallow evaluations of longtermist organizations",
"distance": "2",
"reasoning": "Shallow evaluations contains more object level information"
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 100,
"reasoning": "Goodhart contains more insight"
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 20,
"reasoning": "Goodhart contains more insights"
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 100,
"reasoning": "GPIRA has presumably helped at least GPI set its agenda, and possibly other newcomers to the field.\nThe motivated reasoning critique might have helped some EAs by reiterating a core message"
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 12.5,
"reasoning": "GPIRA helped GPI set their priorities and decompose the problem, shallow evaluations is an experiment on institution evaluation which might result in more work later (I feel like I am not getting at the true reason for my scoring here)"
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 1.1111111111111112,
"reasoning": "Research agendas can mobilize more talent, they can be a multiplier.\nBut Goodhearts law is tangible progress on a problem.\nOverall Im confused"
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Vulnerable World Hypothesis",
"distance": "10",
"reasoning": "vulnerable world had wider reach, and inspired more people"
},
{
"source": "The Vulnerable World Hypothesis",
"target": "Thinking Fast and Slow",
"distance": 5,
"reasoning": "Thinking fast and slow reached more people"
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Reversals in Psychology",
"distance": "10",
"reasoning": "I have heard more discussion of reversals than of AMPSMB"
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 10,
"reasoning": "I learned a couple of things in the low-information priors post but I think curating databases is very very helpful"
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "A Model of Patient Spending and Movement Building",
"distance": 1.25,
"reasoning": "I personally learned more from low information priors, but I havent engaged with patient spending enough to evaluate its value"
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "A Model of Patient Spending and Movement Building",
"distance": 1.1111111111111112,
"reasoning": "I think its slighly more likely I will build on top of the patient spending than on top of the database"
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 100,
"reasoning": "Coal article seems more in-depth reasoning "
},
{
"source": "A comment on setting up a charity",
"target": "Center for Election Science EA Wiki stub",
"distance": 10,
"reasoning": "I imagine the wiki stub will reach more people"
},
{
"source": "A comment on setting up a charity",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": 25,
"reasoning": "I learned more from low info priors"
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": 12.5,
"reasoning": "Learned more from low info priors"
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "1.5",
"reasoning": "I learned more from low info priors but I expect I would learn more if I engaged with coal seam fires"
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "1.5",
"reasoning": "Database seems more reemplazable"
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "A Model of Patient Spending and Movement Building",
"distance": 1.1111111111111112,
"reasoning": "I have no idea of which one would be more useful to me if I engaged with them\nI guess patient spending is more related to my work"
},
{
"source": "A comment on setting up a charity",
"target": "The motivated reasoning critique of effective altruism",
"distance": 100,
"reasoning": "The motivated reasoning critique is better at setting a good culture"
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "The motivated reasoning critique of effective altruism",
"distance": 12.5,
"reasoning": "The motivated reasoning critique is better at setting a good culture"
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "1.1",
"reasoning": "I learned more from priors, critique is better at setting a culture"
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Shallow evaluations of longtermist organizations",
"distance": 10,
"reasoning": "Shallow evaluations has more object level content"
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Shallow evaluations of longtermist organizations",
"distance": 1.1111111111111112,
"reasoning": "Shallow evaluations contains more crystallized reasoning"
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "1.8",
"reasoning": "I expect I would learn more from coal seam if I engaged with it"
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 12.5,
"reasoning": "Goodhart is more hard-to-replace progress "
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 3.3333333333333335,
"reasoning": "Goodheart feels like more hard-to-replace progress"
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "Reversals in Psychology",
"distance": "2",
"reasoning": "reversals has had more reach"
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Reversals in Psychology",
"distance": "3",
"reasoning": "reversals has had more reach"
},
{
"source": "The Vulnerable World Hypothesis",
"target": "Reversals in Psychology",
"distance": "1.5",
"reasoning": "Reversals has had more reach"
},
{
"source": "Reversals in Psychology",
"target": "Thinking Fast and Slow",
"distance": 1.4285714285714286,
"reasoning": "Oof Im stumped.\nI think thinking fast and slow is enough of a good crystallization of knowledge I am giving it the nod, even though reversals in psychology might have a better insight compression rate"
}
]

View File

@ -1,351 +0,0 @@
[
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 5,
"reasoning": "This is by Linch."
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Superintelligence",
"distance": 100,
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Thinking Fast and Slow",
"distance": 10,
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "Superintelligence",
"distance": "10",
"reasoning": ""
},
{
"source": "The Mathematical Theory of Communication",
"target": "Superintelligence",
"distance": "50",
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Vulnerable World Hypothesis",
"distance": 10,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Shallow evaluations of longtermist organizations",
"distance": "5",
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 100,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 20,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 50,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 10,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 2,
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Vulnerable World Hypothesis",
"distance": "5",
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "The Vulnerable World Hypothesis",
"distance": "3",
"reasoning": ""
},
{
"source": "The Mathematical Theory of Communication",
"target": "The Vulnerable World Hypothesis",
"distance": 1,
"reasoning": ""
},
{
"source": "The Vulnerable World Hypothesis",
"target": "Superintelligence",
"distance": 10,
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Reversals in Psychology",
"distance": 1,
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "2",
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "A Model of Patient Spending and Movement Building",
"distance": 1.3333333333333333,
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "1.5",
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "1.5",
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 5,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "A comment on setting up a charity",
"distance": 1,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 5,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 100,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 100,
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 20,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "The motivated reasoning critique of effective altruism",
"distance": 14.285714285714285,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "The motivated reasoning critique of effective altruism",
"distance": 16.666666666666668,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": "2",
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Shallow evaluations of longtermist organizations",
"distance": 2.5,
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Shallow evaluations of longtermist organizations",
"distance": 3.3333333333333335,
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Shallow evaluations of longtermist organizations",
"distance": 5,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "Shallow evaluations of longtermist organizations",
"distance": 10,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Shallow evaluations of longtermist organizations",
"distance": 5,
"reasoning": ""
}
]

View File

@ -1,399 +0,0 @@
[
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 10000,
"reasoning": "Information theory is fundamental. Thinking Fast and Slow is somewhat wrong and not as important in a grand scheme of things. It offered some meta cognitive skills but... They don't seem that valuable 5+y later."
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Superintelligence",
"distance": 20,
"reasoning": "Misha Yagudin\n\nHard choice. Mostly intuition about how many times AI is more important and relative difference in how foundational it have been.\n\n\n\n"
},
{
"source": "Thinking Fast and Slow",
"target": "The Global Priorities Institute's Research Agenda",
"distance": "100",
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Mathematical Theory of Communication",
"distance": 10,
"reasoning": "Or something like that. "
},
{
"source": "Superintelligence",
"target": "The Mathematical Theory of Communication",
"distance": 2,
"reasoning": "Misha\n\nI know I am incoherent...\n\nBut SI is less fundamental but still important"
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Vulnerable World Hypothesis",
"distance": 33.333333333333336,
"reasoning": "VWH is the best argument against liberty. GL is good paper but clearly less important. "
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The motivated reasoning critique of effective altruism",
"distance": 10,
"reasoning": "Misha \n\nI think the later might be more influential via CEA community health team. But low chances.\n\nAs a research direction the first is more important. But it feels inconsequential."
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 10,
"reasoning": "AI stuff is more important; AI stuff gives more general mental models"
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 5,
"reasoning": "Or something. AI is more important and more generalizable but community meta is still fairly important. \n\nI think meta will target worse thinkers on average hence difference."
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Thinking Fast and Slow",
"distance": 66.66666666666667,
"reasoning": "It's a bit hard. I am fairly dismissive of TFaS but it's a book and some ideas are good."
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Thinking Fast and Slow",
"distance": 25,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "Thinking Fast and Slow",
"distance": 2,
"reasoning": ""
},
{
"source": "Thinking Fast and Slow",
"target": "The Vulnerable World Hypothesis",
"distance": "15",
"reasoning": "Clearly more important for the world saving."
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Vulnerable World Hypothesis",
"distance": "2",
"reasoning": "Hard call. VWH feels more urgent than GPI RA. But I tried to disentangle agenda as a piece from its role as a necessary tool for field building. I sorta think that VWH agenda would have been x10+ more valuable per its more immediate focus and applicability to policy."
},
{
"source": "The Vulnerable World Hypothesis",
"target": "Superintelligence",
"distance": 10,
"reasoning": "SI is field building, deeper and about AI."
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Reversals in Psychology",
"distance": "3",
"reasoning": "I sorta think that knowing that some psychology is totally fabricated &c is useful for not relying on it in your reasoning about the world and some of these were fairly fundamental. Also another update about quality of social sciences.\n\nI think some updates are clearly x10+ more important but value of categorising them is not as much.\n\nI am not sure how valuable are econ models, tbh."
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 100,
"reasoning": "Dunno nothing new to me in the priors question but Pablo's comment which is fairly trivial and I haven't used/thought about it since.\n"
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "A Model of Patient Spending and Movement Building",
"distance": 500,
"reasoning": "Sorta even worse"
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "A Model of Patient Spending and Movement Building",
"distance": 3.3333333333333335,
"reasoning": "not sure; the later seems more consequential in the future"
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 10,
"reasoning": "No idea how good the later is but Wiki is not particularly insightful. I think think tags for orgs are obv less useful than tags for cause areas. "
},
{
"source": "A comment on setting up a charity",
"target": "Center for Election Science EA Wiki stub",
"distance": 100,
"reasoning": "idk man seems like a random comment might be consequential but let's not count it as research"
},
{
"source": "A comment on setting up a charity",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": 100,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Center for Election Science EA Wiki stub",
"distance": 1,
"reasoning": "I like the later more but both are just lists which turned out not to be of much use to me. I think others will enjoy priors more."
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 10,
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 2.5,
"reasoning": "I think lists are cool. But maybe we would have it anyway via tags and maybe fires are actually good.\n\n"
},
{
"source": "A comment on setting up a charity",
"target": "Shallow evaluations of longtermist organizations",
"distance": 10000,
"reasoning": "idk"
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Shallow evaluations of longtermist organizations",
"distance": 100,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Shallow evaluations of longtermist organizations",
"distance": 200,
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Shallow evaluations of longtermist organizations",
"distance": 10,
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Shallow evaluations of longtermist organizations",
"distance": 10,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "A Model of Patient Spending and Movement Building",
"distance": "2",
"reasoning": "hard call"
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "The motivated reasoning critique of effective altruism",
"distance": 3.3333333333333335,
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "The motivated reasoning critique of effective altruism",
"distance": 1.4285714285714286,
"reasoning": ""
}
]

View File

@ -1,351 +0,0 @@
[
{
"source": "Thinking Fast and Slow",
"target": "The Mathematical Theory of Communication",
"distance": 5,
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Superintelligence",
"distance": 3.3333333333333335,
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Thinking Fast and Slow",
"distance": 100,
"reasoning": ""
},
{
"source": "Superintelligence",
"target": "Thinking Fast and Slow",
"distance": 2.5,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Vulnerable World Hypothesis",
"distance": 33.333333333333336,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Shallow evaluations of longtermist organizations",
"distance": "3",
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The motivated reasoning critique of effective altruism",
"distance": 1,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "The Vulnerable World Hypothesis",
"distance": 100,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The Vulnerable World Hypothesis",
"distance": 16.666666666666668,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 20,
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 20,
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "The Global Priorities Institute's Research Agenda",
"distance": 20,
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "The Vulnerable World Hypothesis",
"distance": "5",
"reasoning": ""
},
{
"source": "The Vulnerable World Hypothesis",
"target": "Superintelligence",
"distance": 16.666666666666668,
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Reversals in Psychology",
"distance": "10",
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "What are some low-information priors that you find practically useful for thinking about the world?",
"distance": "1",
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "A Model of Patient Spending and Movement Building",
"distance": 20,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "A Model of Patient Spending and Movement Building",
"distance": 20,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Extinguishing or preventing coal seam fires is a potential cause area",
"distance": 2,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Center for Election Science EA Wiki stub",
"distance": 5,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 25,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 3.3333333333333335,
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Database of orgs relevant to longtermist/x-risk work",
"distance": 2,
"reasoning": ""
},
{
"source": "A comment on setting up a charity",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 500,
"reasoning": ""
},
{
"source": "Center for Election Science EA Wiki stub",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 142.85714285714286,
"reasoning": ""
},
{
"source": "Extinguishing or preventing coal seam fires is a potential cause area",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 166.66666666666666,
"reasoning": ""
},
{
"source": "Database of orgs relevant to longtermist/x-risk work",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 16.666666666666668,
"reasoning": ""
},
{
"source": "What are some low-information priors that you find practically useful for thinking about the world?",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 14.285714285714285,
"reasoning": ""
},
{
"source": "A Model of Patient Spending and Movement Building",
"target": "Categorizing Variants of Goodhart's Law",
"distance": 2.5,
"reasoning": ""
},
{
"source": "Categorizing Variants of Goodhart's Law",
"target": "Reversals in Psychology",
"distance": "10",
"reasoning": ""
},
{
"source": "The motivated reasoning critique of effective altruism",
"target": "Reversals in Psychology",
"distance": "20",
"reasoning": ""
},
{
"source": "Shallow evaluations of longtermist organizations",
"target": "Reversals in Psychology",
"distance": "70",
"reasoning": ""
},
{
"source": "The Global Priorities Institute's Research Agenda",
"target": "Reversals in Psychology",
"distance": "30",
"reasoning": ""
},
{
"source": "The Vulnerable World Hypothesis",
"target": "Reversals in Psychology",
"distance": "1",
"reasoning": ""
},
{
"source": "Reversals in Psychology",
"target": "Superintelligence",
"distance": 3.3333333333333335,
"reasoning": ""
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

View File

@ -1,33 +0,0 @@
const sum = (arr) => arr.reduce((a, b) => a + b, 0);
function getStdev(arr) {
if (Array.isArray(arr) && arr.length > 0) {
const n = arr.length;
const mean = arr.reduce((a, b) => a + b) / n;
return Math.sqrt(
arr.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n
);
} else {
return 0;
}
}
export const avg = (arr) => sum(arr) / arr.length;
export const geomMean = (arr) => {
let n = arr.length;
let logavg = sum(arr.map((x) => Math.log(x))); // works for low numbers much better, numerically
let result = Math.exp(logavg / n);
return result;
};
export const getCoefficientOfVariation = (arr) => {
let nonPositiveNumbers = arr.filter((x) => x <= 0);
if (nonPositiveNumbers.length == 0) {
let gm = geomMean(arr);
let stdev = getStdev(arr);
return stdev / gm;
} else {
return getStdev(arr) / avg(arr);
}
};

View File

@ -1,5 +0,0 @@
[[plugins]]
package = "@netlify/plugin-nextjs"
[build]
publish = ".next"

View File

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More