aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store/src/main/java/tools/refinery/store/statecoding/stateequivalence/CombinationNodePairing.java
blob: 2877bd0f1754d78cf0470a67b1a0d7b559f577ac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/*
 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package tools.refinery.store.statecoding.stateequivalence;

import org.eclipse.collections.api.factory.primitive.IntIntMaps;
import org.eclipse.collections.api.map.primitive.IntIntMap;
import org.eclipse.collections.api.set.primitive.IntSet;
import org.eclipse.collections.impl.list.Interval;
import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CombinationNodePairing implements NodePairing {
	private final int[] left;
	private final int[] right;

	CombinationNodePairing(IntSet left, IntHashSet right) {
		this.left = left.toArray();
		this.right = right.toArray();

		Arrays.sort(this.left);
		Arrays.sort(this.right);
	}

	@Override
	public int size() {
		return left.length;
	}

	static final int LIMIT = 5;
	static final List<List<int[]>> permutations = new ArrayList<>();

	/**
	 * Generates and stores permutations up to a given size. If the number would be more than a limit, it provides a
	 * single permutation only.
	 *
	 * @param max The max number in the permutation
	 * @return A complete list of permutations of numbers 0...max, or a single permutation.
	 */
	public static List<int[]> getPermutations(int max) {
		if (max < permutations.size()) {
			return permutations.get(max);
		}
		if (max == 0) {
			List<int[]> result = new ArrayList<>();
			result.add(new int[1]);
			permutations.add(result);
			return result;
		}
		List<int[]> result = new ArrayList<>();
		List<int[]> previousPermutations = getPermutations(max - 1);
		for (var permutation : previousPermutations) {
			for (int pos = 0; pos <= max; pos++) {
				int[] newPermutation = new int[max + 1];
				if (pos >= 0)
					System.arraycopy(permutation, 0, newPermutation, 0, pos);
				newPermutation[pos] = max;
				if (max - (pos + 1) >= 0)
					System.arraycopy(permutation, pos + 1, newPermutation, pos + 1 + 1, max - (pos + 1));
				result.add(newPermutation);
			}
		}
		permutations.add(result);
		return result;
	}

	@Override
	public List<IntIntMap> permutations() {
		final var interval = Interval.zeroTo(this.size() - 1);

		if (isComplete()) {
			final List<int[]> p = getPermutations(this.size() - 1);
			return p.stream().map(x -> constructPermutationMap(interval, x)).toList();
		} else {
			return List.of(constructTrivialMap(interval));
		}
	}

	private IntIntMap constructTrivialMap(Interval interval) {
		return IntIntMaps.immutable.from(interval, l -> left[l], r -> right[r]);
	}

	private IntIntMap constructPermutationMap(Interval interval, int[] permutation) {
		return IntIntMaps.immutable.from(interval, l -> left[l], r -> right[permutation[r]]);
	}

	@Override
	public boolean isComplete() {
		return this.size() <= LIMIT;
	}
}