Beispiel #1
0
        public void TestCECountermeasureSelectionFDS()
        {
            var input = File.ReadAllText("/Users/acailliau/Google Drive/PhD/Dissertation/running-example-fds/model2.kaos");

            ModelBuilder parser = new ModelBuilder();
            var          model  = parser.Parse(input);

            var optimizer  = new MOCECountermeasureSelectionOptimizer(model);
            var propagator = new BDDBasedPropagator(model);

            var root = model.Goal("locals_warned_when_risk_imminent");

            var sr = (DoubleSatisfactionRate)propagator.GetESR(root);

            Console.WriteLine("Satisfaction Rate without countermeasures: " + sr.SatisfactionRate);
            Console.WriteLine("Required Satisfaction Rate: " + root.RDS);

            var optimalSelections = optimizer.GetOptimalSelections(root, propagator);

            if (optimalSelections.Count() == 0)
            {
                Console.WriteLine("Optimal selections: No countermeasure to select.");
                Console.WriteLine();
            }
            else
            {
                Console.WriteLine($"Optimal selections ({optimalSelections.Count()}):");
                foreach (var o in optimalSelections.Distinct().OrderBy(x => x.Cost).ThenBy(x => x.SatisfactionRate))
                {
                    Console.WriteLine("* " + o);
                }
            }
        }
Beispiel #2
0
        public void TestMilestoneGoalRefinement()
        {
            var options = new RandomModelOptions {
                MinGoalBranchingFactor = 2,
                MaxGoalBranchingFactor = 4,
                NbGoals = 2,

                MinObstacleANDBranchingFactor = 2,
                MaxObstacleANDBranchingFactor = 4,
            };

            var generator = new RandomModelGenerator(options);
            var model     = generator.Generate();

            var p1 = new PatternBasedPropagator(model);
            var p2 = new BDDBasedPropagator(model);

            Console.WriteLine("Generated goals: " + model.Goals().Count());
            Console.WriteLine("Generated obstacles: " + model.Obstacles().Count());

            var root = model.RootGoals().Single();
            var sr1  = (DoubleSatisfactionRate)p1.GetESR(root);
            var sr2  = (DoubleSatisfactionRate)p2.GetESR(root);

            Assert.AreEqual(sr1.SatisfactionRate, sr2.SatisfactionRate, 0.0001);
        }
        public void TestRemoveObstructedGoal()
        {
            var input =
                @"declare goal [ anchor ] refinedby child1, child2 end
                  declare goal [ child1 ] obstructedby o1 end
                  declare goal [ child2 ] obstructedby o2 end
                  declare obstacle [ o1 ] probability .1 resolvedby [substitution:anchor] cm1 end
                  declare obstacle [ o2 ] refinedby so1 refinedby so2 end
                  declare obstacle [ so1 ] probability .2 resolvedby [substitution:anchor] cm2 end
                  declare obstacle [ so2 ] probability .3 end
                  declare goal [ cm1 ] end
                  declare goal [ cm2 ] obstructedby o_cm end
                  declare obstacle [ o_cm ] probability .4 end";

            var parser = new ModelBuilder();
            var model  = parser.Parse(input);

            var resolutions = model.Resolutions();

            foreach (var r in resolutions)
            {
                r.Name = "R_" + r.ResolvingGoalIdentifier;
            }
            var anchor = model.Goal("anchor");

            var p1 = new BDDBasedPropagator(model);

            System.Console.WriteLine(p1.GetESR(anchor));

            HashSet <Resolution> hashSet = new HashSet <Resolution> (model.Resolutions());
        }
