From d5821c9cb9a950779ad2a7279c952b240bf4a33a Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Mon, 16 Jun 2025 14:34:24 +0200 Subject: [PATCH] fix error in static merge algorithm. progress with merging of dictionary-operations --- lib/structures/dict.js | 2 +- lib/structures/dict.types.js | 2 +- lib/versioning/static/merge.js | 34 ++++---- snippets/versioning.js | 148 +++++++++++++++++++++------------ 4 files changed, 115 insertions(+), 71 deletions(-) diff --git a/lib/structures/dict.js b/lib/structures/dict.js index 53a7456..3dfb483 100644 --- a/lib/structures/dict.js +++ b/lib/structures/dict.js @@ -15,7 +15,7 @@ export const emptyDict = compareFn => RBTreeWrapper.new((x, y) => compareFn(x)(y export const has = dict => key => dict.tree.get(key) !== undefined; export const get = dict => key => dict.tree.get(key); -export const set = dict => key => value => new RBTreeWrapper(dict.tree.remove(key).insert(key, value), inspectDict); +export const set = key => value => dict => new RBTreeWrapper(dict.tree.remove(key).insert(key, value), inspectDict); export const remove = dict => key => new RBTreeWrapper(dict.tree.remove(key), inspectDict); export const length = dict => dict.tree.length; diff --git a/lib/structures/dict.types.js b/lib/structures/dict.types.js index 6e3302c..8cf2b1a 100644 --- a/lib/structures/dict.types.js +++ b/lib/structures/dict.types.js @@ -15,7 +15,7 @@ const mkType = makeTypeParser({ export const ModuleDict = [ ["emptyDict", newDynamic(emptyDict)(mkType("(a -> a -> Ordering) -> (a => b) "))], ["has" , newDynamic(has )(mkType("(a => b) -> a -> Bool "))], - ["set" , newDynamic(set )(mkType("(a => b) -> a -> b -> (a => b) "))], + ["set" , newDynamic(set )(mkType("a -> b -> (a => b) -> (a => b) "))], ["remove" , newDynamic(remove )(mkType("(a => b) -> a -> (a => b) "))], ["length" , newDynamic(length )(mkType("(a => b) -> Int "))], ["fold" , newDynamic(fold )(mkType("(c -> a -> b -> c) -> c -> (a => b) -> c "))], diff --git a/lib/versioning/static/merge.js b/lib/versioning/static/merge.js index 1243f7b..e375e32 100644 --- a/lib/versioning/static/merge.js +++ b/lib/versioning/static/merge.js @@ -1,22 +1,23 @@ import { emptySet, add, length, forEach, has, remove } from "../../structures/set.js"; import { getDepth, Slot } from "./value_slot.js"; -import { compareSlot } from "../compare.js"; +import { compareSlot } from "./compare.js"; import { makeTypeParser } from "../../parser/type_parser.js"; import { newDynamic } from "../../primitives/dynamic.js"; -const emptySetOfSlots = emptySet(compareSlot); +const emptySetOfSlots = compareElems => emptySet(compareSlot(compareElems)); -export const findLCA = slotA => slotB => { - if (compareSlot(slotA)(slotB) === 0) { +export const findLCA = compareElems => slotA => slotB => { + console.log('compareSlot...', slotA, slotB); + if (compareSlot(compareElems)(slotA)(slotB) === 0) { return slotA; } if (getDepth(slotA) > getDepth(slotB)) { // we can assume that slotA.variant === "write" - return findLCA(slotA.value.slot)(slotB); + return findLCA(compareElems)(slotA.value.slot)(slotB); } else { // we can assume that slotB.variant === "write" - return findLCA(slotA)(slotB.value.slot); + return findLCA(compareElems)(slotA)(slotB.value.slot); } }; @@ -24,26 +25,27 @@ export const findLCA = slotA => slotB => { // {slotA} if slotA is younger // {slotB} if slotB is younger // {slotA, slotB} if they are concurrent (conflicting) -export const merge = slotA => slotB => { - const lca = findLCA(slotA)(slotB); - if (compareSlot(lca)(slotA) === 0) { - return add(emptySetOfSlots)(slotB); +export const merge = compareElems => slotA => slotB => { + const lca = findLCA(compareElems)(slotA)(slotB); + const emptySet = emptySetOfSlots(compareElems); + if (compareSlot(compareElems)(lca)(slotA) === 0) { + return add(emptySet)(slotB); } - if (compareSlot(lca)(slotB) === 0) { - return add(emptySetOfSlots)(slotA); + if (compareSlot(compareElems)(lca)(slotB) === 0) { + return add(emptySet)(slotA); } - const setWithA = add(emptySetOfSlots)(slotA); + const setWithA = add(emptySet)(slotA); const setWithAandB = add(setWithA)(slotB); return setWithAandB; }; -export const mergeN = slots => { +export const mergeN = compareElems => slots => { let result = slots; forEach(slots)(slotA => { forEach(slots)(slotB => { // compare all non-identical pairs - if (compareSlot(slotA)(slotB) !== 0) { - const m = merge(slotA)(slotB); + if (compareSlot(compareElems)(slotA)(slotB) !== 0) { + const m = merge(compareElems)(slotA)(slotB); if (length(m) === 1) { // if in the pair, one is an ancestor of the other, // only keep the other diff --git a/snippets/versioning.js b/snippets/versioning.js index e95ba55..5f8a20b 100644 --- a/snippets/versioning.js +++ b/snippets/versioning.js @@ -2,87 +2,129 @@ import { newDynamic } from "../lib/primitives/dynamic.js"; import { Char, Int } from "../lib/primitives/primitive_types.js"; import { fnType } from "../lib/structures/type_constructors.types.js"; import { pretty } from "../lib/util/pretty.js"; -import { newLiteral, newSlot, read, transform, write } from "../lib/versioning/value_slot.js"; -import { merge, mergeN } from "../lib/versioning/merge.js"; +import { newLiteral, newSlot, read, transform, write } from "../lib/versioning/static/value_slot.js"; +import { merge, mergeN } from "../lib/versioning/static/merge.js"; import { union } from "../lib/structures/set.js"; +import { emptyDict, set } from "../lib/structures/dict.js"; +import { compareInts, compareStrings } from "../lib/compare/primitives.js"; +import { compareDicts } from "../lib/compare/structures.js"; const inc = x => x + 1n; const incLiteral = newLiteral(newDynamic(inc)(fnType(_=>Int)(_=>Int))); -console.log("##############"); -console.log("## Counting ##"); -console.log("##############"); +// { +// console.log("##############"); +// console.log("## Counting ##"); +// console.log("##############"); -const counterOneSlot = write - (newSlot("1d61577e704613f4e48b164852aedd20")) - (newLiteral(newDynamic(1n)(Int))); +// const counterOneSlot = write +// (newSlot("1d61577e704613f4e48b164852aedd20")) +// (newLiteral(newDynamic(1n)(Int))); -console.log(pretty({counterOneSlot})); +// console.log(pretty({counterOneSlot})); -const valueOne = read(counterOneSlot); +// const valueOne = read(counterOneSlot); -console.log(pretty({valueOne})); +// console.log(pretty({valueOne})); -const onePlusOne = transform - (valueOne) - (incLiteral); +// const onePlusOne = transform +// (valueOne) +// (incLiteral); -console.log(pretty({onePlusOne})); +// console.log(pretty({onePlusOne})); -const onePlusOnePlusOne = transform - (onePlusOne) - (incLiteral); +// const onePlusOnePlusOne = transform +// (onePlusOne) +// (incLiteral); -console.log(pretty({onePlusOnePlusOne})); +// console.log(pretty({onePlusOnePlusOne})); +// } + +// // console.log("#############"); +// // console.log("## Summing ##"); +// // console.log("#############"); + +// // const priceSlot = newSlot(Symbol('price'))(newLiteral(20.66)); +// // const taxSlot = newSlot(Symbol('tax'))(newLiteral(4.34)); + +// // const total = +// // transform(read(priceSlot))( +// // transform(read(taxSlot))( +// // newLiteral(tax => price => price + tax))); + +// // console.log(pretty({total})) + +// // const totalPlusOne = transform(total)(newLiteral(inc)); + +// // console.log(pretty({totalPlusOne})); + +// // verifyValue(totalPlusOne); + +// // console.log("getReadDependencies(totalPlusOne):", getReadDependencies(totalPlusOne)); +// { +// console.log("###############"); +// console.log("## Branching ##"); +// console.log("###############"); -// console.log("#############"); -// console.log("## Summing ##"); -// console.log("#############"); +// const initialSlot = newSlot("Slot__4a029b3d758bcd1fffbf495531c95537"); -// const priceSlot = newSlot(Symbol('price'))(newLiteral(20.66)); -// const taxSlot = newSlot(Symbol('tax'))(newLiteral(4.34)); +// const slotA = write(initialSlot)(newLiteral(newDynamic("a")(Char))); +// const slotB = write(slotA )(newLiteral(newDynamic("b")(Char))); +// const slotC = write(initialSlot)(newLiteral(newDynamic("c")(Char))); -// const total = -// transform(read(priceSlot))( -// transform(read(taxSlot))( -// newLiteral(tax => price => price + tax))); +// const slotAB = merge(slotA)(slotB); +// const slotAC = merge(slotA)(slotC); +// const slotBC = merge(slotB)(slotC); -// console.log(pretty({total})) +// console.log({slotAB, slotAC, slotBC}); -// const totalPlusOne = transform(total)(newLiteral(inc)); +// const un = union(slotAC)(slotBC); -// console.log(pretty({totalPlusOne})); +// const merged = mergeN(un); -// verifyValue(totalPlusOne); +// console.log("merged:", merged); +// } -// console.log("getReadDependencies(totalPlusOne):", getReadDependencies(totalPlusOne)); +{ + console.log("#################"); + console.log("## Dict insert ##"); + console.log("#################"); + const dictSlot = write + (newSlot("MyDictSlot__d2e87499d9cf46b5c86d420c2057f52f")) + (newLiteral(emptyDict(compareStrings))); + const insertedX = write(dictSlot) + (transform + (read(dictSlot)) // input + (transform // fn (set "x" => 1n) + (newLiteral(1n)) + (transform + (newLiteral("x")) + (newLiteral(set)) + ))); + const insertedY = write(dictSlot) + (transform + (read(dictSlot)) // input + (transform // fn (set "y" => 2n) + (newLiteral(2n)) + (transform + (newLiteral("y")) + (newLiteral(set)) + ))); -console.log("###############"); -console.log("## Branching ##"); -console.log("###############"); + const merged = merge + (compareDicts(compareStrings)(compareInts)) + (insertedX) + (insertedY); -const initialSlot = newSlot("Slot__4a029b3d758bcd1fffbf495531c95537"); - -const slotA = write(initialSlot)(newLiteral(newDynamic("a")(Char))); -const slotB = write(slotA )(newLiteral(newDynamic("b")(Char))); -const slotC = write(initialSlot)(newLiteral(newDynamic("c")(Char))); - -const slotAB = merge(slotA)(slotB); -const slotAC = merge(slotA)(slotC); -const slotBC = merge(slotB)(slotC); - -console.log({slotAB, slotAC, slotBC}); - -const un = union(slotAC)(slotBC); - -const merged = mergeN(un); - -console.log("merged:", merged); + // is a conflict, but shouldn't be one... + // can we add the 'domain knowledge' that the composition of two non-key-overlapping dict.set-operations is commutative? + console.log({merged}); +} // // console.log(compareSlots(intCompare)(fiveSlot)(fiveSlot)); // // console.log(compareSlots(intCompare)(sixSlot)(sixSlot));