ItEr27S06CUAsignacionGrupoRecursosAPlanificacionItEr26S07: Extracting algorithm for allocating when the ResourcesPerDay and the hours are given
This commit is contained in:
parent
5fa07daa1d
commit
5be85aa8ed
2 changed files with 178 additions and 115 deletions
|
|
@ -1,13 +1,7 @@
|
|||
package org.navalplanner.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.validator.NotNull;
|
||||
|
|
@ -16,6 +10,7 @@ import org.joda.time.LocalDate;
|
|||
import org.navalplanner.business.calendars.entities.BaseCalendar;
|
||||
import org.navalplanner.business.calendars.entities.SameWorkHoursEveryDay;
|
||||
import org.navalplanner.business.common.BaseEntity;
|
||||
import org.navalplanner.business.planner.entities.allocationalgorithms.AllocatorForSpecifiedResourcesPerDayAndHours;
|
||||
import org.navalplanner.business.planner.entities.allocationalgorithms.AllocatorForTaskDurationAndSpecifiedResourcesPerDay;
|
||||
import org.navalplanner.business.planner.entities.allocationalgorithms.ResourceAllocationWithDesiredResourcesPerDay;
|
||||
import org.navalplanner.business.resources.entities.Resource;
|
||||
|
|
@ -88,127 +83,37 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
|
|||
|
||||
private final Task task;
|
||||
|
||||
private Map<ResourceAllocationWithDesiredResourcesPerDay, List<DayAssignment>> resultAssignments = new HashMap<ResourceAllocationWithDesiredResourcesPerDay, List<DayAssignment>>();
|
||||
|
||||
public AllocationsAndResourcesCurried(Task task,
|
||||
List<Resource> resources,
|
||||
List<ResourceAllocationWithDesiredResourcesPerDay> allocations) {
|
||||
this.task = task;
|
||||
this.resources = resources;
|
||||
this.allocations = allocations;
|
||||
initializeResultsMap();
|
||||
}
|
||||
|
||||
private void initializeResultsMap() {
|
||||
for (ResourceAllocationWithDesiredResourcesPerDay r : allocations) {
|
||||
resultAssignments.put(r, new ArrayList<DayAssignment>());
|
||||
}
|
||||
}
|
||||
|
||||
public LocalDate untilAllocating(int hoursToAllocate) {
|
||||
int hoursRemaining = hoursToAllocate;
|
||||
LocalDate start = new LocalDate(task.getStartDate().getTime());
|
||||
int day = 0;
|
||||
while (hoursRemaining > 0) {
|
||||
LocalDate current = start.plusDays(day);
|
||||
int taken = assignForDay(current, hoursRemaining);
|
||||
hoursRemaining = hoursRemaining - taken;
|
||||
day++;
|
||||
}
|
||||
setAssignmentsForEachAllocation();
|
||||
return start.plusDays(day);
|
||||
}
|
||||
AllocatorForSpecifiedResourcesPerDayAndHours allocator = new AllocatorForSpecifiedResourcesPerDayAndHours(
|
||||
task, resources, allocations) {
|
||||
|
||||
private void setAssignmentsForEachAllocation() {
|
||||
for (Entry<ResourceAllocationWithDesiredResourcesPerDay, List<DayAssignment>> entry : resultAssignments
|
||||
.entrySet()) {
|
||||
ResourceAllocation<?> allocation = entry.getKey()
|
||||
.getResourceAllocation();
|
||||
ResourcesPerDay resourcesPerDay = entry.getKey()
|
||||
.getResourcesPerDay();
|
||||
allocation.setResourcesPerDay(resourcesPerDay);
|
||||
allocation.resetGenericAssignmentsTo(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private int assignForDay(LocalDate day, int toBeAssigned) {
|
||||
int i = 0;
|
||||
int total = 0;
|
||||
List<Integer> maxPerAllocations = calculateLimits(toBeAssigned);
|
||||
for (ResourceAllocationWithDesiredResourcesPerDay withResourcesPerDay : allocations) {
|
||||
ResourceAllocation<?> resourceAllocation = withResourcesPerDay
|
||||
.getResourceAllocation();
|
||||
ResourcesPerDay resourcesPerDay = withResourcesPerDay
|
||||
.getResourcesPerDay();
|
||||
List<DayAssignment> assigments = resourceAllocation
|
||||
.createAssignmentsAtDay(resources, day,
|
||||
resourcesPerDay, maxPerAllocations.get(i));
|
||||
resultAssignments.get(withResourcesPerDay).addAll(assigments);
|
||||
total += DayAssignment.sum(assigments);
|
||||
i++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private List<Integer> calculateLimits(int toBeAssigned) {
|
||||
BigDecimal[] limits = new BigDecimal[allocations.size()];
|
||||
BigDecimal sumAll = sumAll();
|
||||
for (int i = 0; i < limits.length; i++) {
|
||||
BigDecimal amount = allocations.get(i).getResourcesPerDay()
|
||||
.getAmount();
|
||||
limits[i] = amount.divide(sumAll, RoundingMode.DOWN).multiply(
|
||||
new BigDecimal(toBeAssigned));
|
||||
}
|
||||
final int remainder = toBeAssigned - sumIntegerParts(limits);
|
||||
return distributeRemainder(limits, remainder);
|
||||
}
|
||||
|
||||
private List<Integer> distributeRemainder(BigDecimal[] decimals,
|
||||
final int remainder) {
|
||||
for (int i = 0; i < remainder; i++) {
|
||||
int position = positionOfBiggestDecimalPart(decimals);
|
||||
decimals[position] = new BigDecimal(decimals[position]
|
||||
.intValue() + 1);
|
||||
}
|
||||
return asIntegers(decimals);
|
||||
}
|
||||
|
||||
private List<Integer> asIntegers(BigDecimal[] decimals) {
|
||||
Integer[] result = new Integer[decimals.length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = decimals[i].intValue();
|
||||
}
|
||||
return Arrays.asList(result);
|
||||
}
|
||||
|
||||
private int positionOfBiggestDecimalPart(BigDecimal[] decimals) {
|
||||
int result = 0;
|
||||
BigDecimal currentBiggestDecimalPart = new BigDecimal(0);
|
||||
for (int i = 0; i < decimals.length; i++) {
|
||||
BigDecimal fractionalPart = decimals[i]
|
||||
.subtract(new BigDecimal(decimals[i].intValue()));
|
||||
if (currentBiggestDecimalPart.compareTo(fractionalPart) < 0) {
|
||||
currentBiggestDecimalPart = fractionalPart;
|
||||
result = i;
|
||||
@Override
|
||||
protected List<DayAssignment> createAssignmentsAtDay(
|
||||
ResourceAllocation<?> resourceAllocation,
|
||||
List<Resource> resources, LocalDate day, ResourcesPerDay resourcesPerDay ,Integer limit) {
|
||||
return resourceAllocation.createAssignmentsAtDay(resources,
|
||||
day,
|
||||
resourcesPerDay, limit);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int sumIntegerParts(BigDecimal[] decimals) {
|
||||
int sum = 0;
|
||||
for (BigDecimal decimal : decimals) {
|
||||
sum += decimal.intValue();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private BigDecimal sumAll() {
|
||||
BigDecimal result = new BigDecimal(0);
|
||||
for (ResourceAllocationWithDesiredResourcesPerDay r : allocations) {
|
||||
result = result.add(r.getResourcesPerDay().getAmount());
|
||||
}
|
||||
return result;
|
||||
@Override
|
||||
protected void setNewDataForAllocation(
|
||||
ResourceAllocation<?> allocation,
|
||||
ResourcesPerDay resourcesPerDay,
|
||||
List<DayAssignment> dayAssignments) {
|
||||
allocation.setResourcesPerDay(resourcesPerDay);
|
||||
allocation.resetGenericAssignmentsTo(dayAssignments);
|
||||
}
|
||||
};
|
||||
return allocator.untilAllocating(hoursToAllocate);
|
||||
}
|
||||
|
||||
public void allocateOnTaskLength() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
package org.navalplanner.business.planner.entities.allocationalgorithms;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.planner.entities.DayAssignment;
|
||||
import org.navalplanner.business.planner.entities.ResourceAllocation;
|
||||
import org.navalplanner.business.planner.entities.ResourcesPerDay;
|
||||
import org.navalplanner.business.planner.entities.Task;
|
||||
import org.navalplanner.business.resources.entities.Resource;
|
||||
|
||||
public abstract class AllocatorForSpecifiedResourcesPerDayAndHours {
|
||||
|
||||
private final Task task;
|
||||
|
||||
private List<Resource> resources;
|
||||
|
||||
private List<ResourceAllocationWithDesiredResourcesPerDay> allocations;
|
||||
|
||||
private Map<ResourceAllocationWithDesiredResourcesPerDay, List<DayAssignment>> resultAssignments = new HashMap<ResourceAllocationWithDesiredResourcesPerDay, List<DayAssignment>>();
|
||||
|
||||
public AllocatorForSpecifiedResourcesPerDayAndHours(Task task,
|
||||
List<Resource> resources,
|
||||
List<ResourceAllocationWithDesiredResourcesPerDay> allocations) {
|
||||
this.task = task;
|
||||
this.resources = resources;
|
||||
this.allocations = allocations;
|
||||
initializeResultsMap();
|
||||
}
|
||||
|
||||
private void initializeResultsMap() {
|
||||
for (ResourceAllocationWithDesiredResourcesPerDay r : allocations) {
|
||||
resultAssignments.put(r, new ArrayList<DayAssignment>());
|
||||
}
|
||||
}
|
||||
|
||||
public LocalDate untilAllocating(int hoursToAllocate) {
|
||||
int hoursRemaining = hoursToAllocate;
|
||||
LocalDate start = new LocalDate(task.getStartDate().getTime());
|
||||
int day = 0;
|
||||
while (hoursRemaining > 0) {
|
||||
LocalDate current = start.plusDays(day);
|
||||
int taken = assignForDay(current, hoursRemaining);
|
||||
hoursRemaining = hoursRemaining - taken;
|
||||
day++;
|
||||
}
|
||||
setAssignmentsForEachAllocation();
|
||||
return start.plusDays(day);
|
||||
}
|
||||
|
||||
private void setAssignmentsForEachAllocation() {
|
||||
for (Entry<ResourceAllocationWithDesiredResourcesPerDay, List<DayAssignment>> entry : resultAssignments
|
||||
.entrySet()) {
|
||||
ResourceAllocation<?> allocation = entry.getKey()
|
||||
.getResourceAllocation();
|
||||
ResourcesPerDay resourcesPerDay = entry.getKey()
|
||||
.getResourcesPerDay();
|
||||
List<DayAssignment> value = entry.getValue();
|
||||
setNewDataForAllocation(allocation, resourcesPerDay, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void setNewDataForAllocation(
|
||||
ResourceAllocation<?> allocation, ResourcesPerDay resourcesPerDay,
|
||||
List<DayAssignment> dayAssignments);
|
||||
|
||||
protected abstract List<DayAssignment> createAssignmentsAtDay(
|
||||
ResourceAllocation<?> resourceAllocation, List<Resource> resources,
|
||||
LocalDate day, ResourcesPerDay resourcesPerDay, Integer limit);
|
||||
|
||||
private int assignForDay(LocalDate day, int toBeAssigned) {
|
||||
int i = 0;
|
||||
int total = 0;
|
||||
List<Integer> maxPerAllocations = calculateLimits(toBeAssigned);
|
||||
for (ResourceAllocationWithDesiredResourcesPerDay withResourcesPerDay : allocations) {
|
||||
ResourceAllocation<?> resourceAllocation = withResourcesPerDay
|
||||
.getResourceAllocation();
|
||||
ResourcesPerDay resourcesPerDay = withResourcesPerDay
|
||||
.getResourcesPerDay();
|
||||
List<DayAssignment> assignments = createAssignmentsAtDay(
|
||||
resourceAllocation, resources, day,
|
||||
resourcesPerDay, maxPerAllocations.get(i));
|
||||
resultAssignments.get(withResourcesPerDay).addAll(assignments);
|
||||
total += DayAssignment.sum(assignments);
|
||||
i++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private List<Integer> calculateLimits(int toBeAssigned) {
|
||||
BigDecimal[] limits = new BigDecimal[allocations.size()];
|
||||
BigDecimal sumAll = sumAll();
|
||||
for (int i = 0; i < limits.length; i++) {
|
||||
BigDecimal amount = allocations.get(i).getResourcesPerDay()
|
||||
.getAmount();
|
||||
limits[i] = amount.divide(sumAll, RoundingMode.DOWN).multiply(
|
||||
new BigDecimal(toBeAssigned));
|
||||
}
|
||||
final int remainder = toBeAssigned - sumIntegerParts(limits);
|
||||
return distributeRemainder(limits, remainder);
|
||||
}
|
||||
|
||||
private List<Integer> distributeRemainder(BigDecimal[] decimals,
|
||||
final int remainder) {
|
||||
for (int i = 0; i < remainder; i++) {
|
||||
int position = positionOfBiggestDecimalPart(decimals);
|
||||
decimals[position] = new BigDecimal(
|
||||
decimals[position].intValue() + 1);
|
||||
}
|
||||
return asIntegers(decimals);
|
||||
}
|
||||
|
||||
private List<Integer> asIntegers(BigDecimal[] decimals) {
|
||||
Integer[] result = new Integer[decimals.length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = decimals[i].intValue();
|
||||
}
|
||||
return Arrays.asList(result);
|
||||
}
|
||||
|
||||
private int positionOfBiggestDecimalPart(BigDecimal[] decimals) {
|
||||
int result = 0;
|
||||
BigDecimal currentBiggestDecimalPart = new BigDecimal(0);
|
||||
for (int i = 0; i < decimals.length; i++) {
|
||||
BigDecimal fractionalPart = decimals[i].subtract(new BigDecimal(
|
||||
decimals[i].intValue()));
|
||||
if (currentBiggestDecimalPart.compareTo(fractionalPart) < 0) {
|
||||
currentBiggestDecimalPart = fractionalPart;
|
||||
result = i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int sumIntegerParts(BigDecimal[] decimals) {
|
||||
int sum = 0;
|
||||
for (BigDecimal decimal : decimals) {
|
||||
sum += decimal.intValue();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private BigDecimal sumAll() {
|
||||
BigDecimal result = new BigDecimal(0);
|
||||
for (ResourceAllocationWithDesiredResourcesPerDay r : allocations) {
|
||||
result = result.add(r.getResourcesPerDay().getAmount());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue