use of org.kie.kogito.explainability.model.Feature in project kogito-apps by kiegroup.
the class CounterfactualExplainerTest method testFinalUniqueIds.
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2 })
void testFinalUniqueIds(int seed) throws ExecutionException, InterruptedException, TimeoutException {
Random random = new Random();
random.setSeed(seed);
final List<Output> goal = new ArrayList<>();
List<Feature> features = List.of(FeatureFactory.newNumericalFeature("f-num1", 10.0, NumericalFeatureDomain.create(0, 20)));
PredictionProvider model = TestUtils.getFeaturePassModel(0);
final TerminationConfig terminationConfig = new TerminationConfig().withScoreCalculationCountLimit(100_000L);
final SolverConfig solverConfig = SolverConfigBuilder.builder().withTerminationConfig(terminationConfig).build();
solverConfig.setRandomSeed((long) seed);
solverConfig.setEnvironmentMode(EnvironmentMode.REPRODUCIBLE);
final List<UUID> intermediateIds = new ArrayList<>();
final List<UUID> executionIds = new ArrayList<>();
final Consumer<CounterfactualResult> captureIntermediateIds = counterfactual -> {
intermediateIds.add(counterfactual.getSolutionId());
};
final Consumer<CounterfactualResult> captureExecutionIds = counterfactual -> {
executionIds.add(counterfactual.getExecutionId());
};
final CounterfactualConfig counterfactualConfig = new CounterfactualConfig().withSolverConfig(solverConfig);
solverConfig.withEasyScoreCalculatorClass(MockCounterFactualScoreCalculator.class);
final CounterfactualExplainer counterfactualExplainer = new CounterfactualExplainer(counterfactualConfig);
PredictionInput input = new PredictionInput(features);
PredictionOutput output = new PredictionOutput(goal);
final UUID executionId = UUID.randomUUID();
Prediction prediction = new CounterfactualPrediction(input, output, null, executionId, null);
final CounterfactualResult counterfactualResult = counterfactualExplainer.explainAsync(prediction, model, captureIntermediateIds.andThen(captureExecutionIds)).get(Config.INSTANCE.getAsyncTimeout(), Config.INSTANCE.getAsyncTimeUnit());
for (CounterfactualEntity entity : counterfactualResult.getEntities()) {
logger.debug("Entity: {}", entity);
}
// All intermediate ids should be unique
assertEquals((int) intermediateIds.stream().distinct().count(), intermediateIds.size());
// There should be at least one intermediate id
assertTrue(intermediateIds.size() > 0);
// There should be at least one execution id
assertTrue(executionIds.size() > 0);
// We should have the same number of execution ids as intermediate ids (captured from intermediate results)
assertEquals(executionIds.size(), intermediateIds.size());
// All execution ids should be the same
assertEquals(1, (int) executionIds.stream().distinct().count());
// The last intermediate id must be different from the final result id
assertNotEquals(intermediateIds.get(intermediateIds.size() - 1), counterfactualResult.getSolutionId());
// Captured execution ids should be the same as the one provided
assertEquals(executionIds.get(0), executionId);
}
use of org.kie.kogito.explainability.model.Feature in project kogito-apps by kiegroup.
the class CounterfactualExplainerTest method testCounterfactualConstrainedMatchUnscaled.
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2 })
void testCounterfactualConstrainedMatchUnscaled(int seed) throws ExecutionException, InterruptedException, TimeoutException {
Random random = new Random();
random.setSeed(seed);
final List<Output> goal = List.of(new Output("inside", Type.BOOLEAN, new Value(true), 0.0));
List<Feature> features = new LinkedList<>();
features.add(FeatureFactory.newNumericalFeature("f-num1", 100.0));
features.add(FeatureFactory.newNumericalFeature("f-num2", 100.0, NumericalFeatureDomain.create(0.0, 1000.0)));
features.add(FeatureFactory.newNumericalFeature("f-num3", 100.0, NumericalFeatureDomain.create(0.0, 1000.0)));
features.add(FeatureFactory.newNumericalFeature("f-num4", 100.0));
final double center = 500.0;
final double epsilon = 10.0;
final CounterfactualResult result = runCounterfactualSearch((long) seed, goal, features, TestUtils.getSumThresholdModel(center, epsilon), DEFAULT_GOAL_THRESHOLD);
final List<CounterfactualEntity> counterfactualEntities = result.getEntities();
double totalSum = 0;
for (CounterfactualEntity entity : counterfactualEntities) {
totalSum += entity.asFeature().getValue().asNumber();
logger.debug("Entity: {}", entity);
}
assertFalse(counterfactualEntities.get(0).isChanged());
assertFalse(counterfactualEntities.get(3).isChanged());
assertTrue(totalSum <= center + epsilon);
assertTrue(totalSum >= center - epsilon);
assertTrue(result.isValid());
}
use of org.kie.kogito.explainability.model.Feature in project kogito-apps by kiegroup.
the class CounterfactualExplainerTest method testCounterfactualConstrainedMatchScaled.
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2 })
void testCounterfactualConstrainedMatchScaled(int seed) throws ExecutionException, InterruptedException, TimeoutException {
Random random = new Random();
random.setSeed(seed);
final List<Output> goal = List.of(new Output("inside", Type.BOOLEAN, new Value(true), 0.0d));
List<Feature> features = new LinkedList<>();
List<FeatureDistribution> featureDistributions = new LinkedList<>();
final Feature fnum1 = FeatureFactory.newNumericalFeature("f-num1", 100.0);
features.add(fnum1);
featureDistributions.add(new NumericFeatureDistribution(fnum1, (new NormalDistribution(500, 1.1)).sample(1000)));
final Feature fnum2 = FeatureFactory.newNumericalFeature("f-num2", 100.0, NumericalFeatureDomain.create(0.0, 1000.0));
features.add(fnum2);
featureDistributions.add(new NumericFeatureDistribution(fnum2, (new NormalDistribution(430.0, 1.7)).sample(1000)));
final Feature fnum3 = FeatureFactory.newNumericalFeature("f-num3", 100.0, NumericalFeatureDomain.create(0.0, 1000.0));
features.add(fnum3);
featureDistributions.add(new NumericFeatureDistribution(fnum3, (new NormalDistribution(470.0, 2.9)).sample(1000)));
final Feature fnum4 = FeatureFactory.newNumericalFeature("f-num4", 100.0);
features.add(fnum4);
featureDistributions.add(new NumericFeatureDistribution(fnum4, (new NormalDistribution(2390.0, 0.3)).sample(1000)));
final double center = 500.0;
final double epsilon = 10.0;
final CounterfactualResult result = runCounterfactualSearch((long) seed, goal, features, TestUtils.getSumThresholdModel(center, epsilon), DEFAULT_GOAL_THRESHOLD);
final List<CounterfactualEntity> counterfactualEntities = result.getEntities();
double totalSum = 0;
for (CounterfactualEntity entity : counterfactualEntities) {
totalSum += entity.asFeature().getValue().asNumber();
logger.debug("Entity: {}", entity);
}
assertFalse(counterfactualEntities.get(0).isChanged());
assertFalse(counterfactualEntities.get(3).isChanged());
assertTrue(totalSum <= center + epsilon);
assertTrue(totalSum >= center - epsilon);
assertTrue(result.isValid());
}
use of org.kie.kogito.explainability.model.Feature in project kogito-apps by kiegroup.
the class CounterfactualExplainerTest method testCounterfactualBoolean.
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2 })
void testCounterfactualBoolean(int seed) throws ExecutionException, InterruptedException, TimeoutException {
Random random = new Random();
random.setSeed(seed);
final List<Output> goal = List.of(new Output("inside", Type.BOOLEAN, new Value(true), 0.0d));
List<Feature> features = new LinkedList<>();
for (int i = 0; i < 4; i++) {
if (i == 2) {
features.add(FeatureFactory.newNumericalFeature("f-" + i, random.nextDouble()));
} else {
features.add(FeatureFactory.newNumericalFeature("f-" + i, random.nextDouble(), NumericalFeatureDomain.create(0.0, 1000.0)));
}
}
features.add(FeatureFactory.newBooleanFeature("f-bool", true, EmptyFeatureDomain.create()));
final double center = 500.0;
final double epsilon = 10.0;
final CounterfactualResult result = runCounterfactualSearch((long) seed, goal, features, TestUtils.getSumThresholdModel(center, epsilon), DEFAULT_GOAL_THRESHOLD);
final List<CounterfactualEntity> counterfactualEntities = result.getEntities();
double totalSum = 0;
for (CounterfactualEntity entity : counterfactualEntities) {
totalSum += entity.asFeature().getValue().asNumber();
logger.debug("Entity: {}", entity);
}
assertFalse(counterfactualEntities.get(2).isChanged());
assertTrue(totalSum <= center + epsilon);
assertTrue(totalSum >= center - epsilon);
assertTrue(result.isValid());
}
use of org.kie.kogito.explainability.model.Feature in project kogito-apps by kiegroup.
the class CounterfactualExplainerTest method testIntermediateUniqueIds.
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2 })
void testIntermediateUniqueIds(int seed) throws ExecutionException, InterruptedException, TimeoutException {
Random random = new Random();
random.setSeed(seed);
final List<Output> goal = new ArrayList<>();
List<Feature> features = List.of(FeatureFactory.newNumericalFeature("f-num1", 10.0, NumericalFeatureDomain.create(0, 20)));
PredictionProvider model = TestUtils.getFeaturePassModel(0);
final TerminationConfig terminationConfig = new TerminationConfig().withScoreCalculationCountLimit(100_000L);
final SolverConfig solverConfig = SolverConfigBuilder.builder().withTerminationConfig(terminationConfig).build();
solverConfig.setRandomSeed((long) seed);
solverConfig.setEnvironmentMode(EnvironmentMode.REPRODUCIBLE);
final List<UUID> intermediateIds = new ArrayList<>();
final List<UUID> executionIds = new ArrayList<>();
final Consumer<CounterfactualResult> captureIntermediateIds = counterfactual -> {
intermediateIds.add(counterfactual.getSolutionId());
};
final Consumer<CounterfactualResult> captureExecutionIds = counterfactual -> {
executionIds.add(counterfactual.getExecutionId());
};
final CounterfactualConfig counterfactualConfig = new CounterfactualConfig().withSolverConfig(solverConfig);
solverConfig.withEasyScoreCalculatorClass(MockCounterFactualScoreCalculator.class);
final CounterfactualExplainer counterfactualExplainer = new CounterfactualExplainer(counterfactualConfig);
PredictionInput input = new PredictionInput(features);
PredictionOutput output = new PredictionOutput(goal);
final UUID executionId = UUID.randomUUID();
Prediction prediction = new CounterfactualPrediction(input, output, null, executionId, null);
final CounterfactualResult counterfactualResult = counterfactualExplainer.explainAsync(prediction, model, captureIntermediateIds.andThen(captureExecutionIds)).get(Config.INSTANCE.getAsyncTimeout(), Config.INSTANCE.getAsyncTimeUnit());
for (CounterfactualEntity entity : counterfactualResult.getEntities()) {
logger.debug("Entity: {}", entity);
}
// all intermediate Ids must be distinct
assertEquals((int) intermediateIds.stream().distinct().count(), intermediateIds.size());
assertEquals(1, (int) executionIds.stream().distinct().count());
assertEquals(executionIds.get(0), executionId);
}
Aggregations