Skip to content

Commit

Permalink
BigDecimal magnitude
Browse files Browse the repository at this point in the history
  • Loading branch information
apete committed Aug 20, 2023
1 parent 762e43b commit 3ec278e
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 162 deletions.
16 changes: 16 additions & 0 deletions src/main/java/org/ojalgo/function/special/MissingMath.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ public static double logit(final double arg) {
return Math.log(1.0 / (1.0 - arg));
}

/**
* Returns a rough approximation of {@link Math#log10(double)} for {@link BigDecimal}.
* <ul>
* <li>For numbers like 10^n it returns the exact correct number, n.
* <li>The magnitude of 0.0 is 0.
* <li>The error is [0.0,1.0) and the returned value is never more than the actual/correct value. For
* 999.0 the correct value is close to 3, but this method returns 2, as the implementation simply counts
* the digits.
* <li>Works for negative numbers as the sign is disregarded.
* <li>Works for fractional numbers 0.1, 0.0456, 1.2 or whatever.
* </ul>
*/
public static int magnitude(final BigDecimal arg) {
return arg.signum() == 0 ? 0 : arg.precision() - arg.scale() - 1;
}

public static double max(final double... values) {
double retVal = values[0];
for (int i = values.length; i-- != 1;) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/ojalgo/matrix/store/ColumnsSupplier.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,16 @@ private SparseArray<N> getCurrent() {
super();
myRowsCount = numberOfRows;
myPhysicalStoreFactory = factory;
myColumnFactory = SparseArray.factory(factory.array()).limit(myRowsCount);
myColumnFactory = SparseArray.factory(factory.array());
}

public SparseArray<N> addColumn() {
return this.addColumn(myColumnFactory.make());
return this.addColumn(myColumnFactory.make(myRowsCount));
}

public void addColumns(final int numberToAdd) {
for (int j = 0; j < numberToAdd; j++) {
myColumns.add(myColumnFactory.make());
myColumns.add(myColumnFactory.make(myRowsCount));
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/ojalgo/matrix/store/RowsSupplier.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,16 @@ private SparseArray<N> getCurrent() {
super();
myColumnsCount = numberOfColumns;
myPhysicalStoreFactory = factory;
myRowFactory = SparseArray.factory(factory.array()).limit(myColumnsCount);
myRowFactory = SparseArray.factory(factory.array());
}

public SparseArray<N> addRow() {
return this.addRow(myRowFactory.make());
return this.addRow(myRowFactory.make(myColumnsCount));
}

public void addRows(final int numberToAdd) {
for (int i = 0; i < numberToAdd; i++) {
myRows.add(myRowFactory.make());
myRows.add(myRowFactory.make(myColumnsCount));
}
}

Expand Down
53 changes: 53 additions & 0 deletions src/test/java/org/ojalgo/function/special/MissingMathTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

import static org.ojalgo.function.constant.PrimitiveMath.MAX;

import java.math.BigDecimal;

import org.junit.jupiter.api.Test;
import org.ojalgo.TestUtils;
import org.ojalgo.function.constant.PrimitiveMath;
Expand Down Expand Up @@ -75,6 +77,57 @@ public void testGCD() {
}
}

@Test
public void testMagnitude() {

for (int exp = -32; exp <= 32; exp++) {

BigDecimal number = BigDecimal.valueOf(1L, -exp);

TestUtils.assertEquals(exp, Math.toIntExact(Math.round(Math.log10(number.doubleValue()))));

TestUtils.assertEquals(exp, MissingMath.magnitude(number));
}

for (int exp = -32; exp <= 32; exp++) {
TestUtils.assertEquals(0, MissingMath.magnitude(BigDecimal.valueOf(0L, -exp)));
}

for (int exp = -32; exp <= 32; exp++) {
for (long base = 1L; base <= 9L; base++) {
TestUtils.assertEquals(exp, MissingMath.magnitude(BigDecimal.valueOf(base, -exp)));
}
}

TestUtils.assertEquals(6, MissingMath.magnitude(BigDecimal.valueOf(1_000_000)));
TestUtils.assertEquals(3, MissingMath.magnitude(BigDecimal.valueOf(1_000)));
TestUtils.assertEquals(2, MissingMath.magnitude(BigDecimal.valueOf(100)));
TestUtils.assertEquals(1, MissingMath.magnitude(BigDecimal.valueOf(10)));
TestUtils.assertEquals(0, MissingMath.magnitude(BigDecimal.valueOf(1)));
TestUtils.assertEquals(0, MissingMath.magnitude(BigDecimal.valueOf(0)));
TestUtils.assertEquals(-1, MissingMath.magnitude(BigDecimal.valueOf(0.1)));
TestUtils.assertEquals(-2, MissingMath.magnitude(BigDecimal.valueOf(0.01)));
TestUtils.assertEquals(-3, MissingMath.magnitude(BigDecimal.valueOf(0.001)));
TestUtils.assertEquals(-6, MissingMath.magnitude(BigDecimal.valueOf(0.000001)));

TestUtils.assertEquals(2, MissingMath.magnitude(BigDecimal.valueOf(999)));
TestUtils.assertEquals(2, MissingMath.magnitude(BigDecimal.valueOf(-100)));
TestUtils.assertEquals(-2, MissingMath.magnitude(BigDecimal.valueOf(0.09)));
TestUtils.assertEquals(-2, MissingMath.magnitude(BigDecimal.valueOf(-0.01)));

for (int exp = -32; exp <= 32; exp++) {

double scale = 0.1 + 0.8 * Math.random(); // Range [0.1,0.9)
double value = scale * Math.pow(10.0, exp);
BigDecimal number = BigDecimal.valueOf(value);

int expected = exp - 1;
int actual = MissingMath.magnitude(number);

TestUtils.assertEquals(expected, actual);
}
}

@Test
public void testMax() {
TestUtils.assertEquals(9, MissingMath.max(9, 0, -9));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ public void testSimplyLowerAndUpperBounds() {
model.newExpression("SUM").set(varA, 1).set(varB, 1).set(varC, 1).level(6);

if (DEBUG) {
BasicLogger.debug(model);
model.options.debug(LinearSolver.class);
}

Expand Down
109 changes: 0 additions & 109 deletions src/test/java/org/ojalgo/optimisation/integer/DesignCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,115 +267,6 @@ public void testFacilityLocation() {
TestUtils.assertEquals(1.0, result.doubleValue(3));
}

/**
* Don't remember where this comes from. Most likely there was a problem entering paramerets like
* 1.7976931348623157E308
*/
@Test
public void testSimpleTSP() {

int n = 6;

double[][] c = new double[n][n];
c[0][0] = 1.7976931348623157E308;
c[0][1] = 141.4213562373095;
c[0][2] = 223.60679774997897;
c[0][3] = 223.60679774997897;
c[0][4] = 141.4213562373095;
c[0][5] = 156.63604262201076;
c[1][0] = 141.4213562373095;
c[1][1] = 1.7976931348623157E308;
c[1][2] = 100.0;
c[1][3] = 223.60679774997897;
c[1][4] = 200.0;
c[1][5] = 219.25609608009617;
c[2][0] = 223.60679774997897;
c[2][1] = 100.0;
c[2][2] = 1.7976931348623157E308;
c[2][3] = 200.0;
c[2][4] = 223.60679774997897;
c[2][5] = 319.2543607976003;
c[3][0] = 223.60679774997897;
c[3][1] = 223.60679774997897;
c[3][2] = 200.0;
c[3][3] = 1.7976931348623157E308;
c[3][4] = 100.0;
c[3][5] = 377.5537017276938;
c[4][0] = 141.4213562373095;
c[4][1] = 200.0;
c[4][2] = 223.60679774997897;
c[4][3] = 100.0;
c[4][4] = 1.7976931348623157E308;
c[4][5] = 297.81988930943544;
c[5][0] = 156.63604262201076;
c[5][1] = 219.25609608009617;
c[5][2] = 319.2543607976003;
c[5][3] = 377.5537017276938;
c[5][4] = 297.81988930943544;
c[5][5] = 1.7976931348623157E308;

ExpressionsBasedModel model = new ExpressionsBasedModel();

//DECISION VARIABLES
Variable[][] x = new Variable[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
x[i][j] = Variable.make("x" + i + "_" + j).binary().weight(c[i][j]);
model.addVariable(x[i][j]);
}
}
Variable[] u = new Variable[n];
for (int i = 1; i < n; i++) {
u[i] = new Variable("u" + i);
model.addVariable(u[i]);
}

//CONSTRAINTS
//forall(i in cities)
//flow_out:
//sum(j in cities : i!=j) x[i][j]==1;
for (int i = 0; i < n; i++) {
Expression constraint_line = model.newExpression("constraint_line" + i).lower(1).upper(1);
for (int j = 0; j < n; j++) {
if (i != j) {
constraint_line.set(x[i][j], 1);
}
}
}

//forall(j in cities)
//flow_in:
//sum(i in cities : i!=j) x[i][j]==1;
for (int j = 0; j < n; j++) {
Expression constraint_column = model.newExpression("constraint_column" + j).lower(1).upper(1);
for (int i = 0; i < n; i++) {
if (i != j) {
constraint_column.set(x[i][j], 1);
}
}
}

//forall(i in cities: i>=1, j in cities: j>=1)
//subroute:
//u[i]-u[j]+n*x[i][j] <= n-1;
for (int i = 1; i < n; i++) {
for (int j = 1; j < n; j++) {
if (i != j) {
Expression constraint_subroute = model.newExpression("constraint_subroute" + i + "_" + j).upper(n - 1);
constraint_subroute.set(u[i], 1);
constraint_subroute.set(u[j], -1);
constraint_subroute.set(x[i][j], n);
}
}
}

Optimisation.Result result = model.minimise();

TestUtils.assertStateNotLessThanOptimal(result);
TestUtils.assertTrue(model.validate(result));
TestUtils.assertEquals(917.3134949394167, result.getValue());
}

/**
* Essentilly this test case just verifies that the SOS presolver doesn't screw things up.
*/
Expand Down
21 changes: 11 additions & 10 deletions src/test/java/org/ojalgo/optimisation/integer/IntegerProblems.java
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ public void testP20150127infeasibleNode() {
* </p>
*/
@Test
public void testP20160701() {
public void testSimpleTSP20160701() {

int n = 6;
double[][] c = new double[n][n];
Expand Down Expand Up @@ -442,22 +442,20 @@ public void testP20160701() {
Variable[][] x = new Variable[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
x[i][j] = Variable.make("x" + i + "_" + j).binary().weight(c[i][j]);
model.addVariable(x[i][j]);
x[i][j] = model.newVariable("x" + i + "_" + j).binary().weight(c[i][j]);
}
}
Variable[] u = new Variable[n];
for (int i = 1; i < n; i++) {
u[i] = new Variable("u" + i);
model.addVariable(u[i]);
u[i] = model.newVariable("u" + i);
}

//CONSTRAINTS
//forall(i in cities)
//flow_out:
//sum(j in cities : i!=j) x[i][j]==1;
for (int i = 0; i < n; i++) {
Expression constraint_line = model.newExpression("constraint_line" + i).lower(1).upper(1);
Expression constraint_line = model.newExpression("constraint_line_" + i).lower(1).upper(1);
for (int j = 0; j < n; j++) {
if (i != j) {
constraint_line.set(x[i][j], 1);
Expand All @@ -469,7 +467,7 @@ public void testP20160701() {
//flow_in:
//sum(i in cities : i!=j) x[i][j]==1;
for (int j = 0; j < n; j++) {
Expression constraint_column = model.newExpression("constraint_column" + j).lower(1).upper(1);
Expression constraint_column = model.newExpression("constraint_column_" + j).lower(1).upper(1);
for (int i = 0; i < n; i++) {
if (i != j) {
constraint_column.set(x[i][j], 1);
Expand All @@ -483,15 +481,17 @@ public void testP20160701() {
for (int i = 1; i < n; i++) {
for (int j = 1; j < n; j++) {
if (i != j) {
Expression constraint_subroute = model.newExpression("constraint_subroute" + i + "_" + j).upper(n - 1);
Expression constraint_subroute = model.newExpression("constraint_subroute_" + i + "_" + j).upper(n - 1);
constraint_subroute.set(u[i], 1);
constraint_subroute.set(u[j], -1);
constraint_subroute.set(x[i][j], n);
}
}
}

// model.options.debug(IntegerSolver.class);
if (OptimisationIntegerTests.DEBUG) {
model.options.debug(IntegerSolver.class);
}

Optimisation.Result result = model.minimise();

Expand All @@ -516,7 +516,8 @@ public void testP20160701() {
}

TestUtils.assertStateNotLessThanOptimal(result);
TestUtils.assertEquals(917.3134949394164, result.getValue());
TestUtils.assertTrue(model.validate(result));
TestUtils.assertEquals(917.31349493942, result.getValue());
}

/**
Expand Down
Loading

0 comments on commit 3ec278e

Please sign in to comment.