dither 0.2.2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.rb +1 -2
- data/lib/dither/version.rb +1 -1
- metadata +13 -3
@@ -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
|
+
}
|
@@ -0,0 +1,155 @@
|
|
1
|
+
package com.github.jesg.dither;
|
2
|
+
|
3
|
+
import java.util.Collections;
|
4
|
+
import java.util.List;
|
5
|
+
import java.util.concurrent.ExecutorService;
|
6
|
+
import java.util.concurrent.Executors;
|
7
|
+
|
8
|
+
/*
|
9
|
+
* #%L
|
10
|
+
* dither
|
11
|
+
* %%
|
12
|
+
* Copyright (C) 2015 Jason Gowan
|
13
|
+
* %%
|
14
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
15
|
+
* you may not use this file except in compliance with the License.
|
16
|
+
* You may obtain a copy of the License at
|
17
|
+
*
|
18
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
19
|
+
*
|
20
|
+
* Unless required by applicable law or agreed to in writing, software
|
21
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
22
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
23
|
+
* See the License for the specific language governing permissions and
|
24
|
+
* limitations under the License.
|
25
|
+
* #L%
|
26
|
+
*/
|
27
|
+
|
28
|
+
public class Dither {
|
29
|
+
|
30
|
+
public static final Integer[][] EMPTY_CONSTRAINTS = new Integer[][]{};
|
31
|
+
public static final Object[][] EMPTY_PREVIOUSLY_TESTED = new Object[][]{};
|
32
|
+
|
33
|
+
public static Object[][] ipog(final int t, final Object[][] params, final Integer[][] constraints, final Object[][] previouslyTested)
|
34
|
+
throws DitherError {
|
35
|
+
validateInput(t, params);
|
36
|
+
return new Ipog(params, t, constraints, previouslyTested).run();
|
37
|
+
}
|
38
|
+
|
39
|
+
public static Object[][] ipog(final int t, final Object[][] params, final Integer[][] constraints)
|
40
|
+
throws DitherError {
|
41
|
+
validateInput(t, params);
|
42
|
+
return new Ipog(params, t, constraints, EMPTY_PREVIOUSLY_TESTED).run();
|
43
|
+
}
|
44
|
+
|
45
|
+
public static Object[][] ipog(final int t, final Object[][] params)
|
46
|
+
throws DitherError {
|
47
|
+
validateInput(t, params);
|
48
|
+
return new Ipog(params, t, EMPTY_CONSTRAINTS, EMPTY_PREVIOUSLY_TESTED).run();
|
49
|
+
}
|
50
|
+
|
51
|
+
public static Object[][] ipog(final Object[][] params)
|
52
|
+
throws DitherError {
|
53
|
+
validateInput(2, params);
|
54
|
+
return new Ipog(params, 2, EMPTY_CONSTRAINTS, EMPTY_PREVIOUSLY_TESTED).run();
|
55
|
+
}
|
56
|
+
|
57
|
+
public static Object[][] ipog(final int t, final Object[] params, final Object[] constraints, final Object[] previouslyTested)
|
58
|
+
throws DitherError {
|
59
|
+
final Object[][] innerParams = new Object[params.length][];
|
60
|
+
for(int i = 0; i < innerParams.length; i++) {
|
61
|
+
innerParams[i] = (Object[]) params[i];
|
62
|
+
}
|
63
|
+
validateInput(t, innerParams);
|
64
|
+
|
65
|
+
final Integer[][] innerConstraints = new Integer[constraints.length][];
|
66
|
+
for(int i = 0; i < innerConstraints.length; i++) {
|
67
|
+
innerConstraints[i] = (Integer[]) constraints[i];
|
68
|
+
}
|
69
|
+
|
70
|
+
final Object[][] innerPerviouslyTested = new Object[previouslyTested.length][];
|
71
|
+
for(int i = 0; i < innerPerviouslyTested.length; i++) {
|
72
|
+
innerPerviouslyTested[i] = (Object[]) previouslyTested[i];
|
73
|
+
}
|
74
|
+
|
75
|
+
return new Ipog(innerParams, t, innerConstraints, innerPerviouslyTested).run();
|
76
|
+
}
|
77
|
+
|
78
|
+
@Deprecated
|
79
|
+
public static Object[][] ateg(final Object[][] params)
|
80
|
+
throws DitherError {
|
81
|
+
return aetg(params);
|
82
|
+
}
|
83
|
+
|
84
|
+
public static Object[][] aetg(final Object[][] params)
|
85
|
+
throws DitherError {
|
86
|
+
return aetg(2, params);
|
87
|
+
}
|
88
|
+
|
89
|
+
@Deprecated
|
90
|
+
public static Object[][] ateg(final int t, final Object[][] params) {
|
91
|
+
return aetg(t, params);
|
92
|
+
}
|
93
|
+
|
94
|
+
public static Object[][] aetg(final int t, final Object[][] params) {
|
95
|
+
return aetg(t, null, params, EMPTY_CONSTRAINTS, EMPTY_PREVIOUSLY_TESTED);
|
96
|
+
}
|
97
|
+
|
98
|
+
@Deprecated
|
99
|
+
public static Object[][] ateg(final int t, final Integer seed, final Object[][] params, final Integer[][] constraints, final Object[][] previouslyTested)
|
100
|
+
throws DitherError {
|
101
|
+
return aetg(t, seed, params, constraints, previouslyTested);
|
102
|
+
}
|
103
|
+
|
104
|
+
public static Object[][] aetg(final int t, final Integer seed, final Object[][] params, final Integer[][] constraints, final Object[][] previouslyTested)
|
105
|
+
throws DitherError {
|
106
|
+
validateInput(t, params);
|
107
|
+
final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
108
|
+
Object[][] result = new Object[][]{};
|
109
|
+
try {
|
110
|
+
result = new AetgPairwise(t, seed, params, constraints, previouslyTested, executor).toArray();
|
111
|
+
} finally {
|
112
|
+
executor.shutdownNow();
|
113
|
+
}
|
114
|
+
return result;
|
115
|
+
}
|
116
|
+
|
117
|
+
@Deprecated
|
118
|
+
public static Object[][] ateg(final int t, final Integer seed, final Object[] params, final Object[] constraints, final Object[] previouslyTested) {
|
119
|
+
return aetg(t, seed, params, constraints, previouslyTested);
|
120
|
+
}
|
121
|
+
|
122
|
+
public static Object[][] aetg(final int t, final Integer seed, final Object[] params, final Object[] constraints, final Object[] previouslyTested) {
|
123
|
+
final Object[][] innerParams = new Object[params.length][];
|
124
|
+
for(int i = 0; i < innerParams.length; i++) {
|
125
|
+
innerParams[i] = (Object[]) params[i];
|
126
|
+
}
|
127
|
+
validateInput(t, innerParams);
|
128
|
+
|
129
|
+
final Integer[][] innerConstraints = new Integer[constraints.length][];
|
130
|
+
for(int i = 0; i < innerConstraints.length; i++) {
|
131
|
+
innerConstraints[i] = (Integer[]) constraints[i];
|
132
|
+
}
|
133
|
+
|
134
|
+
final Object[][] innerPerviouslyTested = new Object[previouslyTested.length][];
|
135
|
+
for(int i = 0; i < innerPerviouslyTested.length; i++) {
|
136
|
+
innerPerviouslyTested[i] = (Object[]) previouslyTested[i];
|
137
|
+
}
|
138
|
+
return aetg(t, seed, innerParams, innerConstraints, innerPerviouslyTested);
|
139
|
+
}
|
140
|
+
|
141
|
+
private static void validateInput(final int t, final Object[][] params) throws DitherError {
|
142
|
+
if (t <= 1) {
|
143
|
+
throw new DitherError("t must be >= 2");
|
144
|
+
}
|
145
|
+
|
146
|
+
if (t > params.length) {
|
147
|
+
throw new DitherError("t must be <= params.length");
|
148
|
+
}
|
149
|
+
for (final Object[] param : params) {
|
150
|
+
if (param.length < 2) {
|
151
|
+
throw new DitherError("param length must be > 1");
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
@@ -0,0 +1,45 @@
|
|
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
|
+
public class DitherError extends RuntimeException {
|
24
|
+
|
25
|
+
public DitherError() {
|
26
|
+
super();
|
27
|
+
}
|
28
|
+
|
29
|
+
public DitherError(String message, Throwable cause,
|
30
|
+
boolean enableSuppression, boolean writableStackTrace) {
|
31
|
+
super(message, cause, enableSuppression, writableStackTrace);
|
32
|
+
}
|
33
|
+
|
34
|
+
public DitherError(String message, Throwable cause) {
|
35
|
+
super(message, cause);
|
36
|
+
}
|
37
|
+
|
38
|
+
public DitherError(String message) {
|
39
|
+
super(message);
|
40
|
+
}
|
41
|
+
|
42
|
+
public DitherError(Throwable cause) {
|
43
|
+
super(cause);
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1,40 @@
|
|
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
|
+
class IndexArrayPair {
|
24
|
+
|
25
|
+
private final int i;
|
26
|
+
private final Object[] arr;
|
27
|
+
|
28
|
+
public IndexArrayPair(final int i, final Object[] arr) {
|
29
|
+
this.i = i;
|
30
|
+
this.arr = arr;
|
31
|
+
}
|
32
|
+
|
33
|
+
public int getI() {
|
34
|
+
return i;
|
35
|
+
}
|
36
|
+
|
37
|
+
public Object[] getArr() {
|
38
|
+
return arr;
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,405 @@
|
|
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.HashMap;
|
26
|
+
import java.util.LinkedList;
|
27
|
+
import java.util.List;
|
28
|
+
import java.util.ListIterator;
|
29
|
+
import java.util.Map;
|
30
|
+
|
31
|
+
class Ipog {
|
32
|
+
|
33
|
+
private final int t;
|
34
|
+
private final Object[][] inputParams;
|
35
|
+
private final Map<Integer, Integer> origIndex = new HashMap<Integer, Integer>();
|
36
|
+
private final Map<Integer, Integer> inverseOrigIndex = new HashMap<Integer, Integer>();
|
37
|
+
private final Pair[][] constraints;
|
38
|
+
private final int[][] previouslyTested;
|
39
|
+
private final Pair[][] pairCache;
|
40
|
+
private final int[] mergeScratch;
|
41
|
+
private final ConstraintHandler constraintHandler;
|
42
|
+
|
43
|
+
public Ipog(final Object[][] input, final int t) {
|
44
|
+
this(input, t, new Integer[][] {}, new Object[][] {});
|
45
|
+
}
|
46
|
+
|
47
|
+
public Ipog(final Object[][] input, final int t,
|
48
|
+
final Integer[][] constraints, final Object[][] tested) {
|
49
|
+
this.t = t;
|
50
|
+
this.inputParams = input;
|
51
|
+
this.mergeScratch = new int[input.length];
|
52
|
+
this.previouslyTested = new int[tested.length][input.length];
|
53
|
+
|
54
|
+
// sort input params and create a shared object pool
|
55
|
+
final IndexArrayPair[] tmp = new IndexArrayPair[input.length];
|
56
|
+
for (int k = 0; k < tmp.length; k++) {
|
57
|
+
tmp[k] = new IndexArrayPair(k, input[k]);
|
58
|
+
}
|
59
|
+
Arrays.sort(tmp, new ArrayLengthComparator());
|
60
|
+
final Map<Integer, Map<Object, Pair>> origParamMap = new HashMap<Integer, Map<Object, Pair>>();
|
61
|
+
this.pairCache = new Pair[tmp.length][];
|
62
|
+
for (int k = 0; k < tmp.length; k++) {
|
63
|
+
this.origIndex.put(k, tmp[k].getI());
|
64
|
+
this.inverseOrigIndex.put(tmp[k].getI(), k);
|
65
|
+
this.pairCache[k] = new Pair[tmp[k].getArr().length];
|
66
|
+
|
67
|
+
origParamMap.put(tmp[k].getI(),
|
68
|
+
new HashMap<Object, Pair>());
|
69
|
+
for (int h = 0; h < this.pairCache[k].length; h++) {
|
70
|
+
this.pairCache[k][h] = new Pair(k, h);
|
71
|
+
origParamMap.get(tmp[k].getI()).put(tmp[k].getArr()[h],
|
72
|
+
this.pairCache[k][h]);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
for (int j = 0; j < previouslyTested.length; j++) {
|
77
|
+
final Object[] innerTestCase = tested[j];
|
78
|
+
for (int k = 0; k < innerTestCase.length; k++) {
|
79
|
+
previouslyTested[j][k] = origParamMap.get(k).get(innerTestCase[k]).j;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
// setup constraints
|
84
|
+
this.constraints = new Pair[constraints.length][];
|
85
|
+
for (int i = 0; i < constraints.length; i++) {
|
86
|
+
final Integer[] constraint = constraints[i];
|
87
|
+
final List<Pair> tmpConstraint = new ArrayList<Pair>(constraint.length);
|
88
|
+
|
89
|
+
for (int k = 0; k < constraint.length; k++) {
|
90
|
+
if (constraint[k] != null) {
|
91
|
+
tmpConstraint.add(pairCache[inverseOrigIndex.get(k)][constraint[k]]);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
this.constraints[i] = tmpConstraint.toArray(new Pair[]{});
|
95
|
+
}
|
96
|
+
final int[] bounds = new int[pairCache.length];
|
97
|
+
for(int i = 0; i < bounds.length; i++) {
|
98
|
+
bounds[i] = pairCache[i].length;
|
99
|
+
}
|
100
|
+
this.constraintHandler = new ConstraintHandler(this.constraints, bounds);
|
101
|
+
}
|
102
|
+
|
103
|
+
List<int[]> allCombinations() {
|
104
|
+
|
105
|
+
final int[] prodarr = new int[t];
|
106
|
+
for (int k = 0; k < prodarr.length; k++) {
|
107
|
+
prodarr[k] = pairCache[k].length;
|
108
|
+
}
|
109
|
+
|
110
|
+
final int[][] prodArrResult = CombinatoricHelper.product(prodarr);
|
111
|
+
|
112
|
+
final List<int[]> results = new LinkedList<int[]>();
|
113
|
+
for(int i = 0; i < prodArrResult.length; i++) {
|
114
|
+
final int[] result = Arrays.copyOf(prodArrResult[i], pairCache.length);
|
115
|
+
Arrays.fill(result, t, result.length, -1);
|
116
|
+
if(!hasTested(t, result)) {
|
117
|
+
results.add(result);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
return results;
|
121
|
+
}
|
122
|
+
|
123
|
+
List<Pair[]> combinations(final int i) {
|
124
|
+
final int[] innerParams = new int[i];
|
125
|
+
for (int k = 0; k < innerParams.length; k++) {
|
126
|
+
innerParams[k] = k;
|
127
|
+
}
|
128
|
+
|
129
|
+
final List<int[]> combinations = CombinatoricHelper.getCombinations(
|
130
|
+
t - 1, innerParams);
|
131
|
+
final List<int[]> combt = new ArrayList<int[]>(combinations.size());
|
132
|
+
for (int k = 0; k < combinations.size(); k++) {
|
133
|
+
final int[] newArr = Arrays.copyOf(combinations.get(k), t);
|
134
|
+
newArr[t - 1] = i;
|
135
|
+
combt.add(newArr);
|
136
|
+
}
|
137
|
+
|
138
|
+
final List<Pair[]> results = new LinkedList<Pair[]>();
|
139
|
+
for (final int[] comb : combt) {
|
140
|
+
|
141
|
+
final int[] prodarr = new int[comb.length];
|
142
|
+
for (int k = 0; k < prodarr.length; k++) {
|
143
|
+
prodarr[k] = pairCache[comb[k]].length;
|
144
|
+
}
|
145
|
+
|
146
|
+
final int[][] prodArrResult = CombinatoricHelper.product(prodarr);
|
147
|
+
|
148
|
+
for (int j = 0; j < prodArrResult.length; j++) {
|
149
|
+
final int[] innerArr = prodArrResult[j];
|
150
|
+
final Pair[] pairs = new Pair[innerArr.length];
|
151
|
+
for (int k = 0; k < innerArr.length; k++) {
|
152
|
+
pairs[k] = pairCache[comb[k]][innerArr[k]];
|
153
|
+
}
|
154
|
+
if (!hasTested(pairs)) {
|
155
|
+
results.add(pairs);
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
return results;
|
161
|
+
}
|
162
|
+
|
163
|
+
private boolean hasTested(final int[] testCase) {
|
164
|
+
for (final int[] innerCase : previouslyTested) {
|
165
|
+
if(Arrays.equals(testCase, innerCase)) {
|
166
|
+
return true;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
|
172
|
+
private boolean hasTested(final int t, final int[] testCase) {
|
173
|
+
outer:
|
174
|
+
for (final int[] innerCase : previouslyTested) {
|
175
|
+
for(int i = 0; i < t; i++) {
|
176
|
+
if(innerCase[i] != testCase[i]) {
|
177
|
+
continue outer;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
return true;
|
181
|
+
}
|
182
|
+
return false;
|
183
|
+
}
|
184
|
+
|
185
|
+
private boolean hasTested(final Pair[] testCase) {
|
186
|
+
outer:
|
187
|
+
for (final int[] innerCase : previouslyTested) {
|
188
|
+
for(final Pair pair : testCase) {
|
189
|
+
if(innerCase[pair.i] != pair.j) {
|
190
|
+
continue outer;
|
191
|
+
}
|
192
|
+
}
|
193
|
+
return true;
|
194
|
+
}
|
195
|
+
return false;
|
196
|
+
}
|
197
|
+
|
198
|
+
Object[][] run() {
|
199
|
+
final List<int[]> testSet = allCombinations();
|
200
|
+
final List<int[]> unbound = new LinkedList<int[]>();
|
201
|
+
for (int k = t; k < pairCache.length; k++) {
|
202
|
+
final List<Pair[]> pi = combinations(k);
|
203
|
+
|
204
|
+
// horizontal extension for parameter i
|
205
|
+
final ListIterator<int[]> iterTestSet = testSet.listIterator();
|
206
|
+
while(iterTestSet.hasNext()) {
|
207
|
+
final int[] testCase = iterTestSet.next();
|
208
|
+
final int max = maximizeCoverage(k,
|
209
|
+
testCase, pi);
|
210
|
+
if(max < 0) {
|
211
|
+
iterTestSet.remove();
|
212
|
+
} else {
|
213
|
+
// remove matches
|
214
|
+
final ListIterator<Pair[]> iter = pi.listIterator();
|
215
|
+
iter:
|
216
|
+
while(iter.hasNext()) {
|
217
|
+
for(final Pair pair : iter.next()) {
|
218
|
+
if(testCase[pair.i] != pair.j) {
|
219
|
+
continue iter;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
iter.remove();
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
// vertical extension for parameter i
|
228
|
+
final ListIterator<Pair[]> piIter = pi.listIterator();
|
229
|
+
while (piIter.hasNext()) {
|
230
|
+
final Pair[] testCase = piIter.next();
|
231
|
+
// remove constraint violation
|
232
|
+
boolean isCaseCovered = violateConstraints(testCase);
|
233
|
+
if(!isCaseCovered) {
|
234
|
+
for (final int[] innerTestCase : testSet) {
|
235
|
+
boolean match = true;
|
236
|
+
for(final Pair pair : testCase) {
|
237
|
+
if(innerTestCase[pair.i] != pair.j) {
|
238
|
+
match = false;
|
239
|
+
break;
|
240
|
+
}
|
241
|
+
}
|
242
|
+
if(match) {
|
243
|
+
isCaseCovered = true;
|
244
|
+
break;
|
245
|
+
}
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
if (!isCaseCovered) {
|
250
|
+
final ListIterator<int[]> unboundIter = unbound.listIterator();
|
251
|
+
boolean isMerged = false;
|
252
|
+
int[] innerTestCase = null;
|
253
|
+
while(unboundIter.hasNext()) {
|
254
|
+
innerTestCase = unboundIter.next();
|
255
|
+
// -1 => no merge, 0 perfect merge (no unbound), 1 partial merge
|
256
|
+
final int mergeResult = merge(k, testCase, innerTestCase);
|
257
|
+
if(mergeResult == 0) {
|
258
|
+
unboundIter.remove();
|
259
|
+
testSet.add(innerTestCase);
|
260
|
+
isMerged = true;
|
261
|
+
break;
|
262
|
+
} else if(mergeResult == 1) {
|
263
|
+
isMerged = true;
|
264
|
+
break;
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
268
|
+
if (!isMerged) {
|
269
|
+
final int[] unboundTestCase = new int[pairCache.length];
|
270
|
+
Arrays.fill(unboundTestCase, -1);
|
271
|
+
for(final Pair pair : testCase) {
|
272
|
+
unboundTestCase[pair.i] = pair.j;
|
273
|
+
}
|
274
|
+
if(!violateConstraints(unboundTestCase)) {
|
275
|
+
unbound.add(unboundTestCase);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
}
|
279
|
+
piIter.remove();
|
280
|
+
}
|
281
|
+
}
|
282
|
+
return testSetToArray(testSet, unbound);
|
283
|
+
}
|
284
|
+
|
285
|
+
// -1 no merge, 0 perfect merge (no unbound), 1 partial merge
|
286
|
+
public int merge(final int k, final Pair[] pairs, final int[] testCase) {
|
287
|
+
// verify merge
|
288
|
+
for(final Pair pair : pairs) {
|
289
|
+
int value = testCase[pair.i];
|
290
|
+
if(!(value == -1 || value == pair.j)) {
|
291
|
+
return -1;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
for(int i = 0; i < mergeScratch.length; i++) {
|
296
|
+
mergeScratch[i] = testCase[i];
|
297
|
+
}
|
298
|
+
|
299
|
+
for(final Pair pair : pairs) {
|
300
|
+
mergeScratch[pair.i] = pair.j;
|
301
|
+
}
|
302
|
+
|
303
|
+
if(violateConstraints(mergeScratch)) {
|
304
|
+
return -1;
|
305
|
+
}
|
306
|
+
|
307
|
+
// merge
|
308
|
+
for(final Pair pair : pairs) {
|
309
|
+
testCase[pair.i] = pair.j;
|
310
|
+
}
|
311
|
+
|
312
|
+
// find unbound
|
313
|
+
for(int i = 0; i < k; i++) {
|
314
|
+
if(testCase[i] == -1) { return 1; }
|
315
|
+
}
|
316
|
+
return 0;
|
317
|
+
}
|
318
|
+
|
319
|
+
private Object[][] testSetToArray(final List<int[]> testSet, final List<int[]> unbound) {
|
320
|
+
|
321
|
+
final List<Object[]> results = new ArrayList<Object[]>(testSet.size() + unbound.size());
|
322
|
+
for(final int[] boundResult : testSet) {
|
323
|
+
final Object[] result = new Object[boundResult.length];
|
324
|
+
for (int k = 0; k < boundResult.length; k++) {
|
325
|
+
final int value = boundResult[k];
|
326
|
+
final int i = origIndex.get(k);
|
327
|
+
result[i] = inputParams[i][value];
|
328
|
+
}
|
329
|
+
if(!violateConstraints(boundResult) && !hasTested(boundResult)) {
|
330
|
+
results.add(result);
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
outer:
|
335
|
+
for(final int[] unboundResult : unbound) {
|
336
|
+
final Object[] result = new Object[unboundResult.length];
|
337
|
+
final int[] groundResult = constraintHandler.groundSolution(unboundResult);
|
338
|
+
if(groundResult == null) {
|
339
|
+
continue outer;
|
340
|
+
}
|
341
|
+
for(int k = 0; k < unboundResult.length; k++) {
|
342
|
+
final int i = origIndex.get(k);
|
343
|
+
final int value = groundResult[k];
|
344
|
+
result[i] = inputParams[i][value];
|
345
|
+
}
|
346
|
+
if(!hasTested(unboundResult)) {
|
347
|
+
results.add(result);
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
return results.toArray(new Object[][]{});
|
352
|
+
}
|
353
|
+
|
354
|
+
boolean violateConstraints(final int[] testCase) {
|
355
|
+
if(constraints.length == 0) {
|
356
|
+
return false;
|
357
|
+
}
|
358
|
+
return constraintHandler.violateConstraints(testCase);
|
359
|
+
}
|
360
|
+
|
361
|
+
boolean violateConstraints(final Pair[] testCase) {
|
362
|
+
if(constraints.length == 0) {
|
363
|
+
return false;
|
364
|
+
}
|
365
|
+
return constraintHandler.violateConstraints(testCase);
|
366
|
+
}
|
367
|
+
|
368
|
+
private int maximizeCoverage(final int i,
|
369
|
+
final int[] testCase, final List<Pair[]> pi) {
|
370
|
+
int currentMax = -1;
|
371
|
+
int currentJ = 0;
|
372
|
+
|
373
|
+
for (int j = 0; j < pairCache[i].length; j++) {
|
374
|
+
final Pair currentPair = pairCache[i][j];
|
375
|
+
testCase[currentPair.i] = currentPair.j;
|
376
|
+
|
377
|
+
if (!violateConstraints(testCase)) {
|
378
|
+
int count = 0;
|
379
|
+
outer:
|
380
|
+
for (final Pair[] innerTestCase : pi) {
|
381
|
+
for(final Pair pair : innerTestCase) {
|
382
|
+
if (testCase[pair.i] != pair.j) {
|
383
|
+
continue outer;
|
384
|
+
}
|
385
|
+
}
|
386
|
+
count++;
|
387
|
+
}
|
388
|
+
|
389
|
+
if (count > currentMax) {
|
390
|
+
currentMax = count;
|
391
|
+
currentJ = j;
|
392
|
+
}
|
393
|
+
}
|
394
|
+
testCase[i] = -1;
|
395
|
+
}
|
396
|
+
|
397
|
+
if (currentMax == -1) {
|
398
|
+
return -1;
|
399
|
+
}
|
400
|
+
|
401
|
+
final Pair pair = pairCache[i][currentJ];
|
402
|
+
testCase[pair.i] = pair.j;
|
403
|
+
return currentMax;
|
404
|
+
}
|
405
|
+
}
|