Skip to content

Bignum multiplication #142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/cryptator/config/CryptaCmdConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public final boolean useBignum() {
return useBigNum;
}

public final void setUseBigNum(boolean useBigNum) {
this.useBigNum = useBigNum;
}

public final boolean useCrypt() {
return useCrypt;
}
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/cryptator/solver/CryptaBignumModeler.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ private ArExpression[] makeConstVars(final char[] word) {
return vars.toArray(res);
}

private ArExpression[] applyMUL(final ArExpression[] a, final ArExpression[] b) {
final int n = a.length + b.length - 1;
final ArExpression[] c = new ArExpression[n];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < b.length; j++) {
final int k = i + j;
final ArExpression prod = a[i].mul(b[j]);
c[k] = c[k] == null ? prod : c[k].add(prod);
}
}
return c;
}

private ArExpression[] applyADD(final ArExpression[] a, final ArExpression[] b) {
final int m = Math.min(a.length, b.length);
final int n = Math.max(a.length, b.length);
Expand Down Expand Up @@ -114,6 +127,10 @@ private void apply(final CryptaOperator op, final ArExpression[] a, final ArExpr
stack.push(applyADD(a, b));
break;
}
case MUL: {
stack.push(applyMUL(a, b));
break;
}
case EQ: {
applyEQ(a, b);
if (!stack.isEmpty()) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/cryptator/tree/TreeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public static CryptaFeatures computeFeatures(final ICryptaNode cryptarithm) {

public static CryptaOperatorDetection computeUnsupportedBignumOperator(final ICryptaNode cryptarithm) {
final CryptaOperatorDetection detect = new CryptaOperatorDetection(CryptaOperator.ID, CryptaOperator.ADD,
CryptaOperator.EQ, CryptaOperator.AND);
CryptaOperator.MUL, CryptaOperator.EQ, CryptaOperator.AND);
TreeTraversals.preorderTraversal(cryptarithm, detect);
return detect;
}
Expand Down
37 changes: 37 additions & 0 deletions src/test/java/cryptator/BignumTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,41 @@ public void testSendMoreMoneyList3() throws CryptaParserException, CryptaModelEx
public void testUnsatSendMoreMoneyList() throws CryptaParserException, CryptaModelException, CryptaSolverException {
t.testUNSAT("send+more=money; s+e=n", "send+more=money;;; s+e=n", "send+more=money; s+e=n;");
}

@Test
public void testBarker5() throws CryptaParserException, CryptaModelException, CryptaSolverException {
t.testUNIQUE("cinq*six=trente");
}

@Test
public void testUniqueLongMultiplications() throws CryptaModelException, CryptaSolverException {
String[] cryptarithms = {"SEE * SO = MIMEO; MIMEO = EMOO + '10'*MESS;SEE * O = EMOO;SEE * S = MESS",
"SEE * SO = MIMEO; MIMEO = EMOO + \"10\"*MESS;SEE * O = EMOO;SEE * S = MESS",
"CUT * T = BUST; CUT * I = TNNT; TNNT * '10' + BUST = TENET; TENET = CUT * IT",
"RED * S = ARCS; RED * A = RED; RED * '10' + ARCS = CDTS; CDTS = RED * AS",
"HOW * E = HAIL; HOW * W = PAL; HAIL + PAL * '10' = LHAL; HOW * WE = LHAL",
"SEE * SO = MIMEO&& MIMEO = EMOO + '10'*MESS&&SEE * O = EMOO&&SEE * S = MESS",
"CUT * T = BUST&& CUT * I = TNNT&& TNNT * '10' + BUST = TENET&& TENET = CUT * IT",
"RED * S = ARCS&& RED * A = RED&& RED * '10' + ARCS = CDTS&& CDTS = RED * AS",
"HOW * E = HAIL&& HOW * W = PAL&& HAIL + PAL * '10' = LHAL&& HOW * WE = LHAL"

};

t.testUNIQUE(cryptarithms);
}

@Test
public void testPrimeBignumMultiplications() throws CryptaModelException, CryptaSolverException {
String[] cryptarithms = {"7901*999999983491=7900999869562391", "8467*999999983491=8466999860218297"};
t.testUNIQUE(cryptarithms);
}

@Test
public void testPrimeBignumLongMultiplications() throws CryptaModelException, CryptaSolverException {
String[] cryptarithms = {
"8467*999999983491=8466999860218297&&8467*1+76203*10+33868*100+25401*1000+67736*10000+76203*100000+76203*1000000+76203*10000000+76203*100000000+76203*1000000000+76203*10000000000+76203*100000000000=8466999860218297&&8467*8=67736&&8467*3=25401&&8467*4=33868&&8467*9=76203&&8467*1=8467",
"999999983491*8467=8466999860218297&&6999999884437*'1'+5999999900946*'10'+3999999933964*'100'+7999999867928*'1000'=8466999860218297&&999999983491*8=7999999867928&&999999983491*4=3999999933964&&999999983491*6=5999999900946&&999999983491*7=6999999884437"};
t.testUNIQUE(cryptarithms);
}

}
26 changes: 22 additions & 4 deletions src/test/java/cryptator/GenerateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private void testHeavyGenerate(final int expectedSolCount, final OptionalInt exp
testGenerate(expectedSolCount, expectedCandCount, wordArray);
}

private void testMultGenerate(final int expectedSolCount, final WordArray wordArray) throws CryptaModelException {
private void testMultGenerateLH(final int expectedSolCount, final WordArray wordArray) throws CryptaModelException {
JULogUtil.configureSilentLoggers();
config.setMultModel(true);
configure(0, false);
Expand All @@ -80,7 +80,15 @@ private void testMultGenerate(final int expectedSolCount, final WordArray wordAr
config.setMultModel(false);
}

private void testLongMultGenerate(final int expectedSolCount, final WordArray wordArray)
private void testMultGenerate(final int expectedSolCount, final WordArray wordArray) throws CryptaModelException {
config.setUseBigNum(false);
testMultGenerateLH(expectedSolCount, wordArray);
config.setUseBigNum(true);
testMultGenerateLH(expectedSolCount, wordArray);
config.setUseBigNum(false);
}

private void testLongMultGenerateLH(final int expectedSolCount, final WordArray wordArray)
throws CryptaModelException {
JULogUtil.configureSilentLoggers();
config.setLongMultModel(true);
Expand All @@ -91,6 +99,15 @@ private void testLongMultGenerate(final int expectedSolCount, final WordArray wo
config.setLongMultModel(false);
}

private void testLongMultGenerate(final int expectedSolCount, final WordArray wordArray)
throws CryptaModelException {
config.setUseBigNum(false);
testLongMultGenerateLH(expectedSolCount, wordArray);
config.setUseBigNum(true);
testLongMultGenerateLH(expectedSolCount, wordArray);
config.setUseBigNum(false);
}

@Test
public void testSendMoreMoney() throws CryptaModelException {
final WordArray words = new WordArray(Arrays.asList("send", "more", "money"), null);
Expand Down Expand Up @@ -192,7 +209,8 @@ public void testMult4() throws CryptaModelException {
@Test
public void testMult5() throws CryptaModelException {
WordArray words = new WordArray(Arrays.asList("north", "south", "east", "west"), null);
testMultGenerate(2, words);
testMultGenerateLH(2, words);
// Takes too long with the bignum model
}

@Test
Expand All @@ -202,7 +220,7 @@ public void testLongMult1() throws CryptaModelException {
}

@Test
public void testLongMult3() throws CryptaModelException {
public void testLongMult2() throws CryptaModelException {
WordArray words = new WordArray(Arrays.asList("get", "by", "babe", "beare"), null);
testLongMultGenerate(1, words);
}
Expand Down