Update Commons Math.

Code refactoring.
This commit is contained in:
Vova Perebykivskyi 2016-04-28 16:45:04 +03:00 committed by Dgray16
parent 3adb216e56
commit 3852c49972
5 changed files with 107 additions and 90 deletions

View file

@ -98,8 +98,8 @@
<!-- Commons Math-->
<dependency>
<groupId>commons-math</groupId>
<artifactId>commons-math</artifactId>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>

View file

@ -26,7 +26,7 @@
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
</dependency>
@ -99,8 +99,8 @@
<!-- Commons Math-->
<dependency>
<groupId>commons-math</groupId>
<artifactId>commons-math</artifactId>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>

View file

@ -24,7 +24,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.math.fraction.Fraction;
import org.apache.commons.math3.fraction.Fraction;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
@ -32,24 +32,26 @@ import org.apache.commons.math.fraction.Fraction;
public class ProportionalDistributor {
public static ProportionalDistributor create(int... initialShares) {
return new ProportionalDistributor(toFractions(
sumIntegerParts(initialShares), initialShares));
return new ProportionalDistributor(toFractions(sumIntegerParts(initialShares), initialShares));
}
private static int sumIntegerParts(int[] numbers) {
int sum = 0;
for (int each : numbers) {
sum += each;
}
return sum;
}
private static Fraction[] toFractions(int initialTotal, int... shares) {
Fraction[] result = new Fraction[shares.length];
for (int i = 0; i < result.length; i++) {
result[i] = initialTotal == 0 ? Fraction.ZERO : new Fraction(
shares[i], initialTotal);
result[i] = initialTotal == 0 ? Fraction.ZERO : new Fraction(shares[i], initialTotal);
}
return result;
}
@ -57,14 +59,15 @@ public class ProportionalDistributor {
* Note: this class has a natural ordering that is inconsistent with equals.
*
*/
private static class FractionWithPosition implements
Comparable<FractionWithPosition> {
private static class FractionWithPosition implements Comparable<FractionWithPosition> {
public static List<FractionWithPosition> transform(Fraction[] fractions) {
List<FractionWithPosition> result = new ArrayList<FractionWithPosition>();
List<FractionWithPosition> result = new ArrayList<>();
for (int i = 0; i < fractions.length; i++) {
result.add(new FractionWithPosition(i, fractions[i]));
}
return result;
}
@ -90,49 +93,56 @@ public class ProportionalDistributor {
}
public int[] distribute(final int total) {
if (fractions.length == 0) {
if ( fractions.length == 0 ) {
return new int[0];
}
int[] result = new int[fractions.length];
int remaining = total - assignIntegerParts(total, result);
if (remaining == 0) {
if ( remaining == 0 ) {
return result;
}
Fraction[] currentFractions = toFractions(total, result);
assignRemaining(result, currentFractions, remaining);
return result;
}
private int assignIntegerParts(int current, int[] result) {
Fraction currentAsFraction = new Fraction(current, 1);
int substract = 0;
for (int i = 0; i < fractions.length; i++) {
int intValue = fractions[i].multiply(currentAsFraction).intValue();
if (intValue > 0) {
if ( intValue > 0 ) {
result[i] = result[i] + intValue;
substract += intValue;
}
}
return substract;
}
private void assignRemaining(int[] result, Fraction[] currentProportions,
int remaining) {
List<FractionWithPosition> transform = FractionWithPosition
.transform(difference(currentProportions));
private void assignRemaining(int[] result, Fraction[] currentProportions, int remaining) {
List<FractionWithPosition> transform = FractionWithPosition.transform(difference(currentProportions));
Collections.sort(transform, Collections.reverseOrder());
for (int i = 0; i < remaining; i++) {
FractionWithPosition proportionWithPosition = transform.get(i
% currentProportions.length);
FractionWithPosition proportionWithPosition = transform.get(i % currentProportions.length);
result[proportionWithPosition.position] = result[proportionWithPosition.position] + 1;
}
}
private Fraction[] difference(Fraction[] pr) {
Fraction[] result = new Fraction[fractions.length];
for (int i = 0; i < result.length; i++) {
result[i] = fractions[i].subtract(pr[i]);
}
return result;
}

View file

@ -26,9 +26,8 @@ import java.util.List;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.SplineInterpolator;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math3.analysis.interpolation.SplineInterpolator;
import org.apache.commons.math3.analysis.UnivariateFunction;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.libreplan.business.common.ProportionalDistributor;
@ -47,32 +46,30 @@ public enum StretchesFunctionTypeEnum {
@Override
public void apply(ResourceAllocation<?> allocation,
List<Interval> intervalsDefinedByStreches,
LocalDate startInclusive, LocalDate endExclusive,
int totalHours) {
Interval.apply(allocation, intervalsDefinedByStreches,
startInclusive, endExclusive, totalHours);
List<Interval> intervalsDefinedByStreches,
LocalDate startInclusive, LocalDate endExclusive,
int totalHours) {
Interval.apply(allocation, intervalsDefinedByStreches, startInclusive, endExclusive, totalHours);
}
},
INTERPOLATED {
@Override
public void apply(ResourceAllocation<?> allocation,
List<Interval> intervalsDefinedByStreches,
LocalDate startInclusive, LocalDate endExclusive,
int totalHours) {
List<Interval> intervalsDefinedByStreches,
LocalDate startInclusive, LocalDate endExclusive,
int totalHours) {
final Task task = allocation.getTask();
double[] x = Interval.getDayPointsFor(task.getStartAsLocalDate(),
intervalsDefinedByStreches);
double[] x = Interval.getDayPointsFor(task.getStartAsLocalDate(), intervalsDefinedByStreches);
assert x.length == 1 + intervalsDefinedByStreches.size();
double[] y = Interval.getHoursPointsFor(totalHours,
intervalsDefinedByStreches);
double[] y = Interval.getHoursPointsFor(totalHours, intervalsDefinedByStreches);
assert y.length == 1 + intervalsDefinedByStreches.size();
int[] hoursForEachDay = hoursForEachDayUsingSplines(x, y,
startInclusive, endExclusive);
int[] hoursForEachDay = hoursForEachDayUsingSplines(x, y, startInclusive, endExclusive);
Days daysBetween = Days.daysBetween(startInclusive, endExclusive);
assert hoursForEachDay.length == daysBetween.getDays();
@ -84,10 +81,9 @@ public enum StretchesFunctionTypeEnum {
// hours for each day specified by the interpolation. The remainder
// must be distributed.
int[] assignedHours = getAssignedHours(allocation, startInclusive, newEndDate);
int[] remindingHours = distributeRemainder(allocation, startInclusive, totalHours, assignedHours);
int[] remindingHours = distributeRemainder(totalHours, assignedHours);
int[] hoursToAllocate = sum(assignedHours, remindingHours);
allocateDaysFrom(allocation, asEffortDuration(hoursToAllocate),
startInclusive);
allocateDaysFrom(allocation, asEffortDuration(hoursToAllocate), startInclusive);
assignedHours = getAssignedHours(allocation, startInclusive, newEndDate);
Validate.isTrue(sum(assignedHours) == totalHours);
@ -98,132 +94,143 @@ public enum StretchesFunctionTypeEnum {
for (int i = 0; i < assignedHours.length; i++) {
assignedHours[i] += remindingHours[i];
}
return assignedHours;
}
private int[] getAssignedHours(ResourceAllocation<?> allocation,
LocalDate startInclusive, LocalDate endExclusive) {
LocalDate startInclusive,
LocalDate endExclusive) {
final Days daysBetween = Days.daysBetween(startInclusive, endExclusive);
int[] result = new int[daysBetween.getDays()];
LocalDate day = new LocalDate(startInclusive); int i = 0;
while (day.isBefore(endExclusive)) {
result[i++] = allocation.getAssignedHours(day, day.plusDays(1));
day = day.plusDays(1);
}
return result;
}
private void allocateDaysFrom(ResourceAllocation<?> allocation,
List<EffortDuration> hoursToAllocate, LocalDate startInclusive) {
List<EffortDuration> hoursToAllocate,
LocalDate startInclusive) {
final LocalDate endExclusive = startInclusive.plusDays(hoursToAllocate.size());
LOG.debug(String.format("allocate on interval (%s, %s): %s", startInclusive, endExclusive, hoursToAllocate));
allocation.withPreviousAssociatedResources().onInterval(
startInclusive, endExclusive).allocate(hoursToAllocate);
LOG.debug(String.format("allocate on interval (%s, %s): %s",
startInclusive, endExclusive, hoursToAllocate));
allocation.withPreviousAssociatedResources()
.onInterval(startInclusive, endExclusive).allocate(hoursToAllocate);
}
private List<EffortDuration> asEffortDuration(int[] hoursPerDay) {
List<EffortDuration> result = new ArrayList<EffortDuration>();
List<EffortDuration> result = new ArrayList<>();
for (int hours: hoursPerDay) {
result.add(EffortDuration.hours(hours));
}
return result;
}
private int[] distributeRemainder(ResourceAllocation<?> allocation,
LocalDate startInclusive, int totalHours,
int[] reallyAssigned) {
private int[] distributeRemainder(int totalHours, int[] reallyAssigned) {
final int remainder = totalHours - sum(reallyAssigned);
if (remainder == 0) {
if ( remainder == 0 ) {
return new int[reallyAssigned.length];
}
return distributeRemainder(reallyAssigned, remainder);
}
private int[] distributeRemainder(int[] hoursForEachDay,
int remainder) {
ProportionalDistributor remainderDistributor = ProportionalDistributor
.create(hoursForEachDay);
private int[] distributeRemainder(int[] hoursForEachDay, int remainder) {
ProportionalDistributor remainderDistributor = ProportionalDistributor.create(hoursForEachDay);
return remainderDistributor.distribute(remainder);
}
private int sum(int[] array) {
int result = 0;
for (int each : array) {
result += each;
}
return result;
}
private LocalDate lastDayAssignment(ResourceAllocation<?> allocation) {
List<DayAssignment> assignments = (List<DayAssignment>) allocation.getAssignments();
DayAssignment last = assignments.get(assignments.size() - 1);
return last.getDay();
}
};
private static final org.apache.commons.logging.Log LOG = LogFactory
.getLog(StretchesFunctionTypeEnum.class);
private static final org.apache.commons.logging.Log LOG = LogFactory.getLog(StretchesFunctionTypeEnum.class);
public static int[] hoursForEachDayUsingSplines(double[] x, double[] y,
LocalDate startInclusive, LocalDate endExclusive) {
UnivariateRealFunction accumulatingFunction = new SplineInterpolator()
.interpolate(x, y);
int[] extractAccumulated = extractAccumulated(accumulatingFunction,
startInclusive, endExclusive);
return extractHoursShouldAssignForEachDay(ValleyFiller
.fillValley(extractAccumulated));
public static int[] hoursForEachDayUsingSplines(double[] x,
double[] y,
LocalDate startInclusive,
LocalDate endExclusive) {
UnivariateFunction accumulatingFunction = new SplineInterpolator().interpolate(x, y);
int[] extractAccumulated = extractAccumulated(accumulatingFunction, startInclusive, endExclusive);
return extractHoursShouldAssignForEachDay(ValleyFiller.fillValley(extractAccumulated));
}
private static int[] extractAccumulated(
UnivariateRealFunction accumulatedFunction,
LocalDate startInclusive, LocalDate endExclusive) {
int[] result = new int[Days.daysBetween(startInclusive,
endExclusive).getDays()];
private static int[] extractAccumulated(UnivariateFunction accumulatedFunction,
LocalDate startInclusive,
LocalDate endExclusive) {
int[] result = new int[Days.daysBetween(startInclusive, endExclusive).getDays()];
for (int i = 0; i < result.length; i++) {
result[i] = evaluate(accumulatedFunction, i + 1);
}
return result;
}
private static int[] extractHoursShouldAssignForEachDay(
int[] accumulated) {
private static int[] extractHoursShouldAssignForEachDay(int[] accumulated) {
int[] result = new int[accumulated.length];
int previous = 0;
for (int i = 0; i < result.length; i++) {
final int current = accumulated[i];
result[i] = current - previous;
previous = current;
}
return result;
}
private static int evaluate(UnivariateRealFunction accumulatedFunction,
int x) {
try {
return (int) accumulatedFunction.value(x);
} catch (FunctionEvaluationException e) {
throw new RuntimeException(e);
}
private static int evaluate(UnivariateFunction accumulatedFunction, int x) {
return (int) accumulatedFunction.value(x);
}
public void applyTo(ResourceAllocation<?> resourceAllocation,
StretchesFunction stretchesFunction) {
public void applyTo(ResourceAllocation<?> resourceAllocation, StretchesFunction stretchesFunction) {
List<Interval> intervals = new ArrayList<Interval>();
List<Interval> intervals = new ArrayList<>();
intervals.addAll(stretchesFunction.getIntervalsDefinedByStreches());
LocalDate startInclusive = resourceAllocation.getFirstNonConsolidatedDate();
LocalDate endExclusive = resourceAllocation.getIntraDayEndDate()
.asExclusiveEnd();
LocalDate endExclusive = resourceAllocation.getIntraDayEndDate().asExclusiveEnd();
int totalHours = resourceAllocation.getNonConsolidatedHours();
apply(resourceAllocation, intervals, startInclusive, endExclusive, totalHours);
}
protected abstract void apply(ResourceAllocation<?> allocation,
List<Interval> intervalsDefinedByStreches,
LocalDate startInclusive, LocalDate endExclusive, int totalHours);
List<Interval> intervalsDefinedByStreches,
LocalDate startInclusive,
LocalDate endExclusive,
int totalHours);
}

View file

@ -397,9 +397,9 @@
<!-- Commons Math-->
<dependency>
<groupId>commons-math</groupId>
<artifactId>commons-math</artifactId>
<version>1.2</version>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
<!-- Commons Logging (required by many frameworks)-->