From b8b671bb581f5f9c74925bbc33e0c1fde03d69b7 Mon Sep 17 00:00:00 2001 From: Nicolas Payette Date: Tue, 12 Mar 2024 19:02:11 +0000 Subject: [PATCH] add test for actionPreferenceOverrides --- .../DrawThenCheapestInsertionPlannerTest.java | 148 ++++++++++++++---- 1 file changed, 117 insertions(+), 31 deletions(-) diff --git a/POSEIDON/src/test/java/uk/ac/ox/oxfish/fisher/purseseiner/planner/DrawThenCheapestInsertionPlannerTest.java b/POSEIDON/src/test/java/uk/ac/ox/oxfish/fisher/purseseiner/planner/DrawThenCheapestInsertionPlannerTest.java index 518ce0c79..eb3d9dbe0 100644 --- a/POSEIDON/src/test/java/uk/ac/ox/oxfish/fisher/purseseiner/planner/DrawThenCheapestInsertionPlannerTest.java +++ b/POSEIDON/src/test/java/uk/ac/ox/oxfish/fisher/purseseiner/planner/DrawThenCheapestInsertionPlannerTest.java @@ -1,36 +1,35 @@ /* - * POSEIDON, an agent-based model of fisheries - * Copyright (C) 2022 CoHESyS Lab cohesys.lab@gmail.com + * POSEIDON, an agent-based model of fisheries + * Copyright (C) 2024 CoHESyS Lab cohesys.lab@gmail.com * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * This program is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . */ package uk.ac.ox.oxfish.fisher.purseseiner.planner; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import ec.util.MersenneTwisterFast; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import sim.util.Int2D; import uk.ac.ox.oxfish.fisher.Fisher; +import uk.ac.ox.oxfish.fisher.equipment.Boat; +import uk.ac.ox.oxfish.fisher.purseseiner.actions.ActionClass; import uk.ac.ox.oxfish.fisher.purseseiner.equipment.PurseSeineGear; import uk.ac.ox.oxfish.fisher.purseseiner.fads.FadManager; import uk.ac.ox.oxfish.fisher.purseseiner.strategies.fields.DeploymentLocationValues; import uk.ac.ox.oxfish.geography.ManhattanDistance; import uk.ac.ox.oxfish.geography.NauticalMap; +import uk.ac.ox.oxfish.geography.ports.Port; import uk.ac.ox.oxfish.model.FishState; import uk.ac.ox.poseidon.common.core.parameters.FixedDoubleParameter; @@ -38,8 +37,12 @@ import java.util.List; import java.util.Map; +import static java.util.stream.Collectors.counting; +import static java.util.stream.Collectors.groupingBy; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +import static uk.ac.ox.oxfish.geography.TestUtilities.makeCornerPortMap; import static uk.ac.ox.oxfish.geography.TestUtilities.makeMap; public class DrawThenCheapestInsertionPlannerTest { @@ -101,16 +104,16 @@ public void plansTheRightAmountOfFishing() { System.out.println(plan); final List plannedActions = plan.plannedActions(); // should have ordered it right - Assertions.assertEquals(plannedActions.get(1).getLocation().getGridX(), 1); - Assertions.assertEquals(plannedActions.get(1).getLocation().getGridY(), 1); - Assertions.assertEquals(plannedActions.get(2).getLocation().getGridX(), 1); - Assertions.assertEquals(plannedActions.get(2).getLocation().getGridY(), 1); - Assertions.assertEquals(plannedActions.get(3).getLocation().getGridX(), 2); - Assertions.assertEquals(plannedActions.get(3).getLocation().getGridY(), 2); - Assertions.assertEquals(plannedActions.get(4).getLocation().getGridX(), 5); - Assertions.assertEquals(plannedActions.get(4).getLocation().getGridY(), 0); - Assertions.assertEquals(plannedActions.get(5).getLocation().getGridX(), 0); - Assertions.assertEquals(plannedActions.get(5).getLocation().getGridY(), 0); + assertEquals(plannedActions.get(1).getLocation().getGridX(), 1); + assertEquals(plannedActions.get(1).getLocation().getGridY(), 1); + assertEquals(plannedActions.get(2).getLocation().getGridX(), 1); + assertEquals(plannedActions.get(2).getLocation().getGridY(), 1); + assertEquals(plannedActions.get(3).getLocation().getGridX(), 2); + assertEquals(plannedActions.get(3).getLocation().getGridY(), 2); + assertEquals(plannedActions.get(4).getLocation().getGridX(), 5); + assertEquals(plannedActions.get(4).getLocation().getGridY(), 0); + assertEquals(plannedActions.get(5).getLocation().getGridX(), 0); + assertEquals(plannedActions.get(5).getLocation().getGridY(), 0); } @@ -148,8 +151,9 @@ public void replan() { ); final DeploymentLocationValues dplValues = new DeploymentLocationValues(__ -> initialValues, 1.0); - final DeploymentFromLocationValuePlanningModule deploymentModule = new DeploymentFromLocationValuePlanningModule( - dplValues, map, rng, 1.0); + final DeploymentFromLocationValuePlanningModule deploymentModule = + new DeploymentFromLocationValuePlanningModule( + dplValues, map, rng, 1.0); final PurseSeineGear gear = mock(PurseSeineGear.class); when(fisher.getGear()).thenReturn(gear); final FadManager fadmanager = mock(FadManager.class); @@ -199,20 +203,102 @@ public void replan() { } System.out.println(numberOfDPLAfterReplan); System.out.println(otherActionsAfterReplan); - Assertions.assertEquals(numberOfDPLAfterReplan, numberOfDPLBeforeReplan); + assertEquals(numberOfDPLAfterReplan, numberOfDPLBeforeReplan); // you should also go to 10,10 before doing those DPLs final List plannedActions = plan.plannedActions(); - Assertions.assertEquals(plannedActions.get(2).getLocation().getGridX(), 10); - Assertions.assertEquals(plannedActions.get(2).getLocation().getGridY(), 10); + assertEquals(plannedActions.get(2).getLocation().getGridX(), 10); + assertEquals(plannedActions.get(2).getLocation().getGridY(), 10); System.out.println(plan); // because we teleported you at 5,5 and consumed only 5 hours (rather than the 10 it takes) // and because you can only take FSH and not DPL; you should have increased the amount of FSH actions // in the replan - Assertions.assertTrue(otherActionsAfterReplan > otherActions); + assertTrue(otherActionsAfterReplan > otherActions); // in fact it should increase by precisely 5 times (but rounding may screw this up) } // todo plan test where you have some nulls + @Test + public void actionPreferenceOverrides() { + + final NauticalMap map = makeCornerPortMap(1, 2); + final Port port = map.getPorts().get(0); + final Boat boat = mock(Boat.class); + when(boat.getSpeedInKph()).thenReturn(100.0); + + final Fisher fisher = mock(Fisher.class); + when(fisher.getLocation()).thenReturn(port.getLocation()); + when(fisher.getHomePort()).thenReturn(port); + when(fisher.isAtPort()).thenReturn(true); + when(fisher.isAllowedAtSea()).thenReturn(true); + when(fisher.getBoat()).thenReturn(boat); + + final FishState fishState = mock(FishState.class); + when(fishState.getRandom()).thenReturn(new MersenneTwisterFast()); + when(fishState.getMap()).thenReturn(map); + when(fisher.grabState()).thenReturn(fishState); + + final FadManager fadmanager = mock(FadManager.class); + when(fadmanager.numberOfPermissibleActions(eq(ActionClass.DPL), anyInt(), any())).thenReturn(99); + + final PurseSeineGear gear = mock(PurseSeineGear.class); + when(fisher.getGear()).thenReturn(gear); + when(gear.getFadManager()).thenReturn(fadmanager); + + final PlanningModule deploymentModule = + new DeploymentFromLocationValuePlanningModule( + new DeploymentLocationValues( + __ -> ImmutableMap.of(new Int2D(0, 1), 1.0), + 0.0 + ), + map, + new MersenneTwisterFast(0), + 1.0 + ); + + final PlanningModule fishingModule = mock(PlanningModule.class); + when(fishingModule.maximumActionsInAPlan(any(), any())).thenReturn(50); + when(fishingModule.chooseNextAction(any())).thenReturn( + new PlannedAction.Fishing(map.getSeaTile(0, 1), 1) + ); + + final DrawThenCheapestInsertionPlanner planner = + new DrawThenCheapestInsertionPlanner( + new FixedDoubleParameter(100), // 100hr + // 50% chance of planning for either fishing or not + ImmutableMap.of( + ActionType.FishingOnTile, 1.0, + ActionType.DeploymentAction, 1.0 + ), + ImmutableMap.of( + ActionType.FishingOnTile, fishingModule, + ActionType.DeploymentAction, deploymentModule + ), + false + ); + planner.start(fishState, fisher); + + final Map, Long> actionClassCountsBeforeOverride = + planner.planNewTrip() + .plannedActions() + .stream() + .collect(groupingBy(PlannedAction::getClass, counting())); + + planner.setActionPreferenceOverrides(ImmutableList.of(ActionType.DeploymentAction)); + final Map, Long> actionClassCountsAfterOverride = + planner.planNewTrip() + .plannedActions() + .stream() + .collect(groupingBy(PlannedAction::getClass, counting())); + + // before the override, we should have enough actions of both types + assertTrue(actionClassCountsBeforeOverride.get(PlannedAction.Fishing.class) > 10); + assertTrue(actionClassCountsBeforeOverride.get(PlannedAction.Deploy.class) > 10); + + // after the override, the plan should be filled with deployments + assertNull(actionClassCountsAfterOverride.get(PlannedAction.Fishing.class)); + assertEquals(99, actionClassCountsAfterOverride.get(PlannedAction.Deploy.class)); + } + }