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:
parent
ec50da23f1
commit
bd5bdb9cd0
583
lib/\
Normal file
583
lib/\
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
|
@ -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>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in New Issue
Block a user