Beispiel #4
0
        public SingleValueCriticalObstacles(KAOSModel model, Goal root) : base(model, root)
        {
            _propagator = new BDDBasedPropagator(model);
            _propagator.PreBuildObstructionSet(root);

            rsr = root.RDS;
        }
        private double GetScore(IEnumerable <Goal> goals, IPropagator propagator, HashSet <string> selection, out IEnumerable <string> rootsSatisfied)
        {
            var r = _model.Resolutions().Where(x => selection.Contains(x.ResolvingGoalIdentifier));
            var rootGoalsSatisfied = new HashSet <string> ();

            integrator = new SoftResolutionIntegrator(_model);
            Console.WriteLine("---- Computing score for " + string.Join(",", selection) + ".");
            // Integrate the selection
            foreach (var resolution in r)
            {
                Console.WriteLine("Integrate " + resolution.ResolvingGoalIdentifier);
                integrator.Integrate(resolution);
            }

            var p2 = new BDDBasedPropagator(_model);

            //var all_goals_satisfied = true;
            var avg_sat_rate = 0.0;

            foreach (var goal in goals)
            {
                var satRate = ((DoubleSatisfactionRate)p2.GetESR(goal));
                avg_sat_rate += satRate.SatisfactionRate;
                if (satRate.SatisfactionRate >= goal.RDS)
                {
                    rootGoalsSatisfied.Add(goal.Identifier);
                }

                Console.WriteLine("Cost " + selection.Count);
                Console.WriteLine("Selected cm: " + string.Join(",", selection));
                Console.WriteLine($"{goal.Identifier} : {satRate.SatisfactionRate} >= {goal.RDS}.");
            }

            //var all_goals_satisfied = (satRate.SatisfactionRate > goal.RDS);


            var cost = selection.Count();


            foreach (var resolution in r)
            {
                integrator.Remove(resolution);
            }

            //if (!all_goals_satisfied)
            //{
            //	Console.WriteLine("---- not all goal satisfied, returning score = 0");
            //	return 0;
            //}

            rootsSatisfied = rootGoalsSatisfied;

            //if (satRate > goal.RDS) {
            Console.WriteLine("---- returning score = " + (avg_sat_rate / goals.Count()));
            return(avg_sat_rate / goals.Count());
            //} else {
            //	return 0;
            //}
        }
Beispiel #6
0
        public void TestBestCountermeasureSelection()
        {
            var input = @"declare goal [ root ] rsr .75 refinedby child1, child2 end
                          declare goal [ child1 ] obstructedby o1 end
                          declare goal [ child2 ] obstructedby o2 end
                          declare obstacle [ o1 ] 
                            probability .2
                            resolvedby [substitution:root] cm1
                          end
                          declare obstacle [ o2 ] 
                            refinedby so1
                            refinedby so2
                          end
                          declare obstacle [ so1 ] 
                            probability .1
                            resolvedby [substitution:root] cm2
                          end
                          declare obstacle [ so2 ]
                            probability .3 
                            resolvedby [substitution:root] cm3
                          end";

            ModelBuilder parser = new ModelBuilder();
            var          model  = parser.Parse(input);

            var optimizer  = new NaiveCountermeasureSelectionOptimizer(model);
            var propagator = new BDDBasedPropagator(model);

            var root = model.Goal("root");

            var sr = (DoubleSatisfactionRate)propagator.GetESR(root);

            Console.WriteLine("Satisfaction Rate without countermeasures: " + sr.SatisfactionRate);
            Console.WriteLine("Required Satisfaction Rate: " + root.RDS);

            var minimalCost = optimizer.GetMinimalCost(root, propagator);

            Console.WriteLine("Minimal cost to guarantee RSR: " + minimalCost);

            if (minimalCost >= 0)
            {
                var optimalSelections = optimizer.GetOptimalSelections(minimalCost, root, propagator);

                if (optimalSelections.Count() == 0)
                {
                    Console.WriteLine("Optimal selections: No countermeasure to select.");
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine($"Optimal selections ({optimalSelections.Count()}):");
                    foreach (var o in optimalSelections.Distinct())
                    {
                        Console.WriteLine("* " + o);
                    }
                }
            }
        }
Beispiel #7
0
        public void TestCECountermeasureSelection2()
        {
            const string Path1 = "/Users/acailliau/Google Drive/PhD/Dissertation/case-studies/ambulance-dispatching-system/Models/runtime.kaos";
            var          input = File.ReadAllText(Path1);

            //input = @"declare goal [ root ] rsr .75 refinedby child1, child2 end
            //declare goal [ child1 ] obstructedby o1 end
            //declare goal [ child2 ] obstructedby o2 end
            //declare obstacle [ o1 ]
            //	probability .2
            //	resolvedby [substitution:root] cm1
            //end
            //declare obstacle [ o2 ]
            //	refinedby so1
            //	refinedby so2
            //end
            //declare obstacle [ so1 ]
            //	probability .1
            //	resolvedby [substitution:root] cm2
            //end
            //declare obstacle [ so2 ]
            //	probability .3
            //	resolvedby [substitution:root] cm3
            //end";

            ModelBuilder parser = new ModelBuilder();
            var          model  = parser.Parse(input, Path1);

            var optimizer  = new MOCECountermeasureSelectionOptimizer(model);
            var propagator = new BDDBasedPropagator(model);

            var root = model.Goal("achieve_incident_resolved");

            var sr = (DoubleSatisfactionRate)propagator.GetESR(root);

            Console.WriteLine("Satisfaction Rate without countermeasures: " + sr.SatisfactionRate);
            Console.WriteLine("Required Satisfaction Rate: " + root.RDS);

            //var minCost = optimizer.GetMinimalCost(root, propagator);
            //Console.WriteLine("Minimal cost: " + minCost);

            var optimalSelections = optimizer.GetOptimalSelections(root, propagator);

            if (optimalSelections.Count() == 0)
            {
                Console.WriteLine("Optimal selections: No countermeasure to select.");
                Console.WriteLine();
            }
            else
            {
                Console.WriteLine($"Optimal selections ({optimalSelections.Count()}):");
                foreach (var o in optimalSelections.Distinct().OrderBy(x => x.Cost).ThenBy(x => x.SatisfactionRate))
                {
                    Console.WriteLine("* " + o);
                }
            }
        }
