Skip to content

Commit

Permalink
Adic utilities seem to be too specific to be in a generic utilities c…
Browse files Browse the repository at this point in the history
…lass. Moved it to padic.impl
  • Loading branch information
mihxil committed Jan 2, 2025
1 parent 48e5e38 commit 5161df4
Show file tree
Hide file tree
Showing 10 changed files with 469 additions and 380 deletions.
1 change: 1 addition & 0 deletions mihxil-algebra/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
exports org.meeuw.math.abstractalgebra.dihedral;
exports org.meeuw.math.abstractalgebra.dim2;
exports org.meeuw.math.abstractalgebra.padic;
exports org.meeuw.math.abstractalgebra.padic.impl;

uses AlgebraicElementFormatProvider;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

import org.meeuw.math.ArrayUtils;
import org.meeuw.math.DigitUtils;
import org.meeuw.math.AdicDigits;
import org.meeuw.math.abstractalgebra.FieldElement;
import org.meeuw.math.abstractalgebra.padic.impl.AdicDigits;
import org.meeuw.math.abstractalgebra.padic.impl.Utils;
import org.meeuw.math.exceptions.*;

import static org.meeuw.math.AdicDigits.NOT_REPETITIVE;
import static org.meeuw.math.DigitUtils.adicToString;
import static org.meeuw.math.DigitUtils.multiplyAdicDigits;
import static org.meeuw.math.abstractalgebra.padic.impl.AdicDigits.NOT_REPETITIVE;
import static org.meeuw.math.abstractalgebra.padic.impl.Utils.*;

/**
* WIP
Expand Down Expand Up @@ -80,7 +80,7 @@ public PAdicInteger times(PAdicInteger multiplier) {

@Override
public PAdicInteger plus(PAdicInteger summand) {
return new PAdicInteger(structure, DigitUtils.sumAdicDigits(structure.base,
return new PAdicInteger(structure, sumAdicDigits(structure.base,
this.digits,
summand.digits
));
Expand All @@ -92,7 +92,7 @@ byte digit(int n, byte[] digits, byte[] repetitive) {

@Override
public PAdicInteger negation() {
return new PAdicInteger(structure, DigitUtils.negate((byte) structure.base, digits));
return new PAdicInteger(structure, Utils.negate((byte) structure.base, digits));
}

public PAdicInteger leftShift(int i) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

import lombok.EqualsAndHashCode;

import org.meeuw.math.AdicDigits;
import org.meeuw.math.IntegerUtils;
import org.meeuw.math.Randomizable;
import org.meeuw.math.abstractalgebra.Cardinality;
import org.meeuw.math.abstractalgebra.Field;
import org.meeuw.math.abstractalgebra.padic.impl.AdicDigits;
import org.meeuw.math.exceptions.InvalidStructureCreationException;
import org.meeuw.math.operators.AbstractAlgebraicIntOperator;
import org.meeuw.math.operators.AlgebraicIntOperator;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.meeuw.math;
package org.meeuw.math.abstractalgebra.padic.impl;

import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.util.Optional;

import org.meeuw.math.ArrayUtils;
import org.meeuw.math.DigitUtils;

import static java.lang.System.arraycopy;
import static org.meeuw.math.ArrayUtils.*;

Expand Down Expand Up @@ -182,6 +185,7 @@ public String toString() {
return builder.toString();
}


@ToString
@EqualsAndHashCode
public static class ByteAndIndex {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package org.meeuw.math.abstractalgebra.padic.impl;

import java.util.*;

import org.meeuw.math.DigitUtils;
import org.meeuw.math.text.TextUtils;

import static java.lang.Byte.toUnsignedInt;
import static java.lang.System.arraycopy;
import static org.meeuw.math.DigitUtils.multiplyInverseDigitsWithCarry;

public class Utils {
/**
* Long multiplication of adic numbers. With proper propagation of the repetitive part.
* @param base The base to interpret the digitis for
* @param multiplier
* @param multiplicand
*/
public static AdicDigits multiplyAdicDigits(
final int base,
final AdicDigits multiplier,
final AdicDigits multiplicand) {
int i = -1;
AdicDigits sum = null;
List<DigitUtils.MultiplierAndNewDigitAndCarry> list = null; // only relevant when repeating digits.
while(true) {
i++;
AdicDigits.ByteAndIndex multiplierDigit = multiplier.get(i).orElse(null);
if (multiplierDigit == null) {
return sum;
}
if (multiplierDigit.value != 0) {

var shiftedMultiplicand = multiplicand.leftShift(i);
final AdicDigits summand = multiplyAdicDigits(base,
multiplierDigit.value,
shiftedMultiplicand
);
if (sum == null) {
sum = summand;
} else {
sum = sumAdicDigits(base, sum, summand);
}
}


if (multiplierDigit.repeating) {
AdicDigits.ByteAndIndex newDigit = sum.get(i).orElseThrow(() -> new IllegalStateException());
if (list == null) {
list = new ArrayList<>();
}
byte carry = sum.repetend[0];
DigitUtils.MultiplierAndNewDigitAndCarry l = new DigitUtils.MultiplierAndNewDigitAndCarry(multiplierDigit.index, multiplierDigit.value, newDigit.value, carry);
int indexOf = list.indexOf(l);
if (indexOf >= 0) {
//if (i > 100) {
System.out.println(sum + "\nAlready saw " + l);

// so we know the length of the repetitive bit.
byte[] repetitive = new byte[indexOf + 1];

arraycopy(sum.digits , sum.digits.length - repetitive.length, repetitive, 0, repetitive.length);

// what remains are the normal digits.
int digitLength = sum.digits.length - repetitive.length;

byte[] digits = new byte[digitLength];
arraycopy(sum.digits, 0, digits, 0, digits.length);
return AdicDigits.create(repetitive, digits);
} else {
//System.out.println(i + " new " + l + " (" +sum + "->" + sum + ")");
list.add(0, l);
}
}
}

}

