Skip to content

Commit

Permalink
Minor performance refactoring to LP
Browse files Browse the repository at this point in the history
  • Loading branch information
apete committed Feb 23, 2025
1 parent c5d9a45 commit 42cb1f5
Show file tree
Hide file tree
Showing 12 changed files with 1,712 additions and 197 deletions.
11 changes: 11 additions & 0 deletions .project
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,15 @@
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature>
</natures>
<filteredResources>
<filter>
<id>1740296511198</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ Added / Changed / Deprecated / Fixed / Removed / Security

> Corresponds to changes in the `develop` branch since the last release
### Changed

#### org.ojalgo.optimisation

- Minor performance refactoring to SimplexSolver.

## [55.1.2] – 2025-02-08

### Changed
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.ojalgo</groupId>
<artifactId>ojalgo</artifactId>
<version>55.1.2</version>
<version>55.2.0-SNAPSHOT</version>
<name>ojAlgo</name>
<description>oj! Algorithms - ojAlgo - is Open Source Java code that has to do with mathematics, linear algebra and optimisation.</description>
<packaging>jar</packaging>
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/org/ojalgo/concurrent/ProcessingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,19 @@ public void run(final int parallelism, final Runnable processor) {
}
}

public void run(final Runnable task1, final Runnable task2) {

Future<?> future1 = myExecutor.submit(task1);
Future<?> future2 = myExecutor.submit(task2);

try {
future1.get();
future2.get();
} catch (InterruptedException | ExecutionException cause) {
throw new RuntimeException(cause);
}
}

/**
* @see ProcessingService#run(int, Runnable)
*/
Expand Down
66 changes: 40 additions & 26 deletions src/main/java/org/ojalgo/optimisation/linear/RevisedStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ private void doExclTranspMult(final MatrixStore<Double> lambda, final PhysicalSt
}
}

private void updateDualVariables() {
R064Store objective = myPhase1Objective != null ? myPhase1Objective : myObjective;
myInvBasis.btran(objective.rows(included), l);
this.doExclTranspMult(l, r);
d.fillMatching(objective.rows(excluded), SUBTRACT, r);
}

