Skip to content

Commit

Permalink
extract functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
mtf90 committed Jan 16, 2024
1 parent 1aabcd5 commit de93cd7
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 29 deletions.
1 change: 1 addition & 0 deletions commons/util/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
exports net.automatalib.common.util.io;
exports net.automatalib.common.util.lib;
exports net.automatalib.common.util.mapping;
exports net.automatalib.common.util.math;
exports net.automatalib.common.util.nid;
exports net.automatalib.common.util.process;
exports net.automatalib.common.util.random;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* Copyright (C) 2013-2024 TU Dortmund University
* This file is part of AutomataLib, http://www.automatalib.net/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.automatalib.common.util.math;

/**
* Utility class for mathematical computations.
*/
public final class MathUtil {

private MathUtil() {
// prevent instantiation
}

/**
* Computes the binomial coefficient n over k using Pascal's triangle. If the binomial coefficient exceeds the
* maximum number representable by a long, this methods returns {@link Long#MAX_VALUE} instead.
*
* @param n
* the value for n
* @param k
* the value for k
*
* @return the binomial coefficient n over k
*/
public static long binomial(int n, int k) {

if (k < 0 || n < k) {
throw new IllegalArgumentException("Illegal values for n and k");
}

// abuse symmetry
final int effectiveK = Math.min(k, n - k);

// pascal's triangle using a one dimensional storage
final int dimN = n + 1;
final int dimK = effectiveK + 1;
final long[] tmp = new long[dimN * dimK];

try {
for (int i = 0; i <= n; i++) {
final int min = Math.min(i, effectiveK);
for (int j = 0; j <= min; j++) {
if (j == 0 || j == i) {
// tmp[i][j] = 1
tmp[i * dimK + j] = 1;
} else {
// tmp[i][j] = tmp[i-1][j-1] + tmp[i-1][k]
tmp[i * dimK + j] = Math.addExact(tmp[(i - 1) * dimK + j - 1], tmp[(i - 1) * dimK + j]);
}
}
}

// tmp[n][k]
return tmp[n * dimK + effectiveK];
} catch (ArithmeticException ae) {
return Long.MAX_VALUE;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Copyright (C) 2013-2024 TU Dortmund University
* This file is part of AutomataLib, http://www.automatalib.net/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.automatalib.common.util.math;

import org.testng.Assert;
import org.testng.annotations.Test;

public class MathUtilTest {

@Test
public void testBinom() {
Assert.assertThrows(IllegalArgumentException.class, () -> MathUtil.binomial(5, -1));
Assert.assertEquals(MathUtil.binomial(5, 0), 1);
Assert.assertEquals(MathUtil.binomial(5, 1), 5);
Assert.assertEquals(MathUtil.binomial(5, 2), 10);
Assert.assertEquals(MathUtil.binomial(5, 3), 10);
Assert.assertEquals(MathUtil.binomial(5, 4), 5);
Assert.assertEquals(MathUtil.binomial(5, 5), 1);
Assert.assertThrows(IllegalArgumentException.class, () -> MathUtil.binomial(5, 6));

Assert.assertEquals(MathUtil.binomial(70, 35), Long.MAX_VALUE);
}
}
31 changes: 2 additions & 29 deletions util/src/main/java/net/automatalib/util/automaton/ads/ADSUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import net.automatalib.automaton.transducer.MealyMachine;
import net.automatalib.common.util.Pair;
import net.automatalib.common.util.math.MathUtil;
import net.automatalib.graph.ads.ADSNode;
import net.automatalib.graph.ads.impl.ADSSymbolNode;
import net.automatalib.word.Word;
Expand Down Expand Up @@ -149,34 +150,6 @@ public static long computeMaximumSplittingWordLength(int n, int i, int m) {
return n;
}

return binomial(n, i) - binomial(m - 1, i - 1) - 1;
return MathUtil.binomial(n, i) - MathUtil.binomial(m - 1, i - 1) - 1;
}

private static long binomial(int n, int k) {

// abuse symmetry
final int effectiveK = Math.min(k, n - k);

// pascal's triangle using a one dimensional storage
final int dimN = n + 1;
final int dimK = effectiveK + 1;
final long[] tmp = new long[dimN * dimK];

for (int i = 0; i <= n; i++) {
final int min = Math.min(i, effectiveK);
for (int j = 0; j <= min; j++) {
if (j == 0 || j == i) {
// tmp[i][j] = 1
tmp[i * dimK + j] = 1;
} else {
// tmp[i][j] = tmp[i-1][j-1] + tmp[i-1][k]
tmp[i * dimK + j] = tmp[(i - 1) * dimK + j - 1] + tmp[(i - 1) * dimK + j];
}
}
}

// tmp[n][k]
return tmp[n * dimK + effectiveK];
}

}

0 comments on commit de93cd7

Please sign in to comment.