fix: Pander to human biases.

The expected number of steps is less than the
true number half the time. This confuses users.

Also some formatting.
This commit is contained in:
NunoSempere 2022-01-30 10:26:05 -05:00
parent ec50da23f1
commit bd5bdb9cd0
4 changed files with 879 additions and 187 deletions

583
lib/\ Normal file
View File

@ -0,0 +1,583 @@
/* Imports */
import Head from "next/head";
import React, { useState } from "react";
import { DrawGraph, removeOldSvg } from "./labeledGraph";
import { SubmitSliderButton } from "./slider";
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 = () => 1; // 1/Math.random() - 1
/* Misc. helpers */
let buildLinks = (quantitativeComparisons) =>
quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({
source: element1,
target: element2,
distance: distance,
reasoning: reasoning,
}));
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]) => ({
source: listOfElements[element1].name,
target: listOfElements[element2].name,
distance: distance,
reasoning: reasoning,
}));
// 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 initialSliderValue = 1;
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 = expectedNumMergeSortSteps(
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 [sliderValue, setSliderValue] = useState(initialSliderValue);
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],
]);
setSliderValue(initialSliderValue);
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(expectedNumMergeSortSteps(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 } = 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);
throw new Error("Comparisons include unknown elements, please retry");
}
quantitativeComparisons2.push([element1, element2, distance, reasoning]);
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 }) {
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 nextStepSlider = async ({
posList,
binaryComparisons,
sliderValue,
reasoning,
element1,
element2,
}) => {
if (!dontPushSubmitButtonAnyMore) {
if (sliderValue < 1 && sliderValue > 0) {
sliderValue = 1 / sliderValue;
[element1, element2] = [element2, element1];
}
console.log(`posList@nextStepSlider:`);
console.log(posList);
let [successStatus, result] = nextStepSimple(
posList,
binaryComparisons,
element1,
element2
);
let newQuantitativeComparison = [
element1,
element2,
sliderValue,
reasoning,
];
let newQuantitativeComparisons = [
...quantitativeComparisons,
newQuantitativeComparison,
];
setQuantitativeComparisons(newQuantitativeComparisons);
setSliderValue(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 slider) */}
<div className="flex m-auto w-72">
<div className="block m-auto text-center">
<br />
<label>
{`... is `}
<br />
<input
type="number"
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={sliderValue}
onChange={(event) => {
//console.log(event)
//console.log(event.target.value)
setSliderValue(event.target.value);
}}
/>
<br />
{`times as valuable as ...`}
</label>
<br />
<SubmitSliderButton
posList={posList}
binaryComparisons={binaryComparisons}
sliderValue={sliderValue}
reasoning={reasoning}
toComparePair={toComparePair}
nextStepSlider={nextStepSlider}
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="">
Reasoning (optional):
<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"
value={reasoning}
onChange={(event) => setReasoning(event.target.value)}
/>
</label>
<br />
<div></div>
{/* Old slider element (previous actuator)
<div className={`flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4 mt-10 ${isListOrdered ? "hidden" : ""}`}>
<SliderElement
className="flex items-center justify-center"
onChange={(event) => (setSliderValue(event[0]))}
value={sliderValue}
displayFunction={displayFunctionSlider}
domain={domain}
/>
</div>
*/}
</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,21 +1,33 @@
/* Imports */ /* Imports */
import Head from 'next/head' import Head from "next/head";
import React, { useState } from "react"; import React, { useState } from "react";
import { DrawGraph, removeOldSvg } from './labeledGraph'; import { DrawGraph, removeOldSvg } from "./labeledGraph";
import { SubmitSliderButton } from "./slider"; import { SubmitSliderButton } from "./slider";
import { DisplayElement } from './displayElement' import { DisplayElement } from "./displayElement";
import { DisplayAsMarkdown } from './displayAsMarkdown' import { DisplayAsMarkdown } from "./displayAsMarkdown";
import { CreateTable, buildRows } from './findPaths' import { CreateTable, buildRows } from "./findPaths";
import { DataSetChanger } from "./datasetChanger" import { DataSetChanger } from "./datasetChanger";
import { ComparisonsChanger } from "./comparisonsChanger" import { ComparisonsChanger } from "./comparisonsChanger";
import { pushToMongo } from "./pushToMongo.js" import { pushToMongo } from "./pushToMongo.js";
import { increasingList, maxMergeSortSteps, expectedNumMergeSortSteps, sleep } from "./utils.js" import {
increasingList,
maxMergeSortSteps,
expectedNumMergeSortSteps,
conservativeNumMergeSortSteps,
} from "./utils.js";
/* DEFINTIONS */ /* DEFINTIONS */
const DEFAULT_COMPARE = () => 1 // 1/Math.random() - 1 const DEFAULT_COMPARE = () => 1; // 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 */ /* Misc. helpers */
let buildLinks = quantitativeComparisons => quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({ source: element1, target: element2, distance: distance, reasoning: reasoning })) let buildLinks = (quantitativeComparisons) =>
quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({
source: element1,
target: element2,
distance: distance,
reasoning: reasoning,
}));
Array.prototype.containsArray = function (val) { Array.prototype.containsArray = function (val) {
var hash = {}; var hash = {};
@ -23,148 +35,200 @@ Array.prototype.containsArray = function (val) {
hash[this[i]] = i; hash[this[i]] = i;
} }
return hash.hasOwnProperty(val); return hash.hasOwnProperty(val);
} };
let checkIfListIsOrdered = (arr, binaryComparisons) => { let checkIfListIsOrdered = (arr, binaryComparisons) => {
let l = arr.length let l = arr.length;
let isOrdered = true let isOrdered = true;
for (let i = 0; i < l - 1; i++) { for (let i = 0; i < l - 1; i++) {
isOrdered = isOrdered && binaryComparisons.containsArray([arr[i], arr[i + 1]]) isOrdered =
} isOrdered && binaryComparisons.containsArray([arr[i], arr[i + 1]]);
return isOrdered
} }
return isOrdered;
};
let nicelyFormatLinks = (quantitativeComparisons, listOfElements) => quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({ source: listOfElements[element1].name, target: listOfElements[element2].name, distance: distance, reasoning: reasoning })) let nicelyFormatLinks = (quantitativeComparisons, listOfElements) =>
quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({
source: listOfElements[element1].name,
target: listOfElements[element2].name,
distance: distance,
reasoning: reasoning,
}));
// Main react component // Main react component
export default function ComparisonView({ listOfElementsForView }) { export default function ComparisonView({ listOfElementsForView }) {
/* State */ /* State */
// initial state values // initial state values
let initialListOfElements = listOfElementsForView.map((element, i) => ({ ...element, id: i })) let initialListOfElements = listOfElementsForView.map((element, i) => ({
let initialPosList = increasingList(listOfElementsForView.length) // [0,1,2,3,4] ...element,
let initialComparePair = [initialPosList[initialPosList.length - 2], initialPosList[initialPosList.length - 1]] id: i,
let initialSliderValue = 1 }));
let initialReasoning = '' let initialPosList = increasingList(listOfElementsForView.length); // [0,1,2,3,4]
let initialBinaryComparisons = [] let initialComparePair = [
let initialQuantitativeComparisons = [] initialPosList[initialPosList.length - 2],
let initialIsListOdered = false initialPosList[initialPosList.length - 1],
let initialOrderedList = [] ];
let initialShowAdvancedOptions = false let initialSliderValue = 1;
let initialShowComparisons = false let initialReasoning = "";
let initialShowLoadComparisons = false let initialBinaryComparisons = [];
let initialShowChangeDataSet = false let initialQuantitativeComparisons = [];
let initialIsListOdered = false;
let initialOrderedList = [];
let initialShowAdvancedOptions = false;
let initialShowComparisons = false;
let initialShowLoadComparisons = false;
let initialShowChangeDataSet = false;
let initialNumSteps = 0; let initialNumSteps = 0;
let initialMaxSteps = maxMergeSortSteps(listOfElementsForView.length) let initialMaxSteps = maxMergeSortSteps(listOfElementsForView.length);
let initialExpectedSteps = expectedNumMergeSortSteps(listOfElementsForView.length) let initialExpectedSteps = estimatedMergeSortSteps(
let initialTableRows = [] listOfElementsForView.length
let initialDontPushSubmitButtonAnyMore = false );
let initialTableRows = [];
let initialDontPushSubmitButtonAnyMore = false;
// state variables and functions // state variables and functions
const [listOfElements, setListOfElements] = useState(initialListOfElements) const [listOfElements, setListOfElements] = useState(initialListOfElements);
const [posList, setPosList] = useState(initialPosList) const [posList, setPosList] = useState(initialPosList);
const [toComparePair, setToComparePair] = useState(initialComparePair) const [toComparePair, setToComparePair] = useState(initialComparePair);
const [sliderValue, setSliderValue] = useState(initialSliderValue) const [sliderValue, setSliderValue] = useState(initialSliderValue);
const [reasoning, setReasoning] = useState(initialReasoning) const [reasoning, setReasoning] = useState(initialReasoning);
const [binaryComparisons, setBinaryComparisons] = useState(initialBinaryComparisons) const [binaryComparisons, setBinaryComparisons] = useState(
const [quantitativeComparisons, setQuantitativeComparisons] = useState(initialQuantitativeComparisons) // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons. 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 [isListOrdered, setIsListOrdered] = useState(initialIsListOdered);
const [orderedList, setOrderedList] = useState(initialOrderedList) const [orderedList, setOrderedList] = useState(initialOrderedList);
const [dontPushSubmitButtonAnyMore, setDontPushSubmitButtonAnyMore] = useState(initialDontPushSubmitButtonAnyMore) const [dontPushSubmitButtonAnyMore, setDontPushSubmitButtonAnyMore] =
useState(initialDontPushSubmitButtonAnyMore);
let [showAdvancedOptions, changeShowAdvanceOptions] = useState(initialShowAdvancedOptions); let [showAdvancedOptions, changeShowAdvanceOptions] = useState(
let [showComparisons, changeShowComparisons] = useState(initialShowComparisons); initialShowAdvancedOptions
let [showLoadComparisons, changeShowLoadComparisons] = useState(initialShowLoadComparisons); );
let [showChangeDataSet, changeshowChangeDataSet] = useState(initialShowChangeDataSet); let [showComparisons, changeShowComparisons] = useState(
initialShowComparisons
);
let [showLoadComparisons, changeShowLoadComparisons] = useState(
initialShowLoadComparisons
);
let [showChangeDataSet, changeshowChangeDataSet] = useState(
initialShowChangeDataSet
);
let [numSteps, changeNumSteps] = useState(initialNumSteps); let [numSteps, changeNumSteps] = useState(initialNumSteps);
let [maxSteps, changeMaxSteps] = useState(initialMaxSteps) let [maxSteps, changeMaxSteps] = useState(initialMaxSteps);
let [expectedSteps, changeExpectedSteps] = useState(initialExpectedSteps) let [expectedSteps, changeExpectedSteps] = useState(initialExpectedSteps);
let [tableRows, setTableRows] = useState(initialTableRows) let [tableRows, setTableRows] = useState(initialTableRows);
/* Convenience utils: restart + changeDataSet */ /* Convenience utils: restart + changeDataSet */
let restart = (posList, initialBinaryComparisons2, initialQuantitativeComparisons2) => {//({posList, initialBinaryComparisons2, initialQuantitativeComparisons2}) => { let restart = (
setToComparePair([posList[posList.length - 2], posList[posList.length - 1]]) posList,
setSliderValue(initialSliderValue) initialBinaryComparisons2,
setBinaryComparisons(initialBinaryComparisons2 || initialBinaryComparisons) initialQuantitativeComparisons2
setQuantitativeComparisons(initialQuantitativeComparisons2 || initialQuantitativeComparisons) ) => {
setIsListOrdered(initialIsListOdered) //({posList, initialBinaryComparisons2, initialQuantitativeComparisons2}) => {
setOrderedList(initialOrderedList) setToComparePair([
changeNumSteps(initialNumSteps) posList[posList.length - 2],
removeOldSvg() posList[posList.length - 1],
setTableRows(initialTableRows) ]);
setDontPushSubmitButtonAnyMore(initialDontPushSubmitButtonAnyMore) setSliderValue(initialSliderValue);
} setBinaryComparisons(initialBinaryComparisons2 || initialBinaryComparisons);
setQuantitativeComparisons(
initialQuantitativeComparisons2 || initialQuantitativeComparisons
);
setIsListOrdered(initialIsListOdered);
setOrderedList(initialOrderedList);
changeNumSteps(initialNumSteps);
removeOldSvg();
setTableRows(initialTableRows);
setDontPushSubmitButtonAnyMore(initialDontPushSubmitButtonAnyMore);
};
let changeDataSet = (listOfElementsNew) => { let changeDataSet = (listOfElementsNew) => {
listOfElementsNew = listOfElementsNew = listOfElementsNew.map((element, i) => ({
listOfElementsNew.map((element, i) => ({ ...element, id: i })) ...element,
let newPosList = increasingList(listOfElementsNew.length) id: i,
let newListLength = listOfElementsNew.length }));
let newPosList = increasingList(listOfElementsNew.length);
let newListLength = listOfElementsNew.length;
setListOfElements(listOfElementsNew) setListOfElements(listOfElementsNew);
setPosList(increasingList(listOfElementsNew.length)) setPosList(increasingList(listOfElementsNew.length));
setToComparePair([newPosList[newPosList.length - 2], newPosList[newPosList.length - 1]]) setToComparePair([
newPosList[newPosList.length - 2],
newPosList[newPosList.length - 1],
]);
changeExpectedSteps(expectedNumMergeSortSteps(newListLength)) changeExpectedSteps(estimatedMergeSortSteps(newListLength));
changeMaxSteps(maxMergeSortSteps(newListLength)) changeMaxSteps(maxMergeSortSteps(newListLength));
restart(newPosList) restart(newPosList);
// restart({posList: newPosList}) // restart({posList: newPosList})
} };
let changeComparisons = async (links) => { let changeComparisons = async (links) => {
let quantitativeComparisons2 = [] let quantitativeComparisons2 = [];
let binaryComparisons2 = [] let binaryComparisons2 = [];
links.shift() links.shift();
for (let link of links) { for (let link of links) {
let { source, target, distance, reasoning } = link let { source, target, distance, reasoning } = link;
let searchByName = (name, candidate) => candidate.name == name let searchByName = (name, candidate) => candidate.name == name;
let testForSource = (candidate) => searchByName(source, candidate) let testForSource = (candidate) => searchByName(source, candidate);
let testForTarget = (candidate) => searchByName(target, candidate) let testForTarget = (candidate) => searchByName(target, candidate);
let element1 = listOfElements.findIndex(testForSource) let element1 = listOfElements.findIndex(testForSource);
let element2 = listOfElements.findIndex(testForTarget) let element2 = listOfElements.findIndex(testForTarget);
if (element1 == -1 || element2 == -1) { if (element1 == -1 || element2 == -1) {
console.log("link", link) console.log("link", link);
console.log(source) console.log(source);
console.log(target) console.log(target);
throw new Error("Comparisons include unknown elements, please retry") throw new Error("Comparisons include unknown elements, please retry");
} }
quantitativeComparisons2.push([element1, element2, distance, reasoning]) quantitativeComparisons2.push([element1, element2, distance, reasoning]);
binaryComparisons2.push([element1, element2]) binaryComparisons2.push([element1, element2]);
} }
// return ({quantitativeComparisons: quantitativeComparisons2, binaryComparisons: binaryComparisons2}) // return ({quantitativeComparisons: quantitativeComparisons2, binaryComparisons: binaryComparisons2})
//restart({posList, initialBinaryComparisons2=initialBinaryComparisons, initialQuantitativeComparisons2=initialQuantitativeComparisons}) //restart({posList, initialBinaryComparisons2=initialBinaryComparisons, initialQuantitativeComparisons2=initialQuantitativeComparisons})
// restart(posList, binaryComparisons2, quantitativeComparisons2) // restart(posList, binaryComparisons2, quantitativeComparisons2)
setQuantitativeComparisons(quantitativeComparisons2) setQuantitativeComparisons(quantitativeComparisons2);
setBinaryComparisons(binaryComparisons2) setBinaryComparisons(binaryComparisons2);
} };
// Manipulations // Manipulations
let compareTwoElements = (newBinaryComparisons, element1, element2) => { let compareTwoElements = (newBinaryComparisons, element1, element2) => {
let element1Greater = newBinaryComparisons.containsArray([element1, element2]) let element1Greater = newBinaryComparisons.containsArray([
let element2Greater = newBinaryComparisons.containsArray([element2, element1]) element1,
element2,
]);
let element2Greater = newBinaryComparisons.containsArray([
element2,
element1,
]);
if (element1Greater || element2Greater) { if (element1Greater || element2Greater) {
return element1Greater && !element2Greater return element1Greater && !element2Greater;
} else { } else {
setToComparePair([element1, element2]) setToComparePair([element1, element2]);
//console.log(`No comparison found between ${element1} and ${element2}`) //console.log(`No comparison found between ${element1} and ${element2}`)
//console.log(`Comparisons:`) //console.log(`Comparisons:`)
//console.log(JSON.stringify(newBinaryComparisons, null, 4)); //console.log(JSON.stringify(newBinaryComparisons, null, 4));
return "No comparison found" return "No comparison found";
}
} }
};
function merge(newBinaryComparisons, left, right) { function merge(newBinaryComparisons, left, right) {
let sortedArr = []; // the sorted elements will go here let sortedArr = []; // the sorted elements will go here
while (left.length && right.length) { while (left.length && right.length) {
// insert the biggest element to the sortedArr // insert the biggest element to the sortedArr
let comparison = compareTwoElements(newBinaryComparisons, left[0], right[0]) let comparison = compareTwoElements(
newBinaryComparisons,
left[0],
right[0]
);
if (comparison == "No comparison found") { if (comparison == "No comparison found") {
return "No comparison found; unable to proceed" return "No comparison found; unable to proceed";
} } else if (comparison) {
else if (comparison) { // left[0] > right[0] // left[0] > right[0]
sortedArr.push(left.shift()); sortedArr.push(left.shift());
} else { } else {
sortedArr.push(right.shift()); sortedArr.push(right.shift());
@ -177,7 +241,7 @@ export default function ComparisonView({ listOfElementsForView }) {
function mergeSort({ array, comparisons }) { function mergeSort({ array, comparisons }) {
if (array == "No comparison found; unable to proceed") { if (array == "No comparison found; unable to proceed") {
return "No comparison found; unable to proceed" return "No comparison found; unable to proceed";
} }
const half = array.length / 2; const half = array.length / 2;
@ -187,70 +251,103 @@ export default function ComparisonView({ listOfElementsForView }) {
} }
const left = array.slice(0, half); // the first half of the 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. const right = array.slice(half, array.length); // Note that splice is destructive.
let orderedFirstHalf = mergeSort({ array: left, comparisons }) let orderedFirstHalf = mergeSort({ array: left, comparisons });
let orderedSecondHalf = mergeSort({ array: right, comparisons }) let orderedSecondHalf = mergeSort({ array: right, comparisons });
if (orderedFirstHalf != "No comparison found; unable to proceed" && orderedSecondHalf != "No comparison found; unable to proceed") { if (
orderedFirstHalf != "No comparison found; unable to proceed" &&
orderedSecondHalf != "No comparison found; unable to proceed"
) {
let result = merge(comparisons, orderedFirstHalf, orderedSecondHalf); let result = merge(comparisons, orderedFirstHalf, orderedSecondHalf);
return result return result;
} else { } else {
return "No comparison found; unable to proceed" return "No comparison found; unable to proceed";
} }
} }
let nextStepSimple = (posList, binaryComparisons, element1, element2) => { let nextStepSimple = (posList, binaryComparisons, element1, element2) => {
//console.log("Binary comparisons: ") //console.log("Binary comparisons: ")
//console.log(JSON.stringify(binaryComparisons, null, 4)); //console.log(JSON.stringify(binaryComparisons, null, 4));
let newComparison = [element1, element2] // [element1, element2] let newComparison = [element1, element2]; // [element1, element2]
let newBinaryComparisons = [...binaryComparisons, newComparison] let newBinaryComparisons = [...binaryComparisons, newComparison];
//console.log("New binaryComparisons: ") //console.log("New binaryComparisons: ")
//console.log(JSON.stringify(newBinaryComparisons, null, 4)); //console.log(JSON.stringify(newBinaryComparisons, null, 4));
setBinaryComparisons(newBinaryComparisons) setBinaryComparisons(newBinaryComparisons);
let result = mergeSort({ array: posList, comparisons: newBinaryComparisons }) let result = mergeSort({
array: posList,
comparisons: newBinaryComparisons,
});
//console.log(result) //console.log(result)
if (result != "No comparison found; unable to proceed" && checkIfListIsOrdered(result, newBinaryComparisons)) { if (
result != "No comparison found; unable to proceed" &&
checkIfListIsOrdered(result, newBinaryComparisons)
) {
// console.log(`isListOrdered: ${isListOrdered}`) // console.log(`isListOrdered: ${isListOrdered}`)
console.log("poslist@nextStepSimple") console.log("poslist@nextStepSimple");
console.log(posList) console.log(posList);
console.log("result@nextStepSimple") console.log("result@nextStepSimple");
console.log(result) console.log(result);
return [true, result] return [true, result];
} else { } else {
return [false, result] return [false, result];
}
} }
};
let nextStepSlider = async ({ posList, binaryComparisons, sliderValue, reasoning, element1, element2 }) => { let nextStepSlider = async ({
posList,
binaryComparisons,
sliderValue,
reasoning,
element1,
element2,
}) => {
if (!dontPushSubmitButtonAnyMore) { if (!dontPushSubmitButtonAnyMore) {
if (sliderValue < 1 && sliderValue > 0) { if (sliderValue < 1 && sliderValue > 0) {
sliderValue = 1 / sliderValue; sliderValue = 1 / sliderValue;
[element1, element2] = [element2, element1] [element1, element2] = [element2, element1];
} }
console.log(`posList@nextStepSlider:`) console.log(`posList@nextStepSlider:`);
console.log(posList) console.log(posList);
let [successStatus, result] = nextStepSimple(posList, binaryComparisons, element1, element2) let [successStatus, result] = nextStepSimple(
posList,
binaryComparisons,
element1,
element2
);
let newQuantitativeComparison = [element1, element2, sliderValue, reasoning] let newQuantitativeComparison = [
let newQuantitativeComparisons = [...quantitativeComparisons, newQuantitativeComparison] element1,
setQuantitativeComparisons(newQuantitativeComparisons) element2,
sliderValue,
reasoning,
];
let newQuantitativeComparisons = [
...quantitativeComparisons,
newQuantitativeComparison,
];
setQuantitativeComparisons(newQuantitativeComparisons);
setSliderValue(DEFAULT_COMPARE()) setSliderValue(DEFAULT_COMPARE());
setReasoning('') setReasoning("");
changeNumSteps(numSteps + 1) changeNumSteps(numSteps + 1);
if (successStatus) { if (successStatus) {
setDontPushSubmitButtonAnyMore(true) setDontPushSubmitButtonAnyMore(true);
let jsObject = nicelyFormatLinks(quantitativeComparisons, listOfElements) let jsObject = nicelyFormatLinks(
await pushToMongo(jsObject) quantitativeComparisons,
console.log(jsObject) listOfElements
);
await pushToMongo(jsObject);
console.log(jsObject);
alert("Comparisons completed. Background work might take a while, or straight-out fail") alert(
setIsListOrdered(true) "Comparisons completed. Background work might take a while, or straight-out fail"
setOrderedList(result) );
setIsListOrdered(true);
setOrderedList(result);
await buildRows({ await buildRows({
isListOrdered: true, isListOrdered: true,
@ -258,8 +355,8 @@ export default function ComparisonView({ listOfElementsForView }) {
listOfElements, listOfElements,
links: buildLinks(newQuantitativeComparisons), links: buildLinks(newQuantitativeComparisons),
rows: tableRows, rows: tableRows,
setTableRows setTableRows,
}) });
/* /*
setTimeout(async () => { setTimeout(async () => {
// Make sure to do this after the // Make sure to do this after the
@ -268,13 +365,11 @@ export default function ComparisonView({ listOfElementsForView }) {
*/ */
} }
} }
};
}
// Html // Html
return ( return (
<div className="flex flex-col items-center justify-center min-h-screen py-2"> <div className="flex flex-col items-center justify-center min-h-screen py-2">
{/* Webpage name & favicon */} {/* Webpage name & favicon */}
<div className="mt-20"> <div className="mt-20">
<Head> <Head>
@ -283,11 +378,8 @@ export default function ComparisonView({ listOfElementsForView }) {
</Head> </Head>
</div> </div>
<main className="flex flex-col items-center w-full flex-1 px-20 text-center"> <main className="flex flex-col items-center w-full flex-1 px-20 text-center">
{/* Heading */} {/* Heading */}
<h1 className="text-6xl font-bold"> <h1 className="text-6xl font-bold">Utility Function Extractor</h1>
Utility Function Extractor
</h1>
{/* Approximate progress indicator */} {/* Approximate progress indicator */}
<p>{`${numSteps} out of ~${expectedSteps} (max ${maxSteps}) comparisons`}</p> <p>{`${numSteps} out of ~${expectedSteps} (max ${maxSteps}) comparisons`}</p>
@ -295,12 +387,12 @@ export default function ComparisonView({ listOfElementsForView }) {
{/* Comparison section */} {/* Comparison section */}
<div className={isListOrdered ? "hidden" : ""}> <div className={isListOrdered ? "hidden" : ""}>
<div className="flex flex-wrap items-center max-w-4xl sm:w-full mt-10"> <div className="flex flex-wrap items-center max-w-4xl sm:w-full mt-10">
{/* Element 1 */} {/* Element 1 */}
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5"> <div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
<div className="block m-auto text-center"> <div className="block m-auto text-center">
<DisplayElement element={listOfElements[toComparePair[0]]}> <DisplayElement
</DisplayElement> element={listOfElements[toComparePair[0]]}
></DisplayElement>
</div> </div>
</div> </div>
@ -318,7 +410,7 @@ export default function ComparisonView({ listOfElementsForView }) {
onChange={(event) => { onChange={(event) => {
//console.log(event) //console.log(event)
//console.log(event.target.value) //console.log(event.target.value)
setSliderValue(event.target.value) setSliderValue(event.target.value);
}} }}
/> />
<br /> <br />
@ -341,8 +433,9 @@ export default function ComparisonView({ listOfElementsForView }) {
{/* Element 2 */} {/* Element 2 */}
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5"> <div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
<div className="block m-auto text-center"> <div className="block m-auto text-center">
<DisplayElement element={listOfElements[toComparePair[1]]}> <DisplayElement
</DisplayElement> element={listOfElements[toComparePair[1]]}
></DisplayElement>
</div> </div>
</div> </div>
</div> </div>
@ -350,14 +443,14 @@ export default function ComparisonView({ listOfElementsForView }) {
<label className=""> <label className="">
Reasoning (optional): Reasoning (optional):
<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" <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"
value={reasoning} value={reasoning}
onChange={(event) => setReasoning(event.target.value)} onChange={(event) => setReasoning(event.target.value)}
/> />
</label> </label>
<br /> <br />
<div> <div></div>
</div>
{/* Old slider element (previous actuator) {/* Old slider element (previous actuator)
<div className={`flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4 mt-10 ${isListOrdered ? "hidden" : ""}`}> <div className={`flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4 mt-10 ${isListOrdered ? "hidden" : ""}`}>
@ -380,8 +473,8 @@ export default function ComparisonView({ listOfElementsForView }) {
isListOrdered={isListOrdered} isListOrdered={isListOrdered}
orderedList={orderedList} orderedList={orderedList}
listOfElements={listOfElements} listOfElements={listOfElements}
links={buildLinks(quantitativeComparisons)}> links={buildLinks(quantitativeComparisons)}
</DrawGraph> ></DrawGraph>
</div> </div>
{/* Comparison table */} {/* Comparison table */}
@ -393,8 +486,7 @@ export default function ComparisonView({ listOfElementsForView }) {
links={buildLinks(quantitativeComparisons)} links={buildLinks(quantitativeComparisons)}
tableRows={tableRows} tableRows={tableRows}
setTableRows={setTableRows} setTableRows={setTableRows}
> ></CreateTable>
</CreateTable>
</div> </div>
</div> </div>
@ -408,12 +500,19 @@ export default function ComparisonView({ listOfElementsForView }) {
</button> </button>
</div> </div>
<div className={showAdvancedOptions ? "flex flex-wrap -mx-4 overflow-hidden" : "hidden"}> <div
className={
showAdvancedOptions
? "flex flex-wrap -mx-4 overflow-hidden"
: "hidden"
}
>
{/* Button: Restart */} {/* Button: Restart */}
<div className="my-4 px-4 w-1/4 overflow-hidden"> <div className="my-4 px-4 w-1/4 overflow-hidden">
<button <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" 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)}
>
{/* onClick={() => restart({posList})}> */} {/* onClick={() => restart({posList})}> */}
Restart Restart
</button> </button>
@ -422,7 +521,8 @@ export default function ComparisonView({ listOfElementsForView }) {
<div className="my-4 px-4 w-1/4 overflow-hidden"> <div className="my-4 px-4 w-1/4 overflow-hidden">
<button <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" 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)}> onClick={() => changeShowComparisons(!showComparisons)}
>
Show comparisons Show comparisons
</button> </button>
</div> </div>
@ -430,7 +530,8 @@ export default function ComparisonView({ listOfElementsForView }) {
<div className="my-4 px-4 w-1/4 overflow-hidden"> <div className="my-4 px-4 w-1/4 overflow-hidden">
<button <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" 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)}> onClick={() => changeShowLoadComparisons(!showLoadComparisons)}
>
Load comparisons Load comparisons
</button> </button>
</div> </div>
@ -438,7 +539,8 @@ export default function ComparisonView({ listOfElementsForView }) {
<div className="my-4 px-4 w-1/4 overflow-hidden"> <div className="my-4 px-4 w-1/4 overflow-hidden">
<button <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" 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)}> onClick={() => changeshowChangeDataSet(!showChangeDataSet)}
>
Use your own data Use your own data
</button> </button>
</div> </div>
@ -453,28 +555,30 @@ export default function ComparisonView({ listOfElementsForView }) {
<div className="text-left"> <div className="text-left">
<DisplayAsMarkdown <DisplayAsMarkdown
markdowntext={` markdowntext={`
${""/* ${
"" /*
## Comparisons ## Comparisons
### Binary comparisons ### Binary comparisons
${JSON.stringify(binaryComparisons, null, 4)} ${JSON.stringify(binaryComparisons, null, 4)}
*/} */
}
### Numerical comparisons ### Numerical comparisons
${JSON.stringify(nicelyFormatLinks(quantitativeComparisons, listOfElements), null, 4)} ${JSON.stringify(
nicelyFormatLinks(quantitativeComparisons, listOfElements),
null,
4
)}
`} `}
className={""}
className={""}> ></DisplayAsMarkdown>
</DisplayAsMarkdown>
</div> </div>
</div> </div>
{/* Load comparisons section */} {/* Load comparisons section */}
<div className={showLoadComparisons ? "inline mt-5" : "hidden"}> <div className={showLoadComparisons ? "inline mt-5" : "hidden"}>
<ComparisonsChanger <ComparisonsChanger handleSubmit={changeComparisons} />
handleSubmit={changeComparisons}
/>
{/*<ComparisonsChanger handleSubmit={changeComparisons} />*/} {/*<ComparisonsChanger handleSubmit={changeComparisons} />*/}
</div> </div>
</main> </main>
</div> </div>
) );
} }

View File

@ -7,6 +7,8 @@ import {
formatLargeOrSmall, formatLargeOrSmall,
} from "./utils.js"; } from "./utils.js";
const displayWidthPercentage = 0.85; // 0.7
let getlength = (number) => number.toString().length; let getlength = (number) => number.toString().length;
export function removeOldSvg() { export function removeOldSvg() {
@ -28,7 +30,8 @@ function drawGraphInner({ nodes, links }) {
let initialWindowWidth = window.innerWidth; let initialWindowWidth = window.innerWidth;
let margin = { top: 0, right: 10, bottom: 30, left: 10 }; let margin = { top: 0, right: 10, bottom: 30, left: 10 };
let width = initialWindowWidth * 0.8 - margin.left - margin.right; let width =
initialWindowWidth * displayWidthPercentage - margin.left - margin.right;
var x = d3.scalePoint().range([0, width]).domain(nodeids); var x = d3.scalePoint().range([0, width]).domain(nodeids);
@ -168,4 +171,3 @@ export function DrawGraph({
</div> </div>
); );
} }

View File

@ -102,6 +102,9 @@ export const geomMean = (arr) => {
return result; return result;
}; };
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 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()); export const increasingList = (n) => Array.from(Array(n).keys());