public static AdicDigits sumAdicDigits(int base, AdicDigits... summands) {
return sumAdicDigits((byte) base, summands);
}

/**
* Performs a sum of number of integers
* @param base The base of this number
*/
public static AdicDigits sumAdicDigits(byte base, AdicDigits... summands) {
byte[] result = new byte[100];
int carry = 0;
int i = 0;
List<DigitUtils.CarryAndIndices> detecting = new ArrayList<>();
while(true) {
int r = carry;
boolean detectRepetition = true;
boolean anyPresent = false;
for (AdicDigits summand : summands) {

Optional<AdicDigits.ByteAndIndex> byteAndIndex = summand.get(i);
if (byteAndIndex.isPresent()) {
anyPresent = true;
detectRepetition &= byteAndIndex.get().repeating;
r += byteAndIndex.get().value;
}
}
if (! anyPresent) {
break;
}
result = DigitUtils.ensureCapacity(i, result);
result[i] = (byte) (r % base);
i++;
if (detectRepetition) {
DigitUtils.CarryAndIndices check = new DigitUtils.CarryAndIndices(
carry,
AdicDigits.getIndexes(i, summands)
);
int indexOf = detecting.indexOf(check);
if (indexOf == -1) {
detecting.add(check);
} else {
i--;
while(indexOf-- > 0) {
detecting.remove(0);
}
break;
}
}
carry = r / base;
}
byte[] digits = new byte[i - detecting.size()];
byte[] repetitive = new byte[detecting.size()];
arraycopy(result, 0, digits, 0, digits.length);
arraycopy(result, i - detecting.size(), repetitive, 0, repetitive.length);
if (repetitive.length == 0) {
repetitive = AdicDigits.NOT_REPETITIVE;
}
return new AdicDigits(repetitive, digits);
}



