From 12357eb50480ead8e7076c406a8db6c65b62ffb3 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 7 Dec 2023 11:43:27 +0000 Subject: [PATCH 1/8] Update directory --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 4a94809560a1..86161e5241bf 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -528,7 +528,7 @@ * [InfixToPostfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java) * [LargestRectangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/LargestRectangle.java) * [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MaximumMinimumWindow.java) - * [NextGraterElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextGraterElement.java) + * [NextGreaterElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextGreaterElement.java) * [NextSmallerElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java) * [PostfixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java) * [StackPostfixNotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java) From a2453fd5c2a149bd1216166d33c95aa4bf34053b Mon Sep 17 00:00:00 2001 From: itakurah <122729995+itakurah@users.noreply.github.com> Date: Thu, 7 Dec 2023 13:38:49 +0100 Subject: [PATCH 2/8] refactor --- .../datastructures/crdt/GSetTest.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java b/src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java index 99588259006f..74250ede1f23 100644 --- a/src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java +++ b/src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java @@ -32,20 +32,14 @@ void testLookup() { void testCompare() { GSet gSet1 = new GSet<>(); GSet gSet2 = new GSet<>(); - gSet1.addElement("apple"); gSet1.addElement("orange"); - gSet2.addElement("orange"); - gSet2.addElement("banana"); - assertFalse(gSet1.compare(gSet2)); - - GSet gSet3 = new GSet<>(); - gSet3.addElement("apple"); - gSet3.addElement("orange"); - - assertTrue(gSet1.compare(gSet3)); + gSet2.addElement("apple"); + assertTrue(gSet1.compare(gSet2)); + gSet2.addElement("banana"); + assertTrue(gSet1.compare(gSet2)); } @Test From e7fa3e223f4806f9b1dc1168ff4ba908f2f69a05 Mon Sep 17 00:00:00 2001 From: itakurah <122729995+itakurah@users.noreply.github.com> Date: Thu, 7 Dec 2023 13:40:32 +0100 Subject: [PATCH 3/8] =?UTF-8?q?fixed=20compare()=20method=20to=20(S.A=20?= =?UTF-8?q?=E2=8A=86=20T.A)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/thealgorithms/datastructures/crdt/GSet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java index 37873adc2573..2b8959ed0136 100644 --- a/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java +++ b/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java @@ -50,7 +50,7 @@ public boolean lookup(T e) { * @return true if the current G-Set is a subset of the other, false otherwise */ public boolean compare(GSet other) { - return elements.containsAll(other.elements); + return other.elements.containsAll(elements); } /** From c0895701040f336acb65cf4aa469dbbe9dc269ec Mon Sep 17 00:00:00 2001 From: itakurah <122729995+itakurah@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:33:53 +0100 Subject: [PATCH 4/8] added tests for LWWElementSet --- .../crdt/LWWElementSetTest.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java diff --git a/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java new file mode 100644 index 000000000000..c55d921d7874 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java @@ -0,0 +1,106 @@ +package com.thealgorithms.datastructures.crdt; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class LWWElementSetTest { + + private LWWElementSet set; + private final Bias bias = Bias.ADDS; + + @BeforeEach + void setUp() { + set = new LWWElementSet(); + } + + @Test + void testAdd() { + Element element = new Element("key1", 1, bias); + set.add(element); + + assertTrue(set.lookup(element)); + } + + @Test + void testRemove() { + Element element = new Element("key1", 1, bias); + set.add(element); + set.remove(element); + + assertFalse(set.lookup(element)); + } + + @Test + void testRemoveNonexistentElement() { + Element element = new Element("key1", 1, bias); + set.remove(element); + + assertFalse(set.lookup(element)); + } + + @Test + void testLookupNonexistentElement() { + Element element = new Element("key1", 1, bias); + + assertFalse(set.lookup(element)); + } + + @Test + void testCompareEqualSets() { + LWWElementSet otherSet = new LWWElementSet(); + + Element element = new Element("key1", 1, bias); + set.add(element); + otherSet.add(element); + + assertTrue(set.compare(otherSet)); + + otherSet.add(new Element("key2", 2, bias)); + assertTrue(set.compare(otherSet)); + } + + @Test + void testCompareDifferentSets() { + LWWElementSet otherSet = new LWWElementSet(); + + Element element1 = new Element("key1", 1, bias); + Element element2 = new Element("key2", 2, bias); + + set.add(element1); + otherSet.add(element2); + + assertFalse(set.compare(otherSet)); + } + + @Test + void testMerge() { + LWWElementSet otherSet = new LWWElementSet(); + + Element element1 = new Element("key1", 1, bias); + Element element2 = new Element("key2", 2, bias); + + set.add(element1); + otherSet.add(element2); + + set.merge(otherSet); + + assertTrue(set.lookup(element1)); + assertTrue(set.lookup(element2)); + } + + @Test + void testCompareTimestampsEqualTimestamps() { + LWWElementSet lwwElementSet = new LWWElementSet(); + + Element e1 = new Element("key1", 10, Bias.REMOVALS); + Element e2 = new Element("key1", 10, Bias.REMOVALS); + + assertTrue(lwwElementSet.compareTimestamps(e1, e2)); + + e1 = new Element("key1", 10, Bias.ADDS); + e2 = new Element("key1", 10, Bias.ADDS); + + assertFalse(lwwElementSet.compareTimestamps(e1, e2)); + } +} From 71c57b4087c056b3cefd19d366186078ee7ef9ed Mon Sep 17 00:00:00 2001 From: itakurah <122729995+itakurah@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:34:49 +0100 Subject: [PATCH 5/8] added LWWElementSet --- .../datastructures/crdt/LWWElementSet.java | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java new file mode 100644 index 000000000000..97212c8b4331 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java @@ -0,0 +1,139 @@ +package com.thealgorithms.datastructures.crdt; + +import java.util.HashMap; +import java.util.Map; + +/** + * Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data Type) + * designed for managing sets in a distributed and concurrent environment. It supports the addition and removal + * of elements, using timestamps to determine the order of operations. The set is split into two subsets: + * the add set for elements to be added and the remove set for elements to be removed. + * + * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah) + * @see Conflict-free_replicated_data_type + * @see itakurah (Niklas Hoefflin) + */ + +class Element { + String key; + int timestamp; + Bias bias; + + /** + * Constructs a new Element with the specified key, timestamp and bias. + * + * @param key The key of the element. + * @param timestamp The timestamp associated with the element. + * @param bias The bias of the element (ADDS or REMOVALS). + */ + public Element(String key, int timestamp, Bias bias) { + this.key = key; + this.timestamp = timestamp; + this.bias = bias; + } +} + +enum Bias { + /** + * ADDS bias for the add set. + * REMOVALS bias for the remove set. + */ + ADDS, REMOVALS +} + +class LWWElementSet { + private final Map addSet; + private final Map removeSet; + + /** + * Constructs an empty LWWElementSet. + */ + public LWWElementSet() { + this.addSet = new HashMap<>(); + this.removeSet = new HashMap<>(); + } + + /** + * Adds an element to the addSet. + * + * @param e The element to be added. + */ + public void add(Element e) { + addSet.put(e.key, e); + } + + /** + * Removes an element from the removeSet. + * + * @param e The element to be removed. + */ + public void remove(Element e) { + if (lookup(e)) { + removeSet.put(e.key, e); + } + } + + /** + * Checks if an element is in the LWWElementSet by comparing timestamps in the addSet and removeSet. + * + * @param e The element to be checked. + * @return True if the element is present, false otherwise. + */ + public boolean lookup(Element e) { + Element inAddSet = addSet.get(e.key); + Element inRemoveSet = removeSet.get(e.key); + + return (inAddSet != null && (inRemoveSet == null || inAddSet.timestamp > inRemoveSet.timestamp)); + } + + /** + * Compares the LWWElementSet with another LWWElementSet to check if addSet and removeSet are a subset. + * + * @param other The LWWElementSet to compare. + * @return True if the set is subset, false otherwise. + */ + public boolean compare(LWWElementSet other) { + return other.addSet.keySet().containsAll(addSet.keySet()) && + other.removeSet.keySet().containsAll(removeSet.keySet()); + } + + /** + * Merges another LWWElementSet into this set by resolving conflicts based on timestamps. + * + * @param other The LWWElementSet to merge. + */ + public void merge(LWWElementSet other) { + for (Element e : other.addSet.values()) { + if (!addSet.containsKey(e.key) || compareTimestamps(addSet.get(e.key), e)) { + addSet.put(e.key, e); + } + } + + for (Element e : other.removeSet.values()) { + if (!removeSet.containsKey(e.key) || compareTimestamps(removeSet.get(e.key), e)) { + removeSet.put(e.key, e); + } + } + } + + /** + * Compares timestamps of two elements based on their bias (ADDS or REMOVALS). + * + * @param e The first element. + * @param other The second element. + * @return True if the first element's timestamp is greater or the bias is ADDS and timestamps are equal. + */ + public boolean compareTimestamps(Element e, Element other) { + if (!e.bias.equals(other.bias)) { + throw new IllegalArgumentException("Invalid bias value"); + } + Bias bias = e.bias; + int timestampComparison = Integer.compare(e.timestamp, other.timestamp); + + + if (timestampComparison == 0) { + return !bias.equals(Bias.ADDS); + } + return timestampComparison < 0; + } +} From a512ff8cf6af9735686e16d8454f8865ef7694ef Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 8 Dec 2023 14:35:05 +0000 Subject: [PATCH 6/8] Update directory --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 86161e5241bf..e6900a93e0c2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -85,6 +85,7 @@ * crdt * [GCounter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/GCounter.java) * [GSet](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java) + * [LWWElementSet](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java) * [PNCounter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java) * disjointsetunion * [DisjointSetUnion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java) @@ -620,6 +621,7 @@ * crdt * [GCounterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/GCounterTest.java) * [GSetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java) + * [LWWElementSetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java) * [PNCounterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/PNCounterTest.java) * disjointsetunion * [DisjointSetUnionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java) From 59b75684caf6cd376ed17ba4b02dacbe9d5d184f Mon Sep 17 00:00:00 2001 From: itakurah <122729995+itakurah@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:41:02 +0100 Subject: [PATCH 7/8] clang format --- .../com/thealgorithms/datastructures/crdt/LWWElementSet.java | 3 +-- .../thealgorithms/datastructures/crdt/LWWElementSetTest.java | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java index 97212c8b4331..eb520af1673a 100644 --- a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java +++ b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java @@ -93,8 +93,7 @@ public boolean lookup(Element e) { * @return True if the set is subset, false otherwise. */ public boolean compare(LWWElementSet other) { - return other.addSet.keySet().containsAll(addSet.keySet()) && - other.removeSet.keySet().containsAll(removeSet.keySet()); + return other.addSet.keySet().containsAll(addSet.keySet()) && other.removeSet.keySet().containsAll(removeSet.keySet()); } /** diff --git a/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java index c55d921d7874..6fb227bd80c5 100644 --- a/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java +++ b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java @@ -1,8 +1,9 @@ package com.thealgorithms.datastructures.crdt; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; class LWWElementSetTest { From c9ddebe4e1e6cd441ac7309000c89acbad2d8aee Mon Sep 17 00:00:00 2001 From: itakurah <122729995+itakurah@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:43:46 +0100 Subject: [PATCH 8/8] clang format --- .../com/thealgorithms/datastructures/crdt/LWWElementSet.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java index eb520af1673a..722c916ab0ce 100644 --- a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java +++ b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java @@ -38,7 +38,8 @@ enum Bias { * ADDS bias for the add set. * REMOVALS bias for the remove set. */ - ADDS, REMOVALS + ADDS, + REMOVALS } class LWWElementSet { @@ -129,7 +130,6 @@ public boolean compareTimestamps(Element e, Element other) { Bias bias = e.bias; int timestampComparison = Integer.compare(e.timestamp, other.timestamp); - if (timestampComparison == 0) { return !bias.equals(Bias.ADDS); }