@Override
protected void pivot(final IterDescr iteration) {

Expand All @@ -151,40 +158,44 @@ void calculateDualDirection(final ExitInfo exit) {
@Override
void calculateIteration() {

// PhysicalStore<Double> x0 = x.copy();
// PhysicalStore<Double> d0 = d.copy();

// Should be able to do something like
// x += y
// d += a
// ...and then move the setup/prepare/update outside of the loop

R064Store objective = myPhase1Objective != null ? myPhase1Objective : myObjective;

myInvBasis.btran(objective.rows(included), l);
myInvBasis.ftran(myConstraintsRHS, x);

this.doExclTranspMult(l, r);
// ProcessingService.INSTANCE.run(() -> myInvBasis.btran(objective.rows(included), l), () -> myInvBasis.ftran(myConstraintsRHS, x));

this.doExclTranspMult(l, r);
d.fillMatching(objective.rows(excluded), SUBTRACT, r);
}

myInvBasis.ftran(myConstraintsRHS, x);
@Override
void calculateIteration(final SimplexSolver.IterDescr iteration, final double shift) {

int exit = iteration.exit.index;
int enter = iteration.enter.index;

if (iteration.isBasisUpdate()) {
// For basis updates, we need to update both x and d

// Update reduced costs
double stepD = d.doubleValue(enter) / a.doubleValue(enter);
a.axpy(-stepD, d);
d.set(enter, -stepD);
}

if (shift == ZERO) {

// BasicLogger.debug();
//
// BasicLogger.debug();
// BasicLogger.debug("x before: {}", x0.asList());
// BasicLogger.debug("Ratio primal: {} exit={}", iteration.ratioPrimal, iteration.exit.index);
// BasicLogger.debug("y step: {}", y.asList());
// BasicLogger.debug("z step: {}", z.asList());
// BasicLogger.debug("l step: {}", l.asList());
// BasicLogger.debug("x after: {}", x.asList());
//
// BasicLogger.debug();
// BasicLogger.debug("d before: {}", d0.asList());
// BasicLogger.debug("Ratio dual: {} enter={}", iteration.ratioDual, iteration.enter.index);
// BasicLogger.debug("a step: {}", a.asList());
// BasicLogger.debug("r step: {}", r.asList());
// BasicLogger.debug("d after: {}", d.asList());
double exitX = x.doubleValue(exit);
double enterY = y.doubleValue(exit);
double stepX = exitX / enterY;
y.axpy(-stepX, x);
x.set(exit, stepX);

} else {

myInvBasis.ftran(myConstraintsRHS, x);
}
}

@Override
Expand Down Expand Up @@ -334,6 +345,9 @@ Primitive1D sliceBodyRow(final int i) {

@Override
Primitive1D sliceDualVariables() {

this.updateDualVariables(); // Add this line

return new Primitive1D() {

@Override
Expand Down
51 changes: 26 additions & 25 deletions src/main/java/org/ojalgo/optimisation/linear/SimplexSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,6 @@ static final class IterDescr {

final EnterInfo enter;
final ExitInfo exit;
double ratioDual = MACHINE_LARGEST;
double ratioPrimal = MACHINE_LARGEST;

IterDescr(final SimplexStore simplex) {
super();
Expand Down Expand Up @@ -301,8 +299,6 @@ void markAsBoundSwitch() {
void reset() {
exit.reset();
enter.reset();
ratioPrimal = MACHINE_LARGEST;
ratioDual = MACHINE_LARGEST;
}

int row() {
Expand Down Expand Up @@ -685,7 +681,7 @@ private void logCurrentState() {
}
}

private void shift(final int column, final ColumnState state) {
private double shift(final int column, final ColumnState state) {

double shift = ZERO;
if (state == ColumnState.LOWER) {
Expand All @@ -699,6 +695,8 @@ private void shift(final int column, final ColumnState state) {
mySolutionShift[column] += shift;
myValueShift += mySimplex.getCost(column) * shift;
}

return shift;
}

private Optimisation.Result solveUnconstrained() {
Expand Down Expand Up @@ -759,7 +757,7 @@ private boolean testDualEnterRatio(final IterDescr iteration) {
double ratio = ZERO;
double scale = ONE;

iteration.ratioDual = Double.MAX_VALUE;
double iterationRatio = Double.MAX_VALUE;
double iterationScale = MACHINE_LARGEST;

int n = mySimplex.structure.countVariables();
Expand Down Expand Up @@ -804,8 +802,8 @@ private boolean testDualEnterRatio(final IterDescr iteration) {
this.log(1, "{}({}) {} / {} = {}", j, je, numer, denom, ratio);
}

if (ratio < iteration.ratioDual
|| scale > iterationScale && PIVOT.isDifferent(iterationScale, scale) && !RATIO.isDifferent(iteration.ratioDual, ratio)) {
if (ratio < iterationRatio
|| scale > iterationScale && PIVOT.isDifferent(iterationScale, scale) && !RATIO.isDifferent(iterationRatio, ratio)) {

enter.index = je;
enter.from = columnState;
Expand All @@ -815,7 +813,7 @@ private boolean testDualEnterRatio(final IterDescr iteration) {
this.log(2, "{} => {}", ratio, enter);
}

iteration.ratioDual = ratio;
iterationRatio = ratio;
iterationScale = scale;
}
}
Expand Down Expand Up @@ -849,7 +847,7 @@ private boolean testPrimalExitRatio(final IterDescr iteration) {
double ratio = ZERO;
double scale = ONE;

iteration.ratioPrimal = range;
double iterationRatio = range;
double iterationScale = MACHINE_LARGEST;

int[] included = mySimplex.included;
Expand Down Expand Up @@ -878,8 +876,8 @@ private boolean testPrimalExitRatio(final IterDescr iteration) {
this.log(1, "{}({}) {} / {} = {}", j, ji, numer, denom, ratio);
}

if (ratio < iteration.ratioPrimal
|| scale > iterationScale && PIVOT.isDifferent(iterationScale, scale) && !RATIO.isDifferent(iteration.ratioPrimal, ratio)) {
if (ratio < iterationRatio
|| scale > iterationScale && PIVOT.isDifferent(iterationScale, scale) && !RATIO.isDifferent(iterationRatio, ratio)) {

exit.index = ji;
if (denom < ZERO) {
Expand All @@ -894,7 +892,7 @@ private boolean testPrimalExitRatio(final IterDescr iteration) {
this.log(2, "{} => {}", ratio, exit);
}

iteration.ratioPrimal = ratio;
iterationRatio = ratio;
iterationScale = scale;
}

Expand All @@ -915,8 +913,8 @@ private boolean testPrimalExitRatio(final IterDescr iteration) {
this.log(1, "{}({}) {} / {} = {}", j, ji, numer, denom, ratio);
}

if (ratio < iteration.ratioPrimal
|| scale > iterationScale && PIVOT.isDifferent(iterationScale, scale) && !RATIO.isDifferent(iteration.ratioPrimal, ratio)) {
if (ratio < iterationRatio
|| scale > iterationScale && PIVOT.isDifferent(iterationScale, scale) && !RATIO.isDifferent(iterationRatio, ratio)) {

exit.index = ji;
if (denom > ZERO) {
Expand All @@ -931,7 +929,7 @@ private boolean testPrimalExitRatio(final IterDescr iteration) {
this.log(2, "{} => {}", ratio, exit);
}

iteration.ratioPrimal = ratio;
iterationRatio = ratio;
iterationScale = scale;
}

Expand All @@ -942,7 +940,7 @@ private boolean testPrimalExitRatio(final IterDescr iteration) {
}
}

if (iteration.ratioPrimal >= range && Double.isFinite(iteration.ratioPrimal)) {
if (iterationRatio >= range && Double.isFinite(iterationRatio)) {

if (this.isLogDebug()) {
this.log("Bound switch!");
Expand Down Expand Up @@ -972,11 +970,17 @@ private void update(final IterDescr iteration) {
this.log("Shift Exit: {}, Enter: {}", mySolutionShift[iteration.exit.column()], mySolutionShift[iteration.enter.column()]);
}

int exitCol = iteration.exit.column();
int enterCol = iteration.enter.column();

mySimplex.pivot(iteration);

this.shift(iteration.enter.column(), iteration.exit.to);
double shift = this.shift(iteration.enter.column(), iteration.exit.to);

// mySimplex.calculateIteration();

mySimplex.calculateIteration();
// mySimplex.calculateIterationOld(iteration, exitCol, enterCol, shift);
mySimplex.calculateIteration(iteration, shift);

} else if (iteration.isBoundSwitch()) {

Expand All @@ -1001,12 +1005,9 @@ private void update(final IterDescr iteration) {
throw new IllegalStateException();
}

} else {

if (this.isLogDebug()) {
this.log();
this.log("No update operation!");
}
} else if (this.isLogDebug()) {
this.log();
this.log("No update operation!");
}

}
Expand Down
11 changes: 5 additions & 6 deletions src/main/java/org/ojalgo/optimisation/linear/SimplexStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
*/
package org.ojalgo.optimisation.linear;

import static org.ojalgo.function.constant.PrimitiveMath.ZERO;
import static org.ojalgo.function.constant.PrimitiveMath.*;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -36,6 +36,7 @@
import org.ojalgo.optimisation.Optimisation.Options;
import org.ojalgo.optimisation.linear.SimplexSolver.EnterInfo;
import org.ojalgo.optimisation.linear.SimplexSolver.ExitInfo;
import org.ojalgo.optimisation.linear.SimplexSolver.IterDescr;
import org.ojalgo.structure.Access1D;
import org.ojalgo.structure.Mutate1D;
import org.ojalgo.structure.Mutate2D;
Expand Down Expand Up @@ -184,6 +185,8 @@ protected void shiftColumn(final int col, final double shift) {

abstract void calculateIteration();

abstract void calculateIteration(IterDescr iteration, double shift);

abstract void calculatePrimalDirection(EnterInfo enter);

/**
Expand Down Expand Up @@ -398,11 +401,7 @@ final boolean isIncluded(final int index) {
}

final boolean isNegated(final int j) {
if (myUpperBounds[j] <= ZERO && myLowerBounds[j] < ZERO) {
return true;
} else {
return false;
}
return myUpperBounds[j] <= ZERO && myLowerBounds[j] < ZERO;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
*/
package org.ojalgo.optimisation.linear;

import static org.ojalgo.function.constant.PrimitiveMath.MACHINE_LARGEST;
import static org.ojalgo.function.constant.PrimitiveMath.ZERO;
import static org.ojalgo.function.constant.PrimitiveMath.*;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -35,6 +34,7 @@
import org.ojalgo.optimisation.Optimisation;
import org.ojalgo.optimisation.linear.SimplexSolver.EnterInfo;
import org.ojalgo.optimisation.linear.SimplexSolver.ExitInfo;
import org.ojalgo.optimisation.linear.SimplexSolver.IterDescr;
import org.ojalgo.structure.Access1D;
import org.ojalgo.structure.Access2D;
import org.ojalgo.structure.ElementView1D;
Expand Down Expand Up @@ -121,6 +121,11 @@ final void calculateIteration() {
// With a tableau all calculations are continuously done when pivoting
}

@Override
void calculateIteration(final IterDescr iteration, final double shift) {
//
}

@Override
final void calculatePrimalDirection(final EnterInfo enter) {
// With a tableau all calculations are continuously done when pivoting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ abstract class OptimisationLinearTests {
opt.sparse = Boolean.TRUE;
}));

static final List<Function<LinearStructure, SimplexStore>> STORE_FACTORIES = List.of(DenseTableau::new, RevisedStore::new, SparseTableau::new);
static final List<Function<LinearStructure, SimplexStore>> STORE_FACTORIES = List.of(RevisedStore::new, DenseTableau::new, SparseTableau::new);

static final List<Function<LinearStructure, SimplexTableau>> TABLEAU_FACTORIES = List.of(DenseTableau::new, SparseTableau::new);

Expand Down
Loading

0 comments on commit 42cb1f5

Please sign in to comment.