Beispiel #8
0
        public static void Main(string [] args)
        {
            Console.WriteLine("*** This is Propagator from KAOSTools. ***");
            Console.WriteLine("*** For more information on KAOSTools see <https://github.com/ancailliau/KAOSTools> ***");
            Console.WriteLine("*** Please report bugs to <https://github.com/ancailliau/KAOSTools/issues> ***");
            Console.WriteLine();
            Console.WriteLine("*** Copyright (c) 2017, Université catholique de Louvain ***");
            Console.WriteLine("");

            string rootname = "root";

            options.Add("root=", "Specify the root goal for which to compute the satisfaction rate. (Default: root)", v => rootname = v);

            bool bdd = true;

            options.Add("bdd", "Uses the BDD-Based propagation (Default)", v => bdd = true);
            options.Add("pattern", "Uses the Pattern-Based propagation", v => bdd   = false);

            Init(args);

            var root = model.Goal(rootname);

            if (root == null)
            {
                PrintError("The goal '" + rootname + "' was not found");
            }

            try {
                IPropagator _propagator;
                if (bdd)
                {
                    _propagator = new BDDBasedPropagator(model);
                }
                else
                {
                    _propagator = new PatternBasedPropagator(model);
                }

                ISatisfactionRate      esr  = _propagator.GetESR(root);
                DoubleSatisfactionRate esrd = (DoubleSatisfactionRate)esr;

                Console.WriteLine(root.FriendlyName + ": {0:P}", esrd.SatisfactionRate);
            } catch (Exception e) {
                PrintError("An error occured during the computation. (" + e.Message + ").\n"
                           + "Please report this error to <https://github.com/ancailliau/KAOSTools/issues>.\n"
                           + "----------------------------\n"
                           + e.StackTrace
                           + "\n----------------------------\n");
            }
        }
Beispiel #9
0
        public void Setup()
        {
            var options = new RandomModelOptions {
                NbGoals        = NbGoals,
                NbObstructions = NbObstructions,
                NbObstacles    = NbObstacles
            };

            var generator = new RandomModelGenerator(options);

            model = generator.Generate();
            root  = model.RootGoals().Single();

            p3 = new BDDBasedPropagator(model);
            p3.PreBuildObstructionSet(root);
        }
        public void TestIntegrateSubstitutionProbabilityComputation()
        {
            var input = @"declare goal [ anchor ] refinedby child1, child2 end
                          declare goal [ child1 ] obstructedby o end
                          declare goal [ child2 ] end
                          declare obstacle [ o ] probability .4 resolvedby [substitution:anchor] cm end
                          declare goal [ cm ] obstructedby o2 end
                          declare obstacle [ o2 ] probability .1 end";

            ModelBuilder parser = new ModelBuilder();
            var          model  = parser.Parse(input);


            var integrator = new ResolutionIntegrator(model);
            var r          = model.Resolutions().Single();

            integrator.Integrate(r);

            var propagator = new BDDBasedPropagator(model);
            var expected   = ((DoubleSatisfactionRate)propagator.GetESR(model.Goal("anchor"))).SatisfactionRate;
        }
        public void TestIntegrateObstaclePreventionProbabilityComputation()
        {
            var input = @"declare goal [ root ] 
                            refinedby anchor
                          end
                          declare goal [ anchor ] 
                            formalspec when Current() then sooner-or-later Target()
                            refinedby child1, child2 
                          end
                          declare goal [ child1 ] 
                            formalspec when Current() then sooner-or-later Milestone()
                            obstructedby o
                          end
                          declare goal [ child2 ]
                            formalspec when Milestone() then sooner-or-later Target()
                          end
                          declare obstacle [ o ] 
                            probability .4
                            formalspec sooner-or-later (Current() and always not Milestone())
                            resolvedby [prevention:anchor] cm
                          end
                          declare goal [ cm ] obstructedby o2 end
                          declare obstacle [ o2 ] probability .1 end";

            ModelBuilder parser = new ModelBuilder();
            var          model  = parser.Parse(input);


            var integrator = new ResolutionIntegrator(model);
            var r          = model.Resolutions().Single();

            integrator.Integrate(r);

            var obstruction = model.Obstructions(x => x.ObstacleIdentifier == "o").Single();

            model.obstacleRepository.Remove(obstruction);

            var propagator = new BDDBasedPropagator(model);
            var expected   = ((DoubleSatisfactionRate)propagator.GetESR(model.Goal("root"))).SatisfactionRate;
        }
