aboutsummaryrefslogtreecommitdiffstats
path: root/model-data/src
diff options
context:
space:
mode:
authorLibravatar OszkarSemerath <semerath@mit.bme.hu>2021-08-08 23:23:03 +0200
committerLibravatar OszkarSemerath <semerath@mit.bme.hu>2021-08-08 23:23:03 +0200
commita97786449babddc7330079b8ec195f8b69404bae (patch)
treef64db12b00414d1cb652df08d9abe86f6f6889b1 /model-data/src
parentMultithread tests added (diff)
downloadrefinery-a97786449babddc7330079b8ec195f8b69404bae.tar.gz
refinery-a97786449babddc7330079b8ec195f8b69404bae.tar.zst
refinery-a97786449babddc7330079b8ec195f8b69404bae.zip
Tuple and Tuple continuous hash provider
Diffstat (limited to 'model-data/src')
-rw-r--r--model-data/src/main/java/org/eclipse/viatra/solver/data/model/Tuple.java131
-rw-r--r--model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProvider.java65
-rw-r--r--model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProviderBitMagic.java28
-rw-r--r--model-data/src/test/java/org/eclipse/viatra/solver/data/model/hashTests/HashEfficiencyTest.java160
4 files changed, 384 insertions, 0 deletions
diff --git a/model-data/src/main/java/org/eclipse/viatra/solver/data/model/Tuple.java b/model-data/src/main/java/org/eclipse/viatra/solver/data/model/Tuple.java
new file mode 100644
index 00000000..eb99c862
--- /dev/null
+++ b/model-data/src/main/java/org/eclipse/viatra/solver/data/model/Tuple.java
@@ -0,0 +1,131 @@
1package org.eclipse.viatra.solver.data.model;
2
3import java.util.Arrays;
4
5public abstract class Tuple {
6 private static final int CustomTupleSize = 2;
7
8 public abstract int getSize();
9 public abstract int get(int element);
10 public abstract int[] toArray();
11 @Override
12 public String toString() {
13 StringBuilder b = new StringBuilder();
14 b.append("[");
15 for(int i = 0; i<getSize(); i++) {
16 if(i!=0) {
17 b.append(",");
18 }
19 b.append(get(i));
20 }
21 b.append("]");
22 return b.toString();
23 }
24
25 public static Tuple of(int... values) {
26 if(values.length == 0) {
27 return new Tuple0();
28 } else if(values.length == 1) {
29 return new Tuple1(values[0]);
30 } else if(values.length == 2) {
31 return new Tuple2(values[0],values[1]);
32 } else return new TupleN(values);
33 }
34
35 protected IllegalArgumentException doesNotContain(int element) {
36 return new IllegalArgumentException("Tuple does not contain element "+element);
37 }
38
39 public static class Tuple0 extends Tuple{
40 protected Tuple0() { }
41 @Override public int getSize() { return 0; }
42 @Override public int get(int element) {
43 throw doesNotContain(element);
44 }
45 @Override public int[] toArray() {return new int[]{};}
46 @Override public int hashCode() { return TupleHashProvider.singleton().getHash(this, 0); }
47 @Override
48 public boolean equals(Object obj) {
49 if (this == obj)
50 return true;
51 if (obj == null)
52 return false;
53 if (getClass() != obj.getClass())
54 return false;
55 return true;
56 }
57 }
58 public static class Tuple1 extends Tuple{
59 final int value0;
60 protected Tuple1(int value0) { this.value0 = value0; }
61 @Override public int getSize() { return 1; }
62 @Override public int get(int element) {
63 if(element == 0) return value0;
64 throw doesNotContain(element);
65 }
66 @Override public int[] toArray() {return new int[]{ value0 };}
67 @Override public int hashCode() { return TupleHashProvider.singleton().getHash(this, 0); }
68 @Override
69 public boolean equals(Object obj) {
70 if (this == obj)
71 return true;
72 if (obj == null)
73 return false;
74 if (getClass() != obj.getClass())
75 return false;
76 Tuple1 other = (Tuple1) obj;
77 return value0 == other.value0;
78 }
79 }
80 public static class Tuple2 extends Tuple{
81 final int value0;
82 final int value1;
83 protected Tuple2(int value0, int value1) { this.value0 = value0; this.value1 = value1; }
84 @Override public int getSize() { return 2; }
85 @Override public int get(int element) {
86 if(element == 0) return value0;
87 else if(element == 1) return value1;
88 throw doesNotContain(element);
89 }
90 @Override public int[] toArray() {return new int[]{ value0,value1 };}
91 @Override public int hashCode() { return TupleHashProvider.singleton().getHash(this, 0); }
92 @Override
93 public boolean equals(Object obj) {
94 if (this == obj)
95 return true;
96 if (obj == null)
97 return false;
98 if (getClass() != obj.getClass())
99 return false;
100 Tuple2 other = (Tuple2) obj;
101 return value0 == other.value0 && value1 == other.value1;
102 }
103 }
104 public static class TupleN extends Tuple{
105 final int[] values;
106 protected TupleN(int[] values) {
107 if(values.length<CustomTupleSize)
108 throw new IllegalArgumentException();
109 this.values = Arrays.copyOf(values, values.length);
110 }
111 @Override public int getSize() { return values.length; }
112 @Override public int get(int element) {
113 if(0<=element && element < values.length) {
114 return values[element];
115 } else throw doesNotContain(element);
116 }
117 @Override public int[] toArray() { return values; }
118 @Override public int hashCode() { return TupleHashProvider.singleton().getHash(this, 0); }
119 @Override
120 public boolean equals(Object obj) {
121 if (this == obj)
122 return true;
123 if (obj == null)
124 return false;
125 if (getClass() != obj.getClass())
126 return false;
127 TupleN other = (TupleN) obj;
128 return Arrays.equals(values, other.values);
129 }
130 }
131}
diff --git a/model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProvider.java b/model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProvider.java
new file mode 100644
index 00000000..6c37aa37
--- /dev/null
+++ b/model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProvider.java
@@ -0,0 +1,65 @@
1package org.eclipse.viatra.solver.data.model;
2
3import org.eclipse.viatra.solver.data.map.ContinousHashProvider;
4
5public class TupleHashProvider implements ContinousHashProvider<Tuple> {
6 protected static TupleHashProvider instance;
7
8 public static TupleHashProvider singleton() {
9 if (instance == null) {
10 instance = new TupleHashProvider();
11 }
12 return instance;
13 }
14
15 protected static final int[] primes = new int[] { 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
16 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
17 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337,
18 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461,
19 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
20 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739,
21 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881,
22 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021,
23 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
24 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283,
25 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429,
26 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549,
27 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
28 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
29 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973,
30 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089,
31 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
32 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377,
33 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531,
34 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677,
35 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791,
36 2797, 2801, 2803, 2819, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217,
37 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359,
38 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517,
39 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637,
40 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793,
41 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911 };
42
43 protected static final long LARGESTPRIME30BITS = 1073741789;
44
45 public TupleHashProvider() {
46 if (primes.length < MAX_PRACTICAL_DEPTH) {
47 throw new UnsupportedOperationException(
48 "Not enough prime numbers to support the practical depth of continuous hash!");
49 }
50 }
51
52 @Override
53 public int getHash(Tuple key, int index) {
54 if (index >= primes.length) {
55 throw new IllegalArgumentException("Not enough prime numbers to support index");
56 }
57 long accumulator = 0;
58 final int prime = primes[index];
59 for (int i = 0; i < key.getSize(); i++) {
60 accumulator = (prime * accumulator + key.get(i)) % LARGESTPRIME30BITS;
61 }
62
63 return (int) accumulator;
64 }
65}
diff --git a/model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProviderBitMagic.java b/model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProviderBitMagic.java
new file mode 100644
index 00000000..2a514d66
--- /dev/null
+++ b/model-data/src/main/java/org/eclipse/viatra/solver/data/model/TupleHashProviderBitMagic.java
@@ -0,0 +1,28 @@
1package org.eclipse.viatra.solver.data.model;
2
3import org.eclipse.viatra.solver.data.map.ContinousHashProvider;
4
5public class TupleHashProviderBitMagic implements ContinousHashProvider<Tuple> {
6
7 @Override
8 public int getHash(Tuple key, int index) {
9 if(key.getSize() == 1) {
10 return key.get(0);
11 }
12
13 int result = 0;
14 final int startBitIndex = index*30;
15 final int finalBitIndex = startBitIndex+30;
16 final int arity = key.getSize();
17
18 for(int i = startBitIndex; i<=finalBitIndex; i++) {
19 final int selectedKey = key.get(i%arity);
20 final int selectedPosition = 1<<(i/arity);
21 if((selectedKey&selectedPosition) != 0) {
22 result |= 1<<(i%30);
23 }
24 }
25
26 return result;
27 }
28}
diff --git a/model-data/src/test/java/org/eclipse/viatra/solver/data/model/hashTests/HashEfficiencyTest.java b/model-data/src/test/java/org/eclipse/viatra/solver/data/model/hashTests/HashEfficiencyTest.java
new file mode 100644
index 00000000..c4d98a43
--- /dev/null
+++ b/model-data/src/test/java/org/eclipse/viatra/solver/data/model/hashTests/HashEfficiencyTest.java
@@ -0,0 +1,160 @@
1package org.eclipse.viatra.solver.data.model.hashTests;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import java.util.ArrayList;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Random;
9
10import org.eclipse.viatra.solver.data.map.ContinousHashProvider;
11import org.eclipse.viatra.solver.data.model.Tuple;
12import org.eclipse.viatra.solver.data.model.TupleHashProvider;
13import org.eclipse.viatra.solver.data.model.TupleHashProviderBitMagic;
14import org.junit.jupiter.api.Test;
15
16class HashEfficiencyTest {
17
18 private static List<Tuple> permutations(int range, int arity) {
19 if(arity == 1) {
20 List<Tuple> result = new ArrayList<>(range);
21 for(int i=0; i<range; i++) {
22 result.add(Tuple.of(i));
23 }
24 return result;
25 } else if(arity > 1) {
26 List<Tuple> smallers = permutations(range, arity-1);
27 List<Tuple> result = new ArrayList<>(range*smallers.size());
28 for(Tuple smaller : smallers) {
29 for(int i=0; i<range; i++) {
30 int[] larger = new int[arity];
31 for(int x = 0; x<smaller.getSize(); x++) {
32 larger[x] = smaller.get(x);
33 }
34 larger[arity-1] = i;
35 result.add(Tuple.of(larger));
36 }
37 }
38 return result;
39 } else throw new IllegalArgumentException();
40 }
41
42 private static int amountToRange(int arity, int n) {
43 int range = 1;
44 while(Math.pow(range,arity)<n+0.1) {
45 range++;
46 }
47 return 1024;
48 }
49
50 public static List<Tuple> nPermutations(int arity, int n) {
51 int range = amountToRange(arity, n);
52 List<Tuple> permutations = permutations(range, arity);
53 return permutations.subList(0, n);
54 }
55
56 public static List<Tuple> nRandoms(int arity, int n, int seed) {
57 int range = amountToRange(arity, n);
58 List<Tuple> permutations = new ArrayList<>(n);
59 Random r = new Random(seed);
60 for(int i = 0; i<n; i++) {
61 int[] tuple = new int[arity];
62 for(int j=0; j<arity; j++) {
63 tuple[j] = r.nextInt(range);
64 }
65 permutations.add(Tuple.of(tuple));
66 }
67 return permutations;
68 }
69
70 @Test
71 void permutationTest() {
72 List<Tuple> p = permutations(10, 2);
73 assertEquals(p.size(),10*10);
74 }
75// private void printTuples(List<Tuple> p) {
76// for(Tuple element : p) {
77// System.out.println(element);
78// }
79// }
80 @Test
81 void nPermutationTest() {
82 final int amount = 500;
83 List<Tuple> p = nPermutations(2, amount);
84 assertEquals(amount,p.size());
85 }
86 @Test
87 void nRandomTest() {
88 final int amount = 500;
89 List<Tuple> p = nRandoms(2, amount, 1);;
90 assertEquals(amount,p.size());
91 }
92 private static double calculateHashClashes(List<Tuple> tuples, ContinousHashProvider<Tuple> chp) {
93 int sumClashes = 0;
94
95 for(int i = 0; i<tuples.size(); i++) {
96 int height = 0;
97 for(int j=0; j<tuples.size(); j++) {
98 int clashes = calculateHashClash(chp, tuples.get(i), tuples.get(j));
99 height = Math.max(height, clashes);
100 }
101 sumClashes += height;
102 }
103 return (sumClashes+0.0) / tuples.size();
104 }
105 private static int calculateHashClash(ContinousHashProvider<Tuple> chp, Tuple a, Tuple b) {
106 if(a.equals(b)) return 0;
107 final int bits = 5;
108 final int segments = Integer.SIZE/bits;
109 final int mask = (1<<bits)-1;
110 for(int i = 0;;i++) {
111 int index = i/segments;
112 int depth = i%segments;
113 int aHash = (chp.getHash(a, index)>>(depth*5))&mask;
114 int bHash = (chp.getHash(b, index)>>(depth*5))&mask;
115 if(aHash != bHash) {
116 return i+1;
117 }
118 if(i>400) {
119 throw new IllegalStateException(a+" vs "+b);
120 }
121 }
122 }
123 private static double caclulateOptimalHashClash(int size) {
124 return (Math.log(size)/Math.log(32));
125 }
126 public static void main(String[] args) {
127 List<String> hashNames = new LinkedList<>();
128 List<ContinousHashProvider<Tuple>> hashes = new LinkedList<>();
129 hashNames.add("PrimeGroup");
130 hashes.add(new TupleHashProvider());
131 hashNames.add("BitMagic");
132 hashes.add(new TupleHashProviderBitMagic());
133
134 int[] arities = new int[] {2,3,4,5};
135 int[] sizes = new int[] {32*32,32*32*8};
136
137 System.out.println("Size,Arity,DataSource,Hash,Chashes,Optimal,Badness");
138 for(int size : sizes) {
139 double optimalClashes = caclulateOptimalHashClash(size);
140 for(int arity : arities) {
141 List<String> dataSourceNames = new LinkedList<>();
142 List<List<Tuple>> dataSources = new LinkedList<>();
143
144// dataSourceNames.add("Permutation");
145// dataSources.add(nPermutations(arity, size));
146 dataSourceNames.add("Random");
147 dataSources.add(nRandoms(arity, size, 0));
148
149 for(int dataSourceIndex = 0; dataSourceIndex<dataSourceNames.size(); dataSourceIndex++) {
150 for(int hashIndex = 0; hashIndex<hashNames.size(); hashIndex++) {
151 double clashes = calculateHashClashes(dataSources.get(dataSourceIndex),hashes.get(hashIndex));
152 System.out.println(
153 size+","+arity+","+dataSourceNames.get(dataSourceIndex)+","+hashNames.get(hashIndex)+","+
154 clashes+","+optimalClashes+","+(clashes+0.0)/optimalClashes);
155 }
156 }
157 }
158 }
159 }
160}