From 8bcfcd3d178c6697248f5a924d6ababedd0f517a Mon Sep 17 00:00:00 2001 From: Linus Wagner Date: Thu, 7 Mar 2024 22:35:42 +0100 Subject: [PATCH 1/5] Add intersection and isDisjoined to set lib --- src/org/rascalmpl/library/Set.rsc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/org/rascalmpl/library/Set.rsc b/src/org/rascalmpl/library/Set.rsc index 10e0f819cd..82903b8125 100644 --- a/src/org/rascalmpl/library/Set.rsc +++ b/src/org/rascalmpl/library/Set.rsc @@ -513,3 +513,29 @@ public set[&T] union(set[set[&T]] sets) = {*s | s <- sets}; @synopsis{Compute the Jaccard similarity between two sets.} real jaccard(set[value] x, set[value] y) = (1. * size(x & y)) / size(x + y); + + +@synopsis{Calculate the intersection of a set of sets.} +public set[&T] intersection(set[set[&T]] sets) = (getFirstFrom(sets) | it & elem | elem <- sets); + + +@synopsis{Checks if all sets in the set are pairwise disjoined.} +@examples{ +```rascal-shell +import Set; +isDisjoined({{1,2}, {3,4}, {5,6}}); +isDisjoined({{1,2}, {1,4}, {5,6}}); +isDisjoined({{1,2}, {1,4}, {1,6}}); +``` +} +public bool isDisjoined(set[set[&T]] sets) { + list[set[&T]] setsAsList = toList(sets); + pairs = {}; + for (elem1 <- setsAsList) { + for (elem2 <- setsAsList[1..]) { + if (elem1 & elem2 != {}) return false; + } + } + + return true; +} \ No newline at end of file From 64fe9e73f060f09718daa0f406409923b1b4d1cb Mon Sep 17 00:00:00 2001 From: Linus Wagner Date: Thu, 7 Mar 2024 22:55:08 +0100 Subject: [PATCH 2/5] fix bug isDisjoined --- src/org/rascalmpl/library/Set.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/org/rascalmpl/library/Set.rsc b/src/org/rascalmpl/library/Set.rsc index 82903b8125..ccaeb3d69d 100644 --- a/src/org/rascalmpl/library/Set.rsc +++ b/src/org/rascalmpl/library/Set.rsc @@ -530,10 +530,10 @@ isDisjoined({{1,2}, {1,4}, {1,6}}); } public bool isDisjoined(set[set[&T]] sets) { list[set[&T]] setsAsList = toList(sets); - pairs = {}; - for (elem1 <- setsAsList) { - for (elem2 <- setsAsList[1..]) { - if (elem1 & elem2 != {}) return false; + + for (elem1 <- [0..size(setsAsList)-1]) { + for (elem2 <- [elem1+1..size(setsAsList)]) { + if (setsAsList[elem1] & setsAsList[elem2] != {}) return false; } } From 2f2aa75a8cf7b87984e52e07fbc5e3a7bd370664 Mon Sep 17 00:00:00 2001 From: Linus Wagner Date: Sun, 10 Mar 2024 14:31:19 +0100 Subject: [PATCH 3/5] Fix disjoint and intersection --- src/org/rascalmpl/library/Set.rsc | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/org/rascalmpl/library/Set.rsc b/src/org/rascalmpl/library/Set.rsc index ccaeb3d69d..f891f0ba6b 100644 --- a/src/org/rascalmpl/library/Set.rsc +++ b/src/org/rascalmpl/library/Set.rsc @@ -516,26 +516,20 @@ real jaccard(set[value] x, set[value] y) = (1. * size(x & y)) / size(x + y); @synopsis{Calculate the intersection of a set of sets.} -public set[&T] intersection(set[set[&T]] sets) = (getFirstFrom(sets) | it & elem | elem <- sets); +public set[&T] intersection({set[&T] firstSet, *set[&T] otherSets}) = (firstSet | it & elem | elem <- otherSets); +public set[&T] intersection({}) = {}; -@synopsis{Checks if all sets in the set are pairwise disjoined.} +@synopsis{Checks if all sets in the set are pairwise disjoint.} @examples{ ```rascal-shell import Set; -isDisjoined({{1,2}, {3,4}, {5,6}}); -isDisjoined({{1,2}, {1,4}, {5,6}}); -isDisjoined({{1,2}, {1,4}, {1,6}}); +isDisjoint([{1,2}, {3,4}, {5,6}]); +isDisjoint([{1,2}, {1,4}, {5,6}]); +isDisjoint([{1,2}, {1,4}, {1,6}]); ``` } -public bool isDisjoined(set[set[&T]] sets) { - list[set[&T]] setsAsList = toList(sets); - - for (elem1 <- [0..size(setsAsList)-1]) { - for (elem2 <- [elem1+1..size(setsAsList)]) { - if (setsAsList[elem1] & setsAsList[elem2] != {}) return false; - } - } - - return true; -} \ No newline at end of file +public bool isDisjoint([set[&T] a, set[&T] b, *_]) = false when a & b != {}; // will backtrack to other pairs of a and b while the condition fails +public default bool isDisjoint([set[&T] a, set[&T] b, *_]) = true; +public bool isDisjoint([set[&T] a]) = true; +public bool isDisjoint([]) = true; From c60ae1465d7b56ef3645f656d98b294c75413700 Mon Sep 17 00:00:00 2001 From: Linus Wagner Date: Sun, 10 Mar 2024 14:33:01 +0100 Subject: [PATCH 4/5] extend documentation isDisjoint --- src/org/rascalmpl/library/Set.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/org/rascalmpl/library/Set.rsc b/src/org/rascalmpl/library/Set.rsc index f891f0ba6b..f634d1630b 100644 --- a/src/org/rascalmpl/library/Set.rsc +++ b/src/org/rascalmpl/library/Set.rsc @@ -521,6 +521,9 @@ public set[&T] intersection({}) = {}; @synopsis{Checks if all sets in the set are pairwise disjoint.} +@description{ + To allow two elements (i.e. two sets) to be identical, the argument is of type list and not type set. +} @examples{ ```rascal-shell import Set; From d29bdf4d16b1730b410b431d7923346f863b5f5c Mon Sep 17 00:00:00 2001 From: Linus Wagner Date: Wed, 13 Mar 2024 17:29:53 +0100 Subject: [PATCH 5/5] Make intersection and isPairwiseDisjoint stricter, add tests --- src/org/rascalmpl/library/Set.rsc | 49 ++++++++++++++---- .../library/lang/rascal/tests/library/Set.rsc | 51 +++++++++++++++++-- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/src/org/rascalmpl/library/Set.rsc b/src/org/rascalmpl/library/Set.rsc index f634d1630b..a2a1105e32 100644 --- a/src/org/rascalmpl/library/Set.rsc +++ b/src/org/rascalmpl/library/Set.rsc @@ -516,23 +516,50 @@ real jaccard(set[value] x, set[value] y) = (1. * size(x & y)) / size(x + y); @synopsis{Calculate the intersection of a set of sets.} -public set[&T] intersection({set[&T] firstSet, *set[&T] otherSets}) = (firstSet | it & elem | elem <- otherSets); -public set[&T] intersection({}) = {}; +@description{ + Can only be applied to sets that contain at least two sets, + because the intersection is generally a binary operator. + Empty sets or sets with one set throw an exception. +} +public set[&T] intersection(wholeSet:{set[&T] firstSet, *set[&T] otherSets}) { + if (otherSets == {}) { + throw IllegalArgument(wholeSet, "Intersection only possible with at least two sets."); + } + return (firstSet | it & elem | elem <- otherSets); +} +public set[&T] intersection(wholeSet:{}) { + throw IllegalArgument(wholeSet, "Intersection only possible with at least two sets."); +} -@synopsis{Checks if all sets in the set are pairwise disjoint.} +@synopsis{Checks if all sets in the list are pairwise disjoint.} @description{ - To allow two elements (i.e. two sets) to be identical, the argument is of type list and not type set. + We follow one definition of pairwise disjoint sets, which does not allow identical sets. + For example, `[{1}, {1}]` is not pairwise disjoint, because it contains two times the same sets. + + Can only be applied to lists that contain at least two sets, + because no or only a single set can not be pairwise disjoint. + Empty lists or lists with one set throw an exception. } @examples{ ```rascal-shell import Set; -isDisjoint([{1,2}, {3,4}, {5,6}]); -isDisjoint([{1,2}, {1,4}, {5,6}]); -isDisjoint([{1,2}, {1,4}, {1,6}]); +isPairwiseDisjoint([{1,2}, {3,4}, {5,6}]); +isPairwiseDisjoint([{1,2}, {1,4}, {5,6}]); +isPairwiseDisjoint([{1,2}, {1,4}, {1,6}]); ``` } -public bool isDisjoint([set[&T] a, set[&T] b, *_]) = false when a & b != {}; // will backtrack to other pairs of a and b while the condition fails -public default bool isDisjoint([set[&T] a, set[&T] b, *_]) = true; -public bool isDisjoint([set[&T] a]) = true; -public bool isDisjoint([]) = true; +public bool isPairwiseDisjoint(wholeInput:list[set[&T]] sets) { + int sizeSets = size(sets); + if (sizeSets == 0 || sizeSets == 1) { + throw IllegalArgument(wholeInput, "Only two or more sets can be pairwise disjoint."); + } + + for (i <- [0..sizeSets-1]) { + for (j <- [i+1..sizeSets]) { + if (sets[i] & sets[j] != {}) return false; + } + } + + return true; +} diff --git a/src/org/rascalmpl/library/lang/rascal/tests/library/Set.rsc b/src/org/rascalmpl/library/lang/rascal/tests/library/Set.rsc index b3374c5e52..a963c6f2c4 100644 --- a/src/org/rascalmpl/library/lang/rascal/tests/library/Set.rsc +++ b/src/org/rascalmpl/library/lang/rascal/tests/library/Set.rsc @@ -157,6 +157,51 @@ test bool testDynamicTypes2() {set[value] s = {"1",2,3}; return set[int] _ := s test bool testDynamicTypes3() {set[value] s = {"1",2,3}; return set[int] _ := s & {2,3};} test bool testDynamicTypes4() = {"1", *int _} := {"1",2,3}; - - - +// intersection +test bool testIntersectionEmptySet() { + try { + intersection({}); + } + catch IllegalArgument(wholeSet, msg): { + return wholeSet == {} && msg == "Intersection only possible with at least two sets."; + } + return false; +} + +test bool testIntersectionSingleElement() { + try { + intersection({{1}}); + } + catch IllegalArgument(wholeSet, msg): { + return wholeSet == {{1}} && msg == "Intersection only possible with at least two sets."; + } + return false; +} + +test bool testIntersectionNoOverlap() {return intersection({{1,2}, {3,4}}) == {};} +test bool testIntersectionOverlap() {return intersection({{1,2}, {2,3}, {2,5}}) == {2};} + +// isDisjoint +test bool testIsPairwiseDisjointEmpty() { + try { + isPairwiseDisjoint([]); + } + catch IllegalArgument(wholeInput, msg): { + return wholeInput == [] && msg == "Only two or more sets can be pairwise disjoint."; + } + return false; +} + +test bool testIsPairwiseDisjointSingleElement() { + try { + isPairwiseDisjoint([{1}]); + } + catch IllegalArgument(wholeInput, msg): { + return wholeInput == [{1}] && msg == "Only two or more sets can be pairwise disjoint."; + } + return false; +} + +test bool testIsPairwiseDisjointIdenticalElements() {return isPairwiseDisjoint([{1}, {1}]) == false;} +test bool testIsPairwiseDisjointNoOverlap() {return isPairwiseDisjoint([{1,2},{3,4},{5,6}]) == true;} +test bool testIsPairwiseDisjointOverlap() {return isPairwiseDisjoint([{1,2}, {-4,5}, {1,6,7}]) == false;} \ No newline at end of file