Beispiel #12
0
        void Initialize()
        {
            RootSatisfactionRates = new Dictionary <string, DoubleSatisfactionRate>();
            TimeSpan monitoringDelay = TimeSpan.FromMinutes(1);

            // Create the new obstacle monitors
            foreach (var obstacle in _model_running.LeafObstacles()
                     .Where(x => x.CustomData.ContainsKey("monitored") &&
                            x.CustomData["monitored"].Equals("true")))
            {
                IStateInformationStorage storage = new FiniteStateInformationStorage(100);
                var monitor = new ObstacleMonitor(obstacle, _model_running, storage, monitoringDelay);
                obstacleMonitors.Add(obstacle.Identifier, monitor);
            }

            // Initialize the propagator
            _propagator = new BDDBasedPropagator(_model_running);
            foreach (var root in _roots)
            {
                _propagator.PreBuildObstructionSet(root);
                RootSatisfactionRates.Add(root.Identifier, null);
            }
        }
        public static void Main(string [] args)
        {
            Console.WriteLine("*** This is CMSelector from KAOSTools. ***");
            Console.WriteLine("*** For more information on KAOSTools see <https://github.com/ancailliau/KAOSTools> ***");
            Console.WriteLine("*** Please report bugs to <https://github.com/ancailliau/KAOSTools/issues> ***");
            Console.WriteLine();
            Console.WriteLine("*** Copyright (c) 2017, Université catholique de Louvain ***");
            Console.WriteLine("");

            string rootname = "root";

            options.Add("root=", "Specify the root goal for which the selection shall be optimized. (Default: root)", v => rootname = v);

            Init(args);

            var root = model.Goal(rootname);

            if (root == null)
            {
                PrintError("The goal '" + rootname + "' was not found");
            }

            try {
                var optimizer  = new NaiveCountermeasureSelectionOptimizer(model);
                var propagator = new BDDBasedPropagator(model);

                var sr = (DoubleSatisfactionRate)propagator.GetESR(root);
                Console.WriteLine("Satisfaction Rate without countermeasures: " + sr.SatisfactionRate);
                Console.WriteLine("Required Satisfaction Rate: " + root.RDS);

                var minimalCost = optimizer.GetMinimalCost(root, propagator);
                Console.WriteLine("Minimal cost to guarantee RSR: " + minimalCost);

                if (minimalCost >= 0)
                {
                    var optimalSelections = optimizer.GetOptimalSelections(minimalCost, root, propagator);

                    if (optimalSelections.Count() == 0)
                    {
                        Console.WriteLine("Optimal selections: No countermeasure to select.");
                        Console.WriteLine();
                    }
                    else
                    {
                        Console.WriteLine($"Optimal selections ({optimalSelections.Count ()}):");
                        foreach (var o in optimalSelections.Distinct())
                        {
                            Console.WriteLine("* " + o);
                        }
                    }
                }
                else
                {
                    var optimalSelections = optimizer.GetOptimalSelections(minimalCost, root, propagator);
                    Console.WriteLine($"The best that can be achived ({optimalSelections.Count ()}):");
                    foreach (var o in optimalSelections.Distinct())
                    {
                        Console.WriteLine("* " + o);
                    }
                }

                var stat = optimizer.GetStatistics();
                Console.WriteLine();
                Console.WriteLine("--- Statistics ---");
                Console.WriteLine("Number of countermeasure goals: " + stat.NbResolvingGoals);
                Console.WriteLine("Number of possible selections: " + stat.NbSelections);
                Console.WriteLine("Number of safe selections: " + stat.NbSafeSelections);
                Console.WriteLine("Number of tested selections (for minimal cost): " + stat.NbTestedSelections);
                Console.WriteLine("Number of tested selections (for optimal selection): " + stat.NbTestedSelectionsForOptimality);
                Console.WriteLine("Maximal safe cost: " + stat.MaxSafeCost);
                Console.WriteLine("Time to compute minimal cost: " + stat.TimeToComputeMinimalCost);
                Console.WriteLine("Time to compute optimal selections: " + stat.TimeToComputeMinimalCost);
            } catch (Exception e) {
                PrintError("An error occured during the computation. (" + e.Message + ").\n"
                           + "Please report this error to <https://github.com/ancailliau/KAOSTools/issues>.\n"
                           + "----------------------------\n"
                           + e.StackTrace
                           + "\n----------------------------\n");
            }
        }
