dither 0.2.2-java → 0.2.5-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +8 -2
- data/dither.gemspec +1 -3
- data/ext/dither/Aetg.java +51 -0
- data/ext/dither/AetgPairwise.java +258 -0
- data/ext/dither/ArrayLengthComparator.java +30 -0
- data/ext/dither/CombinatoricHelper.java +143 -0
- data/ext/dither/ConstraintHandler.java +120 -0
- data/ext/dither/Dither.java +155 -0
- data/ext/dither/DitherError.java +45 -0
- data/ext/dither/IndexArrayPair.java +40 -0
- data/ext/dither/Ipog.java +405 -0
- data/ext/dither/Pair.java +61 -0
- data/ext/dither/base_constraint_handler.h +4 -1
- data/ext/dither/combinations.h +21 -12
- data/ext/dither/ipog.cc +71 -37
- data/ext/dither/ipog.h +12 -7
- data/ext/dither/simple_constraint_handler.cc +14 -2
- data/ext/dither/simple_constraint_handler.h +2 -1
- data/lib/dither/version.rb +1 -1
- data/lib/dither.jar +0 -0
- data/lib/dither.rb +1 -2
- metadata +28 -19
- data/lib/choco-solver-3.3.1-with-dependencies.jar +0 -0
- data/lib/dither-0.1.5.jar +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70b7f18273e2e2f9f75673c656887486d4bcbe48
|
4
|
+
data.tar.gz: 037da612c8c844b3e6c10e6931c95f76e9c284f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13d7a1918fe9fbcef6213aeafab6a6d71cd6aa1320554c219fd2751a3d3542852c7c5b792897c6d2fe4bedd6fe89806692d9112c353c8976fa0aa82dfe4158df
|
7
|
+
data.tar.gz: 78d47ad277c884cbf6450151f2532ff4311c86809857e0c358a138c688ed7b0c762c7961a44ac72b75607e7e4a8b2083508d21999006de788cf798aafccf4264
|
data/Rakefile
CHANGED
@@ -5,7 +5,13 @@ Bundler::GemHelper.install_tasks
|
|
5
5
|
require 'rspec/core/rake_task'
|
6
6
|
RSpec::Core::RakeTask.new
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
if RUBY_PLATFORM =~ /java/
|
9
|
+
require 'rake/javaextensiontask'
|
10
|
+
Rake::JavaExtensionTask.new('dither')
|
11
|
+
else
|
12
|
+
require 'rake/extensiontask'
|
13
|
+
Rake::ExtensionTask.new('dither')
|
14
|
+
end
|
10
15
|
|
11
16
|
task :default => :spec
|
17
|
+
|
data/dither.gemspec
CHANGED
@@ -23,9 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
|
24
24
|
if RUBY_PLATFORM =~ /java/
|
25
25
|
s.platform = "java"
|
26
|
-
|
27
|
-
files << "lib/dither-0.1.5.jar"
|
28
|
-
files << "lib/choco-solver-3.3.1-with-dependencies.jar"
|
26
|
+
files << "lib/dither.jar"
|
29
27
|
else
|
30
28
|
s.add_dependency "ffi", "~> 1.0"
|
31
29
|
s.extensions = 'ext/dither/extconf.rb'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
package com.github.jesg.dither;
|
2
|
+
|
3
|
+
/*
|
4
|
+
* #%L
|
5
|
+
* dither
|
6
|
+
* %%
|
7
|
+
* Copyright (C) 2015 Jason Gowan
|
8
|
+
* %%
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
* you may not use this file except in compliance with the License.
|
11
|
+
* You may obtain a copy of the License at
|
12
|
+
*
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
*
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
* See the License for the specific language governing permissions and
|
19
|
+
* limitations under the License.
|
20
|
+
* #L%
|
21
|
+
*/
|
22
|
+
|
23
|
+
import java.util.Iterator;
|
24
|
+
import java.util.LinkedList;
|
25
|
+
import java.util.List;
|
26
|
+
|
27
|
+
public abstract class Aetg implements Iterator<Object[]> {
|
28
|
+
|
29
|
+
public abstract boolean hasNext();
|
30
|
+
public abstract Object[] next();
|
31
|
+
|
32
|
+
public List<Object[]> toList() {
|
33
|
+
final List<Object[]> results = new LinkedList<Object[]>();
|
34
|
+
|
35
|
+
while(hasNext()) {
|
36
|
+
final Object[] result = next();
|
37
|
+
if(result != null) {
|
38
|
+
results.add(result);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
return results;
|
43
|
+
}
|
44
|
+
|
45
|
+
public Object[][] toArray() {
|
46
|
+
return toList().toArray(new Object[][]{});
|
47
|
+
}
|
48
|
+
|
49
|
+
public void remove() {}
|
50
|
+
|
51
|
+
}
|
@@ -0,0 +1,258 @@
|
|
1
|
+
package com.github.jesg.dither;
|
2
|
+
|
3
|
+
import java.util.ArrayList;
|
4
|
+
import java.util.LinkedList;
|
5
|
+
import java.util.List;
|
6
|
+
import java.util.ListIterator;
|
7
|
+
import java.util.Random;
|
8
|
+
import java.util.concurrent.Callable;
|
9
|
+
import java.util.concurrent.ExecutorService;
|
10
|
+
import java.util.concurrent.Semaphore;
|
11
|
+
import java.util.concurrent.ThreadLocalRandom;
|
12
|
+
|
13
|
+
/*
|
14
|
+
* #%L
|
15
|
+
* dither
|
16
|
+
* %%
|
17
|
+
* Copyright (C) 2015 Jason Gowan
|
18
|
+
* %%
|
19
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
20
|
+
* you may not use this file except in compliance with the License.
|
21
|
+
* You may obtain a copy of the License at
|
22
|
+
*
|
23
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
24
|
+
*
|
25
|
+
* Unless required by applicable law or agreed to in writing, software
|
26
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
27
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
28
|
+
* See the License for the specific language governing permissions and
|
29
|
+
* limitations under the License.
|
30
|
+
* #L%
|
31
|
+
True*/
|
32
|
+
|
33
|
+
class AetgPairwise extends Aetg {
|
34
|
+
|
35
|
+
private final int n = 50;
|
36
|
+
private final int[][] scratch = new int[n][];
|
37
|
+
private final int[] fitness = new int[n];
|
38
|
+
private final Object[][] params;
|
39
|
+
private final Pair[][] pairCache;
|
40
|
+
private final List<Pair[]> coverage;
|
41
|
+
private final AtegRandom random;
|
42
|
+
private final ExecutorService executor;
|
43
|
+
private final Semaphore barrier;
|
44
|
+
private final List<Callable<Void>> tasks = new ArrayList<Callable<Void>>(n);
|
45
|
+
private final Pair[][] constraints;
|
46
|
+
|
47
|
+
public AetgPairwise(final int t, final Integer seed, final Object[][] params, final Integer[][] constraintsParam, final Object[][] previouslyTested, final ExecutorService executor) {
|
48
|
+
this.params = params;
|
49
|
+
this.executor = executor;
|
50
|
+
this.barrier = new Semaphore(0);
|
51
|
+
|
52
|
+
for(int i = 0; i < n; i++) {
|
53
|
+
final int index = i;
|
54
|
+
final Semaphore localBarrier = this.barrier;
|
55
|
+
tasks.add(new Callable<Void>() {
|
56
|
+
public Void call() {
|
57
|
+
try {
|
58
|
+
generate(index);
|
59
|
+
fitness(index);
|
60
|
+
} finally {
|
61
|
+
localBarrier.release();
|
62
|
+
}
|
63
|
+
return null;
|
64
|
+
}
|
65
|
+
});
|
66
|
+
}
|
67
|
+
|
68
|
+
if(seed == null) {
|
69
|
+
this.random = new AtegRandom() {
|
70
|
+
public int nextInt(final int i) { return ThreadLocalRandom.current().nextInt(0, i); }
|
71
|
+
};
|
72
|
+
} else {
|
73
|
+
this.random = new AtegRandom() {
|
74
|
+
final Random random = new Random(seed);
|
75
|
+
public int nextInt(final int i) { return random.nextInt(i); }
|
76
|
+
};
|
77
|
+
}
|
78
|
+
|
79
|
+
this.pairCache = new Pair[params.length][];
|
80
|
+
for(int i = 0; i < params.length; i++) {
|
81
|
+
this.pairCache[i] = new Pair[params[i].length];
|
82
|
+
|
83
|
+
for(int j = 0; j < params[i].length; j++) {
|
84
|
+
this.pairCache[i][j] = new Pair(i, j);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
this.constraints = new Pair[constraintsParam.length + previouslyTested.length][];
|
89
|
+
int constraintIndex = 0;
|
90
|
+
for(final Integer[] constraint : constraintsParam) {
|
91
|
+
final List<Pair> pairs = new ArrayList<Pair>();
|
92
|
+
for(int i = 0; i < constraint.length; i++) {
|
93
|
+
if(constraint[i] == null) {
|
94
|
+
continue;
|
95
|
+
}
|
96
|
+
pairs.add(pairCache[i][constraint[i]]);
|
97
|
+
}
|
98
|
+
constraints[constraintIndex++] = pairs.toArray(new Pair[]{});
|
99
|
+
}
|
100
|
+
|
101
|
+
for(final Object[] testCase : previouslyTested) {
|
102
|
+
final Pair[] pairs = new Pair[testCase.length];
|
103
|
+
for(int i = 0; i < pairs.length; i++) {
|
104
|
+
final Object currentObject = testCase[i];
|
105
|
+
for(int j = 0; j < params[i].length; j++) {
|
106
|
+
if(currentObject.equals(params[i][j])) {
|
107
|
+
pairs[i] = pairCache[i][j];
|
108
|
+
break;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
112
|
+
constraints[constraintIndex++] = pairs;
|
113
|
+
}
|
114
|
+
|
115
|
+
|
116
|
+
for(int u = 0; u < n; u++) {
|
117
|
+
scratch[u] = new int[params.length];
|
118
|
+
}
|
119
|
+
|
120
|
+
final int[] arr = new int[params.length];
|
121
|
+
for(int k = 0; k < params.length; k++) {
|
122
|
+
arr[k] = k;
|
123
|
+
}
|
124
|
+
|
125
|
+
this.coverage = new LinkedList<Pair[]>();
|
126
|
+
final int[] lengths = new int[t];
|
127
|
+
for(final int[] tmp : CombinatoricHelper.getCombinations(t, arr)) {
|
128
|
+
|
129
|
+
for(int i = 0; i < lengths.length; i++) {
|
130
|
+
lengths[i] = params[tmp[i]].length;
|
131
|
+
}
|
132
|
+
|
133
|
+
final Pair[][] pairs = new Pair[tmp.length][];
|
134
|
+
for(int i = 0; i < pairs.length; i++) {
|
135
|
+
pairs[i] = this.pairCache[tmp[i]];
|
136
|
+
}
|
137
|
+
|
138
|
+
outer:
|
139
|
+
for(final List<Pair> innerPairs : CombinatoricHelper.product(pairs)) {
|
140
|
+
final Pair[] innerComb = innerPairs.toArray(new Pair[innerPairs.size()]);
|
141
|
+
|
142
|
+
for(final Pair[] constraint : constraints) {
|
143
|
+
int count = 0;
|
144
|
+
for(final Pair pair : constraint) {
|
145
|
+
for(final Pair innerCombPair : innerComb) {
|
146
|
+
if(pair.equals(innerCombPair)) {
|
147
|
+
count++;
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
if(count == constraint.length) {
|
153
|
+
continue outer;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
coverage.add(innerComb);
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
public boolean hasNext() {
|
163
|
+
return !coverage.isEmpty();
|
164
|
+
}
|
165
|
+
|
166
|
+
public Object[] next() {
|
167
|
+
try {
|
168
|
+
executor.invokeAll(tasks);
|
169
|
+
barrier.acquire(n);
|
170
|
+
} catch(InterruptedException e) {
|
171
|
+
Thread.currentThread().interrupt();
|
172
|
+
return null;
|
173
|
+
}
|
174
|
+
final int i = bestFit();
|
175
|
+
if(fitness[i] <= 0) {
|
176
|
+
return null;
|
177
|
+
}
|
178
|
+
final int[] best = scratch[i];
|
179
|
+
final Object[] result = new Object[params.length];
|
180
|
+
for(int k = 0; k < result.length; k++) {
|
181
|
+
result[k] = params[k][best[k]];
|
182
|
+
}
|
183
|
+
removeMatches(i);
|
184
|
+
return result;
|
185
|
+
}
|
186
|
+
|
187
|
+
private void removeMatches(final int i) {
|
188
|
+
final int[] cases = scratch[i];
|
189
|
+
final ListIterator<Pair[]> iter = coverage.listIterator(0);
|
190
|
+
while(iter.hasNext()) {
|
191
|
+
if(match(iter.next(), cases)) {
|
192
|
+
iter.remove();
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
private void generate(final int i) {
|
198
|
+
for(int j = 0; j < params.length; j++) {
|
199
|
+
scratch[i][j] = random.nextInt(params[j].length);
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
private void fitness(final int i) {
|
204
|
+
final int[] cases = scratch[i];
|
205
|
+
if(constraints.length > 0) {
|
206
|
+
for(final Pair pair : coverage.get(0)) {
|
207
|
+
cases[pair.i] = pair.j;
|
208
|
+
}
|
209
|
+
}
|
210
|
+
for(final Pair[] constraint : constraints) {
|
211
|
+
int count = 0;
|
212
|
+
for(final Pair pair : constraint) {
|
213
|
+
if(pair.j == cases[pair.i]) {
|
214
|
+
count++;
|
215
|
+
}
|
216
|
+
}
|
217
|
+
if(count == constraint.length) {
|
218
|
+
fitness[i] = -1;
|
219
|
+
return;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
int count = 0;
|
223
|
+
for(final Pair[] pairs : coverage) {
|
224
|
+
if(match(pairs, cases)) {
|
225
|
+
count++;
|
226
|
+
}
|
227
|
+
}
|
228
|
+
fitness[i] = count;
|
229
|
+
}
|
230
|
+
|
231
|
+
private int bestFit() {
|
232
|
+
int index = 0;
|
233
|
+
int max = 0;
|
234
|
+
for(int i = 0; i < fitness.length; i++) {
|
235
|
+
final int value = fitness[i];
|
236
|
+
if(value > max) {
|
237
|
+
max = value;
|
238
|
+
index = i;
|
239
|
+
}
|
240
|
+
}
|
241
|
+
return index;
|
242
|
+
}
|
243
|
+
|
244
|
+
private interface AtegRandom {
|
245
|
+
int nextInt(int a);
|
246
|
+
}
|
247
|
+
|
248
|
+
private static boolean match(final Pair[] pairs, final int[] cases) {
|
249
|
+
boolean flag = true;
|
250
|
+
for(final Pair pair : pairs) {
|
251
|
+
if(cases[pair.i] != pair.j) {
|
252
|
+
flag = false;
|
253
|
+
break;
|
254
|
+
}
|
255
|
+
}
|
256
|
+
return flag;
|
257
|
+
}
|
258
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
package com.github.jesg.dither;
|
2
|
+
|
3
|
+
/*
|
4
|
+
* #%L
|
5
|
+
* dither
|
6
|
+
* %%
|
7
|
+
* Copyright (C) 2015 Jason Gowan
|
8
|
+
* %%
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
* you may not use this file except in compliance with the License.
|
11
|
+
* You may obtain a copy of the License at
|
12
|
+
*
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
*
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
* See the License for the specific language governing permissions and
|
19
|
+
* limitations under the License.
|
20
|
+
* #L%
|
21
|
+
*/
|
22
|
+
|
23
|
+
import java.util.Comparator;
|
24
|
+
|
25
|
+
class ArrayLengthComparator implements Comparator<IndexArrayPair> {
|
26
|
+
|
27
|
+
public int compare(IndexArrayPair arg1, IndexArrayPair arg2) {
|
28
|
+
return -Integer.compare(arg1.getArr().length, arg2.getArr().length);
|
29
|
+
}
|
30
|
+
}
|
@@ -0,0 +1,143 @@
|
|
1
|
+
package com.github.jesg.dither;
|
2
|
+
|
3
|
+
/*
|
4
|
+
* #%L
|
5
|
+
* dither
|
6
|
+
* %%
|
7
|
+
* Copyright (C) 2015 Jason Gowan
|
8
|
+
* %%
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
* you may not use this file except in compliance with the License.
|
11
|
+
* You may obtain a copy of the License at
|
12
|
+
*
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
*
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
* See the License for the specific language governing permissions and
|
19
|
+
* limitations under the License.
|
20
|
+
* #L%
|
21
|
+
*/
|
22
|
+
|
23
|
+
import java.util.ArrayList;
|
24
|
+
import java.util.Arrays;
|
25
|
+
import java.util.List;
|
26
|
+
|
27
|
+
class CombinatoricHelper {
|
28
|
+
|
29
|
+
public static List<int[]> getCombinations(final int n, final int[] input) {
|
30
|
+
final List<int[]> result = new ArrayList<int[]>();
|
31
|
+
final int[] scratch = new int[n];
|
32
|
+
|
33
|
+
if (n <= input.length) {
|
34
|
+
for (int i = 0; (scratch[i] = i) < n - 1; i++)
|
35
|
+
;
|
36
|
+
result.add(_getCombinations(input, scratch));
|
37
|
+
for (;;) {
|
38
|
+
int i;
|
39
|
+
for (i = n - 1; i >= 0 && scratch[i] == input.length - n + i; i--)
|
40
|
+
;
|
41
|
+
if (i < 0) {
|
42
|
+
break;
|
43
|
+
} else {
|
44
|
+
scratch[i]++;
|
45
|
+
for (++i; i < n; i++) {
|
46
|
+
scratch[i] = scratch[i - 1] + 1;
|
47
|
+
}
|
48
|
+
result.add(_getCombinations(input, scratch));
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
return result;
|
54
|
+
}
|
55
|
+
|
56
|
+
private static int[] _getCombinations(final int[] input, final int[] scratch) {
|
57
|
+
final int[] result = new int[scratch.length];
|
58
|
+
for (int i = 0; i < scratch.length; i++) {
|
59
|
+
result[i] = input[scratch[i]];
|
60
|
+
}
|
61
|
+
return result;
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
public static <T> List<List<T>> product(final T[][] args) {
|
66
|
+
final int[] tmp = new int[args.length];
|
67
|
+
for(int i = 0; i < tmp.length; i++) {
|
68
|
+
tmp[i] = args[i].length;
|
69
|
+
}
|
70
|
+
|
71
|
+
final int[][] solution = product(tmp);
|
72
|
+
final List<List<T>> results = new ArrayList<List<T>>(solution.length);
|
73
|
+
for(int i = 0; i < solution.length; i++) {
|
74
|
+
final List<T> inner = new ArrayList<T>(args.length);
|
75
|
+
results.add(i, inner);
|
76
|
+
for(int j = 0; j < args.length; j++) {
|
77
|
+
results.get(i).add(j, args[j][solution[i][j]]);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
return results;
|
81
|
+
}
|
82
|
+
|
83
|
+
public static int[][] product(final int[] ranges) {
|
84
|
+
int length = 1;
|
85
|
+
for(int i = 0; i < ranges.length; i++) {
|
86
|
+
length *= ranges[i];
|
87
|
+
--ranges[i];
|
88
|
+
}
|
89
|
+
|
90
|
+
final int[][] results = new int[length][ranges.length];
|
91
|
+
final int[] scratch = new int[ranges.length];
|
92
|
+
|
93
|
+
int k = 0;
|
94
|
+
final int max = ranges.length - 1;
|
95
|
+
for(int i = max;;) {
|
96
|
+
|
97
|
+
if(i == max) {
|
98
|
+
for(int val = 0; val <= ranges[i]; val++) {
|
99
|
+
for(int j = 0; j < scratch.length; j++) {
|
100
|
+
results[k][j] = scratch[j];
|
101
|
+
}
|
102
|
+
k++;
|
103
|
+
scratch[i]++;
|
104
|
+
}
|
105
|
+
scratch[i] = 0;
|
106
|
+
i--;
|
107
|
+
} else if(i == 0 && scratch[i] >= ranges[i]) {
|
108
|
+
return results;
|
109
|
+
} else if(scratch[i] < ranges[i]) {
|
110
|
+
scratch[i]++;
|
111
|
+
i++;
|
112
|
+
} else {
|
113
|
+
scratch[i] = -1;
|
114
|
+
i--;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
private static int[][] _product(final int left, final int right) {
|
120
|
+
final int[][] result = new int[left * right][];
|
121
|
+
int k = 0;
|
122
|
+
for (int i = 0; i < left; i++) {
|
123
|
+
for (int j = 0; j < right; j++) {
|
124
|
+
result[k] = new int[] { i, j };
|
125
|
+
k++;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
return result;
|
129
|
+
}
|
130
|
+
|
131
|
+
private static int[][] _product(final int[][] left, final int right) {
|
132
|
+
final int[][] result = new int[left.length * right][];
|
133
|
+
int k = 0;
|
134
|
+
for (int i = 0; i < left.length; i++) {
|
135
|
+
for (int j = 0; j < right; j++) {
|
136
|
+
result[k] = Arrays.copyOf(left[i], left[i].length + 1);
|
137
|
+
result[k][left[i].length] = j;
|
138
|
+
k++;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
return result;
|
142
|
+
}
|
143
|
+
}
|
@@ -0,0 +1,120 @@
|
|
1
|
+
package com.github.jesg.dither;
|
2
|
+
|
3
|
+
import java.util.Arrays;
|
4
|
+
|
5
|
+
/*
|
6
|
+
* #%L
|
7
|
+
* dither
|
8
|
+
* %%
|
9
|
+
* Copyright (C) 2015 Jason Gowan
|
10
|
+
* %%
|
11
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
12
|
+
* you may not use this file except in compliance with the License.
|
13
|
+
* You may obtain a copy of the License at
|
14
|
+
*
|
15
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
16
|
+
*
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
20
|
+
* See the License for the specific language governing permissions and
|
21
|
+
* limitations under the License.
|
22
|
+
* #L%
|
23
|
+
*/
|
24
|
+
|
25
|
+
import java.util.Comparator;
|
26
|
+
|
27
|
+
class ConstraintHandler {
|
28
|
+
|
29
|
+
private final Pair[][] constraints;
|
30
|
+
private final int[] bounds;
|
31
|
+
private final int[] scratch;
|
32
|
+
|
33
|
+
ConstraintHandler(final Pair[][] constraints, final int[] bounds) {
|
34
|
+
this.constraints = constraints;
|
35
|
+
this.bounds = new int[bounds.length];
|
36
|
+
this.scratch = new int[bounds.length];
|
37
|
+
for(int i = 0; i < bounds.length; i++) {
|
38
|
+
this.bounds[i] = bounds[i] - 1;
|
39
|
+
}
|
40
|
+
Arrays.fill(scratch, -1);
|
41
|
+
Arrays.sort(this.constraints, new Comparator<Pair[]>() {
|
42
|
+
public int compare(final Pair[] a, final Pair[] b) { return a.length - b.length; }
|
43
|
+
});
|
44
|
+
}
|
45
|
+
|
46
|
+
boolean violateConstraints_(final int[] testCase) {
|
47
|
+
outer:
|
48
|
+
for(final Pair[] pairs : constraints) {
|
49
|
+
for(final Pair pair : pairs) {
|
50
|
+
final int value = testCase[pair.i];
|
51
|
+
if(value == -1 || value != pair.j) {
|
52
|
+
continue outer;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
return true;
|
56
|
+
}
|
57
|
+
return false;
|
58
|
+
}
|
59
|
+
|
60
|
+
boolean violateConstraints(final int[] solution) {
|
61
|
+
if(violateConstraints_(solution)) {
|
62
|
+
return true;
|
63
|
+
}
|
64
|
+
for(int i = 0; i < solution.length; i++) {
|
65
|
+
scratch[i] = solution[i];
|
66
|
+
}
|
67
|
+
return groundSolution(scratch) == null;
|
68
|
+
}
|
69
|
+
|
70
|
+
boolean violateConstraints(final Pair[] pairs) {
|
71
|
+
Arrays.fill(scratch, -1);
|
72
|
+
for(int i = 0; i < pairs.length; i++) {
|
73
|
+
final Pair pair = pairs[i];
|
74
|
+
scratch[pair.i] = pair.j;
|
75
|
+
}
|
76
|
+
if(violateConstraints_(scratch)) {
|
77
|
+
return true;
|
78
|
+
}
|
79
|
+
return groundSolution(scratch) == null;
|
80
|
+
}
|
81
|
+
|
82
|
+
// return null if unable to find a solution
|
83
|
+
int[] groundSolution(final int[] solution) {
|
84
|
+
final int[] indexes = new int[solution.length];
|
85
|
+
int last_index = 0;
|
86
|
+
for(int i = 0; i < solution.length; i++) {
|
87
|
+
if(solution[i] == -1) {
|
88
|
+
indexes[last_index] = i;
|
89
|
+
++last_index;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
final int[] bound_values = new int[last_index + 1];
|
93
|
+
Arrays.fill(bound_values, -1);
|
94
|
+
int i = 0;
|
95
|
+
|
96
|
+
outer:
|
97
|
+
while(i < bound_values.length) {
|
98
|
+
final int max = bounds[indexes[i]];
|
99
|
+
for(int value = bound_values[i] + 1; value <= max; value++) {
|
100
|
+
solution[indexes[i]] = value;
|
101
|
+
if(violateConstraints_(solution)) {
|
102
|
+
continue;
|
103
|
+
}
|
104
|
+
bound_values[i] = value;
|
105
|
+
++i;
|
106
|
+
continue outer;
|
107
|
+
}
|
108
|
+
|
109
|
+
if(i == 0) {
|
110
|
+
return null;
|
111
|
+
}
|
112
|
+
|
113
|
+
// unwind
|
114
|
+
bound_values[i] = -1;
|
115
|
+
solution[indexes[i]] = -1;
|
116
|
+
--i;
|
117
|
+
}
|
118
|
+
return solution;
|
119
|
+
}
|
120
|
+
}
|