/**
* Multiply an {@link AdicDigits} with exactly one digit.
* @param multiplier The multiplier digit
* @param multiplicand The multiplicand {@link AdicDigits}
*/
public static AdicDigits multiplyAdicDigits(
final int base,
final byte multiplier,
final AdicDigits multiplicand) {
final byte[] resultDigits = multiplyInverseDigitsWithCarry(base, multiplier, multiplicand.digits);
final int originalCarry = toUnsignedInt(resultDigits[resultDigits.length - 1]);

if (multiplicand.repetend.length == 0 || Arrays.equals(multiplicand.repetend, AdicDigits.NOT_REPETITIVE)) {
return AdicDigits.create(
AdicDigits.NOT_REPETITIVE,
resultDigits);
}
int carry = originalCarry;
int digiti = toUnsignedInt(multiplier);
List<DigitUtils.CarryAndIndex> carries = new ArrayList<>();
List<Byte> moreDigits = new ArrayList<>();
int i = 0;
byte[] repetitive;
while(true) {
int index = i % multiplicand.repetend.length;
DigitUtils.CarryAndIndex carryAndIndex = new DigitUtils.CarryAndIndex(carry, index);
int indexOf = carries.indexOf(carryAndIndex);
if (indexOf == -1) {
carries.add(carryAndIndex);
int ri = carry + digiti * toUnsignedInt(multiplicand.repetend[index]);
byte b = (byte) (ri % base);
moreDigits.add(Byte.valueOf(b));
carry = ri / base;
i++;
} else {
repetitive = new byte[moreDigits.size() - indexOf];
for (int j= 0; j < repetitive.length; j++) {
repetitive[j] = moreDigits.remove(indexOf);;
}
break;
}
}
int numberOfOriginalDigits = Math.max(0, resultDigits.length - 1);
int numberOfDigits = Math.max(0, moreDigits.size() + numberOfOriginalDigits);
byte[] digits = new byte[numberOfDigits];

arraycopy(resultDigits, 0, digits, 0, numberOfDigits);
for (int j = 0; j < moreDigits.size(); j++) {
digits[numberOfOriginalDigits + j] = moreDigits.get(j);
}
return AdicDigits.create(repetitive, digits);
}


public static String adicToString(int base, AdicDigits digits) {
return adicToString((byte) base, digits);
}

public static String adicToString(byte base, AdicDigits digits) {
return digits.toString() + TextUtils.subscript(base);
}

public static AdicDigits negate(byte base, AdicDigits negated) {
byte[] negatedDigits = new byte[negated.digits.length];
byte[] negatedRepetend = new byte[negated.repetend.length];
byte carry = 0;
for (int i = 0 ; i < negated.digits.length; i++) {
negatedDigits[i] = (byte) (base - negated.digits[i] - carry);
carry = 1;
}
for (int i = 0 ; i < negated.repetend.length; i++) {
negatedRepetend[i] = (byte) (base - negated.repetend[i] - carry);
carry = 1;
}
return AdicDigits.create(negatedRepetend, negatedDigits);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@

import lombok.extern.log4j.Log4j2;

import java.util.Random;

import net.jqwik.api.Arbitraries;
import net.jqwik.api.Arbitrary;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import org.meeuw.math.abstractalgebra.padic.PAdicInteger;
import org.meeuw.math.abstractalgebra.padic.PAdicIntegers;
import org.meeuw.theories.abstractalgebra.FieldTheory;

import static org.assertj.core.api.Assertions.assertThat;

@Log4j2
class PadicIntegersTest { //implements FieldTheory<PAdicInteger> {
class PadicIntegersTest {

PAdicIntegers p5 = PAdicIntegers.of(5);

Expand All @@ -24,5 +32,48 @@ public void simple() {
log.info("{} + {} = {}", a.bigIntegerValue(), b.bigIntegerValue(), c.bigIntegerValue());
}

@Test
@Disabled
public void negationOfOne() {
PAdicInteger minusOne = p5.one().negation();
assertThat(minusOne.toString()).isEqualTo("...4 ₅");


// FAILS
assertThat(p5.one().plus(minusOne)).isEqualTo(p5.zero());
assertThat(minusOne.negation()).isEqualTo(p5.one());
}

@Test
public void negation() {
PAdicInteger minusOne = p5.one().negation();
assertThat(minusOne.toString()).isEqualTo("...4 ₅");
}

@Test
public void random() {
PAdicInteger random = p5.nextRandom(new Random(1));
assertThat(random.toString()).isEqualTo("...1334 32344₅");
}

@Test
public void withRepetitive() {
PAdicInteger a = p5.of("0", "234");
PAdicInteger b = a.withRepetend(1, 3);

}

public static class PAdic5Test implements FieldTheory<PAdicInteger> {

PAdicIntegers p5 = PAdicIntegers.of(5);


@Override
public Arbitrary<PAdicInteger> elements() {
return Arbitraries
.randomValue(r -> p5.nextRandom(r));
}
}


}
Loading

0 comments on commit 5161df4

Please sign in to comment.