/*
* This file is part of the TimeFinder project.
* Visit http://www.timefinder.de for more information.
* Copyright (c) 2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.timefinder.algo.ncp;
import de.timefinder.algo.ConflictMatrix;
import de.timefinder.algo.constraint.RasterConstraint;
import de.timefinder.algo.util.TimeFinder2Tester;
import de.timefinder.data.Feature;
import de.timefinder.data.Location;
import de.timefinder.data.Person;
import de.timefinder.data.Resource;
import de.timefinder.data.algo.Assignment;
import de.timefinder.data.set.RasterEnum;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javolution.util.FastMap;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
* @author Peter Karich, peat_hal 'at' users 'dot' sourceforge 'dot' net
*/
public class PeriodTest extends TimeFinder2Tester {
private Period periode;
private ConflictMatrix conflictingMatrix;
public PeriodTest() {
}
@Before
@Override
public void setUp() {
super.setUp();
conflictingMatrix = new ConflictMatrix(5, 5);
List locArray = Arrays.asList(new Location(10));
periode = newPeriod(5, locArray, conflictingMatrix);
}
private Period newPeriod(int days, List<Location> locations, ConflictMatrix cMatrix) {
return new Period(days, new ArrayList<Assignment>(), new FastMap<Assignment, Set<Assignment>>(),
new FastMap<Assignment, Set<Assignment>>(), new ArrayList<Location>(locations),
new FastMap<Person, Set<Assignment>>(), cMatrix);
}
@Test
public void testRollbackDoMove() {
System.out.println("testRollback");
Assignment ev = newAssignment(-1, 1);
conflictingMatrix.initAssignments(Collections.singletonList(ev));
assertTrue(periode.add(ev, 0));
assertEquals(0, periode.getEventMoveStack().size());
assertTrue(periode.doMove(ev, 1));
assertEquals(1, periode.getEventMoveStack().size());
periode.rollback(0);
assertEquals(0, ev.getStart());
assertEquals(0, periode.getEventMoveStack().size());
}
@Test
public void testASimpleInjectOfAssignmentA() {
System.out.println("testASimpleInjectOfAssignmentA");
// the test week is a bit smaller
int slotsPerWeek = 2;
int slotsPerDay = 2;
final Assignment a = newAssignment("a", -1, 1);
final Assignment b = newAssignment("b", -1, 1);
final Assignment c = newAssignment("c", -1, 1);
ConflictMatrix matrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
Map<Resource, Set<Assignment>> resources = newResources(Arrays.asList(a, b), Arrays.asList(a, c));
matrix.initFromResources(resources);
Location loc1 = new Location(10);
Location loc2 = new Location(5);
List locations = Arrays.asList(loc1, loc2);
periode = newPeriod(slotsPerWeek, locations, matrix);
assertTrue(periode.add(b, 0));
assertEquals(loc1, b.getLocation());
assertTrue(periode.add(c, 1));
assertEquals(loc1, c.getLocation());
periode.add(a, -1);
// no more free slots are available for event A
assertEquals(-1, matrix.getConflictingRaster(a).getLastFreePlus1(0));
// but we could injectAt event A, if we allow moving at least one colliding event
int depth = 1;
int collidingAssignments = 0;
assertEquals(false, periode.inject(a, depth, collidingAssignments));
assertEquals(-1, a.getStart());
collidingAssignments = 1;
assertTrue(periode.inject(a, depth, collidingAssignments));
assertTrue(a.getStart() >= 0);
}
@Test
public void testInjectWithRollback() {
System.out.println("testInjectWithRollback");
// the test week is a bit smaller
int slotsPerWeek = 3;
int slotsPerDay = 3;
settings.setTimeslotsPerDay(slotsPerDay);
settings.setNumberOfDays(slotsPerWeek / slotsPerDay);
final Assignment a = newAssignment("a", -1, 1);
final Assignment b = newAssignment("b", -1, 1);
final Assignment c = newAssignment("c", -1, 1);
final Assignment d = newAssignment("d", -1, 1);
d.getEvent().putConstraint(newForbidden(1, 2));
final int LIMITING_CAPACITY = 5;
ConflictMatrix matrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
Map<Resource, Set<Assignment>> resources = newResources(Arrays.asList(d, b), Arrays.asList(d, a), Arrays.asList(c));
matrix.initFromResources(resources);
// add more visiors => force d into location with 10 seats
for (int i = 0; i < LIMITING_CAPACITY + 1; i++) {
b.getEvent().addPerson(new Person(), true);
c.getEvent().addPerson(new Person(), true);
}
List locations = Arrays.asList(new Location(10), new Location(LIMITING_CAPACITY));
periode = newPeriod(slotsPerWeek, locations, matrix);
assertTrue(periode.add(b, 0));
assertTrue(periode.add(a, 0));
assertTrue(periode.add(c, 1));
periode.add(d, -1);
assertEquals(true, d.getStart() < 0);
int depth = 2;
int collidingAssignment = 2;
assertEquals(true, periode.inject(d, depth, collidingAssignment));
assertEquals(0, d.getStart());
}
private RasterConstraint newForbidden(Integer... values) {
RasterConstraint constraint = newRasterConstraint();
for (Integer i : values) {
constraint.getRaster().set(i, RasterEnum.FORBIDDEN);
}
return constraint;
}
@Test
public void testInjectWithRemoveCollidingAndMoveCurrentBeforeGoingDeeper() {
System.out.println("testInjectWithRemoveCollidingAndMoveCurrentBeforeGoingDeeper");
int slotsPerWeek = 2;
int slotsPerDay = 2;
settings.setTimeslotsPerDay(slotsPerDay);
settings.setNumberOfDays(slotsPerWeek / slotsPerDay);
final Assignment a = newAssignment("a", -1, 1);
final Assignment b = newAssignment("b", -1, 1);
final Assignment c = newAssignment("c", -1, 1);
ConflictMatrix matrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
matrix.initFromResources(newResources(Arrays.asList(a, b), Arrays.asList(a, c), Arrays.asList(b, c)));
List locations = Arrays.asList(new Location(5));
periode = newPeriod(slotsPerWeek, locations, matrix);
periode.setRandom(new Random());
assertTrue(periode.add(b, 0));
assertTrue(periode.add(c, 1));
periode.add(a, -1);
assertEquals(true, a.getStart() < 0);
int depth = 3;
int collidingAssignment = 3;
assertFalse("assign shouldn't be possible:" + a, periode.inject(a, depth, collidingAssignment));
}
@Test
public void testMoveAndRollback() {
int slotsPerWeek = 2;
int slotsPerDay = 2;
settings.setTimeslotsPerDay(slotsPerDay);
settings.setNumberOfDays(slotsPerWeek / slotsPerDay);
final Assignment a = newAssignment("a", -1, 1);
ConflictMatrix matrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
matrix.initFromResources(newResources(Arrays.asList(a)));
Location loc = new Location(5);
List locations = Arrays.asList(loc);
periode = newPeriod(slotsPerWeek, locations, matrix);
periode.setRandom(new Random());
assertTrue(periode.doMove(a, 0));
assertEquals(0, a.getStart());
assertEquals(loc, a.getLocation());
periode.rollback(0);
assertEquals(-1, a.getStart());
}
@Test
public void testAddingRoomsWithBiggerDuration() {
int slotsPerWeek = 4;
int slotsPerDay = 4;
settings.setTimeslotsPerDay(slotsPerDay);
settings.setNumberOfDays(slotsPerWeek / slotsPerDay);
final Assignment a = newAssignment("a", -1, 2);
final Assignment b = newAssignment("b", -1, 2);
final Assignment c = newAssignment("c", -1, 2);
ConflictMatrix matrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
matrix.initFromResources(newResources(Arrays.asList(a, b), Arrays.asList(a, c), Arrays.asList(b, c)));
List locations = Arrays.asList(new Location(5));
periode = newPeriod(slotsPerWeek, locations, matrix);
periode.setRandom(new Random());
assertTrue(periode.add(b, 0));
assertFalse(periode.add(c, 1));
assertTrue(periode.add(c, 2));
periode.add(a, -1);
assertEquals(-1, a.getStart());
assertEquals(0, b.getStart());
assertEquals(2, c.getStart());
int depth = 3;
int collidingAssignment = 3;
assertFalse(periode.inject(a, depth, collidingAssignment));
assertNotNull(periode.remove(b));
assertNotNull(periode.remove(c));
assertNotNull(periode.remove(a));
}
@Test
public void testConflictingMatrixEntryClear() {
int slotsPerWeek = 6;
int slotsPerDay = 6;
settings.setTimeslotsPerDay(slotsPerDay);
settings.setNumberOfDays(slotsPerWeek / slotsPerDay);
final Assignment a = newAssignment("a", -1, 2);
final Assignment b = newAssignment("b", -1, 2);
final Assignment c = newAssignment("c", -1, 2);
ConflictMatrix conflictMatrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
conflictMatrix.initFromResources(newResources(Arrays.asList(a, b), Arrays.asList(a, c), Arrays.asList(b, c)));
List locations = Arrays.asList(new Location(5));
periode = newPeriod(slotsPerWeek, locations, conflictMatrix);
periode.setRandom(new Random());
// 'spread'
assertTrue(periode.add(b, 0));
periode.add(c, -1);
// 'compress' with injectAt which is not possible
assertEquals(3, conflictMatrix.getConflictingAssignments(b).size());
assertEquals(3, conflictMatrix.getConflictingAssignments(c).size());
// again spread; show the different use cases of move and addToUnassignedHead
periode.moveToUnassignedHead(b);
periode.clearInvalid();
assertTrue(periode.add(b, 2));
assertEquals(2, b.getStart());
try {
// remove has to be called before add:
periode.add(b, 0);
assertTrue(false);
} catch (Exception ex) {
}
// try {
// // TODO
// periode.add(b, -1);
// assertTrue(false);
// } catch (Exception ex) {
// }
// remove event from index
periode.moveToUnassignedHead(b);
periode.clearInvalid();
// now no exception occurs
periode.add(b, -1);
assertTrue(periode.getInvalidAssignments().contains(b));
}
@Test
public void testSameLocation() {
int slotsPerWeek = 6;
int slotsPerDay = 6;
settings.setTimeslotsPerDay(slotsPerDay);
settings.setNumberOfDays(slotsPerWeek / slotsPerDay);
final Assignment a = newAssignment("a", -1, 1);
final Assignment b = newAssignment("b", -1, 2);
ConflictMatrix conflictMatrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
conflictMatrix.initFromResources(newResources(Arrays.asList(a), Arrays.asList(b)));
final Location loc1 = new Location(5);
final Location loc2 = new Location(10);
List locations = Arrays.asList(loc1, loc2);
periode = newPeriod(slotsPerWeek, locations, conflictMatrix);
periode.setRandom(new Random());
assertTrue(periode.add(a, 0));
assertTrue(periode.add(b, 0));
assertNotNull(a.getLocation());
assertNotNull(b.getLocation());
assertNotSame(a.getLocation(), b.getLocation());
}
@Test
public void testTestReassignmentWithBiggerDuration() {
int slotsPerWeek = 6;
int slotsPerDay = 6;
settings.setTimeslotsPerDay(slotsPerDay);
settings.setNumberOfDays(slotsPerWeek / slotsPerDay);
Feature loc1Feature = newFeature("special");
Assignment ass1 = newAssignment("1", -1, 2);
ass1.getEvent().addFeature(loc1Feature);
Assignment ass2 = newAssignment("2", -1, 2);
Assignment ass3 = newAssignment("3", -1, 1);
ConflictMatrix conflictMatrix = new ConflictMatrix(slotsPerWeek, slotsPerDay);
conflictMatrix.initFromResources(newResources(Arrays.asList(ass1), Arrays.asList(ass2), Arrays.asList(ass3)));
final Location loc1 = new Location(5);
final Location loc2 = new Location(10);
loc1.addFeature(loc1Feature);
List locations = Arrays.asList(loc1, loc2);
periode = newPeriod(slotsPerWeek, locations, conflictMatrix);
periode.setRandom(new Random());
assertEquals(true, periode.add(ass3, 2));
assertEquals(true, periode.add(ass2, 1));
assertEquals(loc2, ass3.getLocation());
assertEquals(loc1, ass2.getLocation());
// event with duration==1 cannot move larger event (ass2)
assertEquals(false, periode.add(ass1, 0));
assertNotNull(periode.remove(ass3));
assertNotNull(periode.remove(ass2));
ass3.getEvent().addFeature(loc1Feature);
assertEquals(true, periode.add(ass3, 2));
assertEquals(true, periode.add(ass2, 1));
assertEquals(loc1, ass3.getLocation());
assertEquals(loc2, ass2.getLocation());
}
}