Beispiel #14
0
        static void OptimizeLoop()
        {
            var factory = new ConnectionFactory()
            {
                HostName = "localhost"
            };
            var currentSelection = new HashSet <string> ();

            using (var connection = factory.CreateConnection())
                using (var channel = connection.CreateModel())
                {
                    channel.QueueDeclare(queue: kaos_cm_selection_queue_name,
                                         durable: false,
                                         exclusive: false,
                                         autoDelete: false,
                                         arguments: null);

                    var _propagator_optimization = new BDDBasedPropagator(model);
                    while (!stop)
                    {
                        Thread.Sleep(TimeSpan.FromMinutes(1));

                        bool optimization_required = false;
                        foreach (var root in roots)
                        {
                            var doubleSatisfactionRate = modelMonitor.RootSatisfactionRates[root.Identifier];
                            if (doubleSatisfactionRate == null)
                            {
                                logger.Info($"Ignoring '{root.Identifier}', no satisfaction rate monitored.");
                                continue;
                            }
                            logger.Info($"RSR = " + root.RDS);
                            if (doubleSatisfactionRate.SatisfactionRate >= root.RDS)
                            {
                                logger.Info("Current configuration is above RSR for " + root.FriendlyName + ".");
                            }
                            else
                            {
                                logger.Info("Current configuration is below RSR for " + root.FriendlyName + ".");
                                optimization_required = true;
                            }
                        }

                        if (!optimization_required)
                        {
                            continue;
                        }

                        //var minimalcost = optimizer.GetMinimalCost(roots, _propagator_optimization);
                        //var optimalSelections = optimizer.GetOptimalSelections(minimalcost, roots, _propagator_optimization).FirstOrDefault();

                        var optimizer = new MOCECountermeasureSelectionOptimizer(optimization_model);
                        optimization_model.satisfactionRateRepository = modelMonitor._model_running.satisfactionRateRepository;

                        Console.WriteLine("Computing optimization");


                        var propagator        = new BDDBasedPropagator(optimization_model);
                        var enumerable        = new HashSet <Goal> (optimization_model.Goals(x => roots.Select(y => y.Identifier).Contains(x.Identifier)));
                        var optimalSelections = optimizer.GetOptimalSelections(enumerable, propagator);

                        if (optimalSelections.Count() == 0)
                        {
                            Console.WriteLine("Optimal selections: No countermeasure to select.");
                            Console.WriteLine();
                        }
                        else
                        {
                            Console.WriteLine($"Optimal selections ({optimalSelections.Count()}):");
                            foreach (var o in optimalSelections.Distinct().OrderBy(x => x.Cost).ThenBy(x => x.SatisfactionRate))
                            {
                                Console.WriteLine("* " + o);
                            }
                        }

                        if (optimalSelections.Count() > 0)
                        {
                            var optimalSelection = optimalSelections
                                                   .Where(x => x.SatRoots.SetEquals(roots.Select(y => y.Identifier)))
                                                   .OrderBy(x => x.Cost)
                                                   .ThenByDescending(x => x.SatisfactionRate)
                                                   .FirstOrDefault();

                            if (optimalSelection == null)
                            {
                                optimalSelection = optimalSelections
                                                   .OrderByDescending(x => x.SatRoots.Count)
                                                   .ThenBy(x => x.Cost)
                                                   .ThenByDescending(x => x.SatisfactionRate)
                                                   .FirstOrDefault();
                            }

                            if (optimalSelection == null)
                            {
                                logger.Info("No optimal selection found!");
                                return;
                            }

                            // Update the model
                            var deployment_methods = new List <string>();
                            foreach (var resolution in optimalSelection.Resolutions.Except(_active_resolutions))
                            {
                                _integrator_model.Integrate(resolution);
                                deployment_methods.Add(resolution.ResolvingGoal().CustomData["ondeploy"]);
                            }
                            foreach (var resolution in optimalSelection.Resolutions.Intersect(_active_resolutions))
                            {
                                _integrator_model.Remove(resolution);
                                deployment_methods.Add(resolution.ResolvingGoal().CustomData["onwithold"]);
                            }
                            modelMonitor.ModelChanged();

                            _active_resolutions = optimalSelection.Resolutions.ToHashSet();

                            // Deploy the countermeasures in the running system
                            var json = new JavaScriptSerializer().Serialize(deployment_methods);
                            logger.Info(json);

                            var body = Encoding.UTF8.GetBytes(json);

                            channel.BasicPublish(exchange: "",
                                                 routingKey: kaos_cm_selection_queue_name,
                                                 basicProperties: null,
                                                 body: body);
                        }
                        else
                        {
                            logger.Info("No selection found!");
                        }
                    }
                }
        }
