diff --git a/matsim/src/main/java/org/matsim/core/population/routes/PopulationComparison.java b/matsim/src/main/java/org/matsim/core/population/routes/PopulationComparison.java index 30902a92e97..4ab30799adc 100644 --- a/matsim/src/main/java/org/matsim/core/population/routes/PopulationComparison.java +++ b/matsim/src/main/java/org/matsim/core/population/routes/PopulationComparison.java @@ -3,9 +3,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.population.*; +import org.matsim.utils.objectattributes.attributable.AttributesComparison; import java.util.Iterator; import java.util.List; +import java.util.Optional; public class PopulationComparison{ public enum Result { equal, notEqual } @@ -24,34 +26,70 @@ public static Result compare( Population population1, Population population2 ){ while( it1.hasNext() || it2.hasNext() ) { if ( ! it1.hasNext() ) { result = Result.notEqual ; + log.warn( "" ); + log.warn( " different length in populations. " ); return result ; } if ( ! it2.hasNext() ) { result = Result.notEqual ; + log.warn( "" ); + log.warn( " different length in populations. " ); return result ; } + Person person1 = it1.next(); Person person2 = it2.next(); + if ( !person1.getId().equals( person2.getId() ) ) { - log.warn( "persons out of sequence" ); + log.warn( "" ); + log.warn( "persons out of sequence p1: " + person1.getId() + " | p2: " + person2.getId()); result = Result.notEqual ; continue; } + + if(!AttributesComparison.equals(person1.getAttributes(), person2.getAttributes())) { + log.warn( "" ); + log.warn( "person attributes different p1: " + person1.getId() + " | p2: " + person2.getId()); + } + Plan plan1 = person1.getSelectedPlan(); Plan plan2 = person2.getSelectedPlan(); - if ( Math.abs( plan1.getScore() - plan2.getScore() ) > 100.*Double.MIN_VALUE || - !equals(plan1.getPlanElements(), plan2.getPlanElements())) { - double maxScore = Double.NEGATIVE_INFINITY; - for( Plan plan : person2.getPlans() ){ - if ( plan.getScore() > maxScore ) { - maxScore = plan.getScore() ; + if(!AttributesComparison.equals(plan1.getAttributes(), plan2.getAttributes())) { + log.warn( "" ); + log.warn( "selected plan attributes different p1: " + person1.getId() + " | p2: " + person2.getId()); + } + + Optional score1 = Optional.ofNullable(plan1.getScore()); + Optional score2 = Optional.ofNullable(plan2.getScore()); + + if(score1.isPresent() && score2.isPresent()) { + if ( Math.abs( plan1.getScore() - plan2.getScore() ) > 100.*Double.MIN_VALUE) { + + double maxScore = Double.NEGATIVE_INFINITY; + for( Plan plan : person2.getPlans() ){ + if ( plan.getScore() > maxScore ) { + maxScore = plan.getScore() ; + } } - } + log.warn( "" ); + log.warn("personId=" + person1.getId() + "; score1=" + plan1.getScore() + "; score2=" + plan2.getScore() + "; maxScore2=" + maxScore ) ; + log.warn( "" ); + + result = Result.notEqual; + + } + } else if(score1.isEmpty() && score2.isEmpty()) {} else { log.warn( "" ); - log.warn("personId=" + person1.getId() + "; score1=" + plan1.getScore() + "; score2=" + plan2.getScore() + "; maxScore2=" + maxScore ) ; + log.warn( " selected plan scores not consistently present: p1: " + person1.getId() + " | p2: " + person2.getId()); + result = Result.notEqual; + } + + if(!equals(plan1.getPlanElements(), plan2.getPlanElements())) { log.warn( "" ); + log.warn( " selected plan elements not equal: p1: " + person1.getId() + " | p2: " + person2.getId() ); + for( PlanElement planElement : plan1.getPlanElements() ){ log.warn( planElement ); } @@ -60,7 +98,7 @@ public static Result compare( Population population1, Population population2 ){ log.warn( planElement ); } log.warn( "" ); - + result = Result.notEqual; } } return result ; @@ -86,6 +124,9 @@ public static boolean equals(List planElements, * */ private static boolean equals(PlanElement o1, PlanElement o2) { + if(!AttributesComparison.equals(o1.getAttributes(), o2.getAttributes())) { + return false; + } if (o1 instanceof Leg) { if (o2 instanceof Leg) { Leg leg1 = (Leg) o1; diff --git a/matsim/src/main/java/org/matsim/utils/objectattributes/attributable/AttributesComparison.java b/matsim/src/main/java/org/matsim/utils/objectattributes/attributable/AttributesComparison.java new file mode 100644 index 00000000000..12047efa57d --- /dev/null +++ b/matsim/src/main/java/org/matsim/utils/objectattributes/attributable/AttributesComparison.java @@ -0,0 +1,41 @@ +package org.matsim.utils.objectattributes.attributable; + +import com.google.common.base.Equivalence; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.matsim.vehicles.PersonVehicles; + +import java.util.Map; + +/** + * @author nkuehnel / MOIA + */ +public final class AttributesComparison { + + private AttributesComparison(){} + + public static boolean equals(Attributes a1, Attributes a2) { + if(a1.size() != a2.size()) { + return false; + } + + return Maps.difference(a1.getAsMap(), a2.getAsMap(), new CustomEquivalence()).areEqual(); + } + + private static class CustomEquivalence extends Equivalence { + @Override + protected boolean doEquivalent(Object a, Object b) { + if (a instanceof Map mapA && b instanceof Map mapB) { + return Maps.difference(mapA, mapB, new CustomEquivalence()).areEqual(); + } else if (a instanceof PersonVehicles vehiclesA && b instanceof PersonVehicles vehiclesB) { + return Maps.difference(vehiclesA.getModeVehicles(), vehiclesB.getModeVehicles(), new CustomEquivalence()).areEqual(); + } + return a.equals(b); + } + + @Override + protected int doHash(Object o) { + return o.hashCode(); + } + } +} diff --git a/matsim/src/test/java/org/matsim/utils/objectattributes/attributable/AttributesTest.java b/matsim/src/test/java/org/matsim/utils/objectattributes/attributable/AttributesTest.java index 353c7b5476b..dd5043974e7 100644 --- a/matsim/src/test/java/org/matsim/utils/objectattributes/attributable/AttributesTest.java +++ b/matsim/src/test/java/org/matsim/utils/objectattributes/attributable/AttributesTest.java @@ -148,4 +148,22 @@ void testGetAsMap() { Assertions.fail("Expected NoSuchElementException, but caught a different one."); } } + + @Test + void testComparison() { + + AttributesImpl a1 = new AttributesImpl(); + AttributesImpl a2 = new AttributesImpl(); + Assertions.assertTrue(AttributesComparison.equals(a1, a2)); + + a1.putAttribute("att1", "1"); + Assertions.assertFalse(AttributesComparison.equals(a1, a2)); + + a2.putAttribute("att1", "1"); + Assertions.assertTrue(AttributesComparison.equals(a1, a2)); + + a2.putAttribute("att1", "one"); + Assertions.assertFalse(AttributesComparison.equals(a1, a2)); + + } }