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--> <!-- Commons Math-->
<dependency> <dependency>
<groupId>commons-math</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-math</artifactId> <artifactId>commons-math3</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>joda-time</groupId> <groupId>joda-time</groupId>

View file

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

View file

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

View file

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

View file

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