Beispiel #15
0
        public DoubleSatisfactionRate BDDBasedComputation()
        {
            var p2 = new BDDBasedPropagator(model);

            return((DoubleSatisfactionRate)p2.GetESR(root));
        }
Beispiel #16
0
        public void TestCECountermeasureSelection()
        {
            var input = @"declare goal [ root ] rsr .75 refinedby child1, child2 end
                          declare goal [ child1 ] obstructedby o1 end
                          declare goal [ child2 ] obstructedby o2 end
                          declare obstacle [ o1 ] 
                            probability .2
                            refinedby so4
                            refinedby so5, so6
                          end
                          declare obstacle [ so4 ]
                            probability .1
                          end
                          declare obstacle [ so5 ]
                            probability .4
                            resolvedby [substitution:root] cm5
                          end
                          declare obstacle [ so6 ]
                            probability .4
                            resolvedby [substitution:root] cm4
                          end
                          declare obstacle [ o2 ] 
                            refinedby so1
                            refinedby so2
                          end
                          declare obstacle [ so1 ] 
                            probability .1
                            resolvedby [substitution:root] cm2
                          end
                          declare obstacle [ so2 ]
                            probability .3 
                            resolvedby [substitution:root] cm3
                          end
                          declare obstacle [ so3 ]
                            probability .4
                            resolvedby [substitution:root] cm4
                          end
                          ";

            //input = @"declare goal [ root ] rsr .75 refinedby child1, child2 end
            //declare goal [ child1 ] obstructedby o1 end
            //declare goal [ child2 ] obstructedby o2 end
            //declare obstacle [ o1 ]
            //	probability .2
            //	resolvedby [substitution:root] cm1
            //end
            //declare obstacle [ o2 ]
            //	refinedby so1
            //	refinedby so2
            //end
            //declare obstacle [ so1 ]
            //	probability .1
            //	resolvedby [substitution:root] cm2
            //end
            //declare obstacle [ so2 ]
            //	probability .3
            //	resolvedby [substitution:root] cm3
            //end";

            ModelBuilder parser = new ModelBuilder();
            var          model  = parser.Parse(input);

            var optimizer  = new MOCECountermeasureSelectionOptimizer(model);
            var propagator = new BDDBasedPropagator(model);

            var root = model.Goal("root");

            var sr = (DoubleSatisfactionRate)propagator.GetESR(root);

            Console.WriteLine("Satisfaction Rate without countermeasures: " + sr.SatisfactionRate);
            Console.WriteLine("Required Satisfaction Rate: " + root.RDS);

            //var minCost = optimizer.GetMinimalCost(root, propagator);
            //Console.WriteLine("Minimal cost: " + minCost);

            var optimalSelections = optimizer.GetOptimalSelections(root, propagator);

            if (optimalSelections.Count() == 0)
            {
                Console.WriteLine("Optimal selections: No countermeasure to select.");
                Console.WriteLine();
            }
            else
            {
                Console.WriteLine($"Optimal selections ({optimalSelections.Count()}):");
                foreach (var o in optimalSelections.Distinct().OrderBy(x => x.Cost).ThenBy(x => x.SatisfactionRate))
                {
                    Console.WriteLine("* " + o);
                }
            }
        }