<commit_before>package org.navalplanner.business.planner.entities;

import java.math.BigDecimal;

import org.joda.time.Days;
import org.joda.time.LocalDate;

/**
 *
 * @author <NAME><<EMAIL>>
 *
 */
public class SigmoidFunction extends AssignmentFunction {

    private static final int PRECISSION = 6;

    private static final int ROUND_MODE = BigDecimal.ROUND_HALF_EVEN;

    // Fragmentation of hours (0.25, 0.50, 0.75, 1). 1 indicates no fragmentation
    private static final BigDecimal HOUR_FRAGMENTATION = BigDecimal.valueOf(1);

    public static SigmoidFunction create() {
        return create(new SigmoidFunction());
    }

    protected SigmoidFunction() {

    }

    @Override
    public void applyTo(ResourceAllocation<?> resourceAllocation) {
        final Task task = resourceAllocation.getTask();
        LocalDate start = LocalDate.fromDateFields(task.getStartDate());
        LocalDate end = LocalDate.fromDateFields(task.getEndDate());
        int totalHours = resourceAllocation.getAssignedHours();

        apply(resourceAllocation, start, end, totalHours);
    }

    private void apply(ResourceAllocation<?> resourceAllocation,
            LocalDate start, LocalDate end, int totalHours) {

        final int daysDuration = Days.daysBetween(start, end).getDays();

        // Calculate hours per day and round values (take only integer part)
        BigDecimal[] hoursToAllocatePerDay = generateHoursToAllocateFor(daysDuration, totalHours);
        hoursToAllocatePerDay = roundValues(hoursToAllocatePerDay, HOUR_FRAGMENTATION);

        // Calculate reminder (difference between totalHours and sum of hours calculated)
        BigDecimal totalHoursToAllocate = sumHoursPerDay(hoursToAllocatePerDay);
        assert(totalHoursToAllocate.compareTo(BigDecimal.valueOf(totalHours)) <= 0);
        BigDecimal remindingHours = BigDecimal.valueOf(totalHours).subtract(totalHoursToAllocate);
        allocateRemindingHours(hoursToAllocatePerDay, remindingHours);

        // Starting from startDate allocatem, one slot of hours per day in resource
        LocalDate day = new LocalDate(start);
        int hours = 0, i = 0;
        for (; i < hoursToAllocatePerDay.length; i++) {
            hours = hoursToAllocatePerDay[i].intValue();
            apply(resourceAllocation, day, hours);
            day = day.plusDays(1);
        }

        clearPreviouslyAllocatedDays(resourceAllocation, day, end);
    }

    private void clearPreviouslyAllocatedDays(
            ResourceAllocation<?> resourceAllocation, LocalDate start,
            LocalDate end) {

        while (start.isBefore(end) || start.isEqual(end)) {
            apply(resourceAllocation, start, 0);
            start = start.plusDays(1);
        }
    }

    private void allocateRemindingHours(BigDecimal[] hoursToAllocatePerDay, BigDecimal remindingHours) {
        final int length = hoursToAllocatePerDay.length;

        // Add reminding hours to best fit in a way that the distribution of
        // hours grows continuously
        for (int i = 0; i < length - 1; i++) {
            BigDecimal current = hoursToAllocatePerDay[i];
            BigDecimal next = hoursToAllocatePerDay[i+1];

            if (current.add(remindingHours).compareTo(next) <= 0) {
                hoursToAllocatePerDay[i] = current.add(remindingHours);
                return;
            }
        }

        // Add reminding hours to last day
        BigDecimal lastDay = hoursToAllocatePerDay[length - 1];
        hoursToAllocatePerDay[length - 1] = lastDay.add(remindingHours);
    }

    private void showSamplePointValues(BigDecimal[] samplePointValues) {
        for (int i = 0; i < samplePointValues.length; i++) {
            System.out.println(String.format("%d: %f", i, samplePointValues[i]));
        }
     }

    private void apply(ResourceAllocation<?> resourceAllocation,
            LocalDate day, int hours) {
        resourceAllocation.withPreviousAssociatedResources()
                .onInterval(day, day.plusDays(1))
                .allocateHours(hours);
    }
<commit_msg>Fix bug respect bank holidays and weekend on applying Sigmoid function<commit_after>package org.navalplanner.business.planner.entities;

import java.math.BigDecimal;

import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.BaseCalendar;
import org.navalplanner.business.workingday.EffortDuration;
import org.navalplanner.business.workingday.IntraDayDate.PartialDay;

/**
 *
 * @author <NAME><<EMAIL>>
 *
 */
public class SigmoidFunction extends AssignmentFunction {

    private static final int PRECISSION = 6;

    private static final int ROUND_MODE = BigDecimal.ROUND_HALF_EVEN;

    // Fragmentation of hours (0.25, 0.50, 0.75, 1). 1 indicates no fragmentation
    private static final BigDecimal HOUR_FRAGMENTATION = BigDecimal.valueOf(1);

    public static SigmoidFunction create() {
        return create(new SigmoidFunction());
    }

    protected SigmoidFunction() {

    }

    @Override
    public void applyTo(ResourceAllocation<?> resourceAllocation) {
        final Task task = resourceAllocation.getTask();
        LocalDate start = LocalDate.fromDateFields(task.getStartDate());
        LocalDate end = LocalDate.fromDateFields(task.getEndDate());
        int totalHours = resourceAllocation.getAssignedHours();

        apply(resourceAllocation, start, end, totalHours);
    }

    private void apply(ResourceAllocation<?> resourceAllocation,
            LocalDate start, LocalDate end, int totalHours) {

        final int daysDuration = Days.daysBetween(start, end).getDays();
        EffortDuration capacity;

        // Calculate hours per day and round values (take only integer part)
        BigDecimal[] hoursToAllocatePerDay = generateHoursToAllocateFor(daysDuration, totalHours);
        hoursToAllocatePerDay = roundValues(hoursToAllocatePerDay, HOUR_FRAGMENTATION);

        // Calculate reminder (difference between totalHours and sum of hours calculated)
        BigDecimal totalHoursToAllocate = sumHoursPerDay(hoursToAllocatePerDay);
        assert(totalHoursToAllocate.compareTo(BigDecimal.valueOf(totalHours)) <= 0);
        BigDecimal remindingHours = BigDecimal.valueOf(totalHours).subtract(totalHoursToAllocate);
        allocateRemindingHours(hoursToAllocatePerDay, remindingHours);

        // Starting from startDate do allocation, one slot of hours per day in resource
        BaseCalendar calendar = resourceAllocation.getTask().getCalendar();
        LocalDate day = new LocalDate(start);
        int hours = 0, i = 0;
        for (; i < hoursToAllocatePerDay.length;) {
            hours = hoursToAllocatePerDay[i].intValue();
            capacity = calendar.getCapacityOn(PartialDay.wholeDay(day));
            if (!EffortDuration.zero().equals(capacity)) {
                allocate(resourceAllocation, day, hours);
                i++;
            }
            day = day.plusDays(1);
        }

        clearPreviouslyAllocatedDays(resourceAllocation, day, end);
    }

    private void clearPreviouslyAllocatedDays(
            ResourceAllocation<?> resourceAllocation, LocalDate start,
            LocalDate end) {

        while (start.isBefore(end) || start.isEqual(end)) {
            allocate(resourceAllocation, start, 0);
            start = start.plusDays(1);
        }
    }

    private void allocateRemindingHours(BigDecimal[] hoursToAllocatePerDay, BigDecimal remindingHours) {
        final int length = hoursToAllocatePerDay.length;

        // Add reminding hours to best fit in a way that the distribution of
        // hours grows continuously
        for (int i = 0; i < length - 1; i++) {
            BigDecimal current = hoursToAllocatePerDay[i];
            BigDecimal next = hoursToAllocatePerDay[i+1];

            if (current.add(remindingHours).compareTo(next) <= 0) {
                hoursToAllocatePerDay[i] = current.add(remindingHours);
                return;
            }
        }

        // Add reminding hours to last day
        BigDecimal lastDay = hoursToAllocatePerDay[length - 1];
        hoursToAllocatePerDay[length - 1] = lastDay.add(remindingHours);
    }

    private void showSamplePointValues(BigDecimal[] samplePointValues) {
        for (int i = 0; i < samplePointValues.length; i++) {
            System.out.println(String.format("%d: %f", i, samplePointValues[i]));
        }
     }

    private void allocate(ResourceAllocation<?> resourceAllocation,
            LocalDate day, int hours) {
        final LocalDate nextDay = day.plusDays(1);
        resourceAllocation.withPreviousAssociatedResources()
                .onInterval(day, nextDay).allocateHours(hours);
    }

{'fraction_non_alphanumeric': 0.09175577785443256, 'fraction_numerical': 0.006209037599172128, 'mean_word_length': 3.0027611596870685, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3756550', 'n_tokens_mistral': 2491, 'n_tokens_neox': 2360, 'n_words': 561}