Browse Source
			
			
			more work on jit-based builder
			
				
		more work on jit-based builder
	
		
	
			
				Former-commit-id:main579adb85eb[formerly574a25aa3d] Former-commit-id:2a1d2ca2c2
				 17 changed files with 378 additions and 887 deletions
			
			
		- 
					778src/builder/ExplicitJitJaniModelBuilder.cpp
 - 
					83src/builder/ExplicitJitJaniModelBuilder.h
 - 
					23src/builder/JitModelBuilderInterface.h
 - 
					19src/builder/jit/Choice.cpp
 - 
					22src/builder/jit/Choice.h
 - 
					43src/builder/jit/Distribution.cpp
 - 
					44src/builder/jit/Distribution.h
 - 
					24src/builder/jit/DistributionEntry.cpp
 - 
					22src/builder/jit/DistributionEntry.h
 - 
					24src/builder/jit/JitModelBuilderInterface.cpp
 - 
					64src/builder/jit/ModelComponentBuilder.cpp
 - 
					46src/builder/jit/ModelComponentBuilder.h
 - 
					25src/builder/jit/StateBehaviour.cpp
 - 
					25src/builder/jit/StateBehaviour.h
 - 
					14src/storage/jani/ModelType.cpp
 - 
					3src/storage/jani/ModelType.h
 - 
					4src/utility/storm.h
 
@ -1,778 +0,0 @@ | 
				
			|||
#include "src/builder/ExplicitJitJaniModelBuilder.h"
 | 
				
			|||
 | 
				
			|||
#include <iostream>
 | 
				
			|||
#include <cstdio>
 | 
				
			|||
#include <chrono>
 | 
				
			|||
 | 
				
			|||
#include "src/adapters/CarlAdapter.h"
 | 
				
			|||
 | 
				
			|||
#include "src/solver/SmtSolver.h"
 | 
				
			|||
 | 
				
			|||
#include "src/utility/macros.h"
 | 
				
			|||
#include "src/utility/solver.h"
 | 
				
			|||
#include "src/exceptions/InvalidStateException.h"
 | 
				
			|||
#include "src/exceptions/NotSupportedException.h"
 | 
				
			|||
#include "src/exceptions/UnexpectedException.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
         | 
				
			|||
        static const std::string CXX_COMPILER = "clang++"; | 
				
			|||
        static const std::string DYLIB_EXTENSION = ".dylib"; | 
				
			|||
        static const std::string COMPILER_FLAGS = "-std=c++11 -stdlib=libc++ -fPIC -O3 -shared -funroll-loops -undefined dynamic_lookup"; | 
				
			|||
        static const std::string STORM_ROOT = "/Users/chris/work/storm"; | 
				
			|||
        static const std::string L3PP_ROOT = "/Users/chris/work/storm/resources/3rdparty/l3pp"; | 
				
			|||
        static const std::string BOOST_ROOT = "/usr/local/Cellar/boost/1.62.0/include"; | 
				
			|||
        static const std::string GMP_ROOT = "/usr/local/Cellar/gmp/6.1.1"; | 
				
			|||
        static const std::string CARL_ROOT = "/Users/chris/work/carl"; | 
				
			|||
        static const std::string CLN_ROOT = "/usr/local/Cellar/cln/1.3.4"; | 
				
			|||
        static const std::string GINAC_ROOT = "/usr/local/Cellar/ginac/1.6.7_1"; | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::ExplicitJitJaniModelBuilder(storm::jani::Model const& model) : model(model) { | 
				
			|||
            // Intentionally left empty.
 | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        std::string ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::createSourceCode() { | 
				
			|||
            std::string sourceTemplate = R"( | 
				
			|||
             | 
				
			|||
#define NDEBUG
 | 
				
			|||
             | 
				
			|||
#include <cstdint>
 | 
				
			|||
#include <iostream>
 | 
				
			|||
#include <vector>
 | 
				
			|||
#include <cmath>
 | 
				
			|||
#include <unordered_map>
 | 
				
			|||
#include <boost/dll/alias.hpp>
 | 
				
			|||
 | 
				
			|||
#include "resources/3rdparty/sparsepp/sparsepp.h"
 | 
				
			|||
 | 
				
			|||
#include "src/builder/JitModelBuilderInterface.h"
 | 
				
			|||
#include "src/storage/SparseMatrix.h"
 | 
				
			|||
#include "src/models/sparse/Dtmc.h"
 | 
				
			|||
#include "src/models/sparse/StandardRewardModel.h"
 | 
				
			|||
             | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
         | 
				
			|||
        typedef uint32_t IndexType; | 
				
			|||
 | 
				
			|||
        struct StateType { | 
				
			|||
            // Boolean variables.
 | 
				
			|||
            {% for variable in stateVariables.boolean %}bool {$variable.name} : 1; | 
				
			|||
            {% endfor %} | 
				
			|||
            // Bounded integer variables.
 | 
				
			|||
            {% for variable in stateVariables.boundedInteger %}uint64_t {$variable.name} : {$variable.numberOfBits}; | 
				
			|||
            {% endfor %} | 
				
			|||
            // Location variables.
 | 
				
			|||
            {% for variable in stateVariables.locations %}uint64_t {$variable.name} : {$variable.numberOfBits}; | 
				
			|||
            {% endfor %} | 
				
			|||
        }; | 
				
			|||
         | 
				
			|||
        bool operator==(StateType const& first, StateType const& second) { | 
				
			|||
            bool result = true; | 
				
			|||
            {% for variable in stateVariables.boolean %}result &= !(first.{$variable.name} ^ second.{$variable.name}); | 
				
			|||
            {% endfor %} | 
				
			|||
            {% for variable in stateVariables.boundedInteger %}result &= first.{$variable.name} == second.{$variable.name}; | 
				
			|||
            {% endfor %} | 
				
			|||
            {% for variable in stateVariables.locations %}result &= first.{$variable.name} == second.{$variable.name}; | 
				
			|||
            {% endfor %} | 
				
			|||
            return result; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        std::ostream& operator<<(std::ostream& out, StateType const& state) { | 
				
			|||
            out << "<"; | 
				
			|||
            {% for variable in stateVariables.boolean %}out << "{$variable.name}=" << state.{$variable.name} << ", "; | 
				
			|||
            {% endfor %} | 
				
			|||
            {% for variable in stateVariables.boundedInteger %}out << "{$variable.name}=" << state.{$variable.name} << ", "; | 
				
			|||
            {% endfor %} | 
				
			|||
            {% for variable in stateVariables.locations %}out << "{$variable.name}=" << state.{$variable.name} << ", "; | 
				
			|||
            {% endfor %} | 
				
			|||
            out << ">"; | 
				
			|||
            return out; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
namespace std { | 
				
			|||
    template <> | 
				
			|||
    struct hash<storm::builder::StateType> { | 
				
			|||
        std::size_t operator()(storm::builder::StateType const& state) const { | 
				
			|||
            // Note: this is faster than viewing the struct as a bit field and taking hash_combine of the bytes.
 | 
				
			|||
            std::size_t seed = 0; | 
				
			|||
            {% for variable in stateVariables.boolean %}spp::hash_combine(seed, state.{$variable.name}); | 
				
			|||
            {% endfor %} | 
				
			|||
            {% for variable in stateVariables.boundedInteger %}spp::hash_combine(seed, state.{$variable.name}); | 
				
			|||
            {% endfor %} | 
				
			|||
            {% for variable in stateVariables.locations %}spp::hash_combine(seed, state.{$variable.name}); | 
				
			|||
            {% endfor %} | 
				
			|||
            return seed; | 
				
			|||
        } | 
				
			|||
    }; | 
				
			|||
} | 
				
			|||
             | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
     | 
				
			|||
        typedef double ValueType; | 
				
			|||
         | 
				
			|||
        static bool model_is_deterministic() { | 
				
			|||
            return {$deterministic_model}; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        static bool model_is_discrete_time() { | 
				
			|||
            return {$discrete_time_model}; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        class Entry { | 
				
			|||
        public: | 
				
			|||
            Entry() : column(0), value(0) { | 
				
			|||
                // Intentionally left empty.
 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            Entry(IndexType const& column, ValueType const& value) : column(column), value(value) { | 
				
			|||
                // Intentionally left empty.
 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            IndexType const& getColumn() const { | 
				
			|||
                return column; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            ValueType const& getValue() const { | 
				
			|||
                return value; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            void addToValue(ValueType const& value) { | 
				
			|||
                this->value += value; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            void scaleValue(ValueType const& divisor) { | 
				
			|||
                this->value /= divisor; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        private: | 
				
			|||
            IndexType column; | 
				
			|||
            ValueType value; | 
				
			|||
        }; | 
				
			|||
         | 
				
			|||
        class Choice { | 
				
			|||
        public: | 
				
			|||
            typedef std::vector<Entry> ContainerType; | 
				
			|||
             | 
				
			|||
            void add(IndexType const& stateIndex, ValueType const& value) { | 
				
			|||
                distribution.push_back(Entry(stateIndex, value)); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            void add(Choice&& choice) { | 
				
			|||
                distribution.insert(distribution.end(), std::make_move_iterator(choice.getDistribution().begin()), std::make_move_iterator(choice.getDistribution().end())); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            void makeUniqueAndShrink() { | 
				
			|||
                std::sort(distribution.begin(), distribution.end(), | 
				
			|||
                          [] (Entry const& a, Entry const& b) { | 
				
			|||
                              return a.getColumn() < b.getColumn(); | 
				
			|||
                          } | 
				
			|||
                          ); | 
				
			|||
                 | 
				
			|||
                // Code taken from std::unique and modified to fit needs.
 | 
				
			|||
                auto first = distribution.begin(); | 
				
			|||
                auto last = distribution.end(); | 
				
			|||
                 | 
				
			|||
                if (first != last) { | 
				
			|||
                    auto result = first; | 
				
			|||
                    while (++first != last) { | 
				
			|||
                        if (!(result->getColumn() == first->getColumn())) { | 
				
			|||
                            if (++result != first) { | 
				
			|||
                                *result = std::move(*first); | 
				
			|||
                            } | 
				
			|||
                        } else { | 
				
			|||
                            result->addToValue(first->getValue()); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    ++result; | 
				
			|||
                     | 
				
			|||
                    distribution.resize(std::distance(distribution.begin(), result)); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            ContainerType const& getDistribution() const { | 
				
			|||
                return distribution; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            ContainerType& getDistribution() { | 
				
			|||
                return distribution; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        private: | 
				
			|||
            ContainerType distribution; | 
				
			|||
        }; | 
				
			|||
         | 
				
			|||
        class StateSet { | 
				
			|||
        public: | 
				
			|||
            StateType const& peek() const { | 
				
			|||
                return storage.back(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            StateType get() { | 
				
			|||
                StateType result = std::move(storage.back()); | 
				
			|||
                storage.pop_back(); | 
				
			|||
                return result; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            void add(StateType const& state) { | 
				
			|||
                storage.push_back(state); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            bool empty() const { | 
				
			|||
                return storage.empty(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        private: | 
				
			|||
            std::vector<StateType> storage; | 
				
			|||
        }; | 
				
			|||
         | 
				
			|||
        struct ModelComponents { | 
				
			|||
            ModelComponents() : transitionMatrixBuilder(0, 0, 0, true, !model_is_deterministic()), stateLabeling(), rewardModels(), choiceLabeling() { | 
				
			|||
                // Intentionally left empty.
 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder; | 
				
			|||
            storm::models::sparse::StateLabeling stateLabeling; | 
				
			|||
            std::unordered_map<std::string, storm::models::sparse::StandardRewardModel<ValueType>> rewardModels; | 
				
			|||
            boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabeling; | 
				
			|||
             | 
				
			|||
            storm::models::sparse::Model<ValueType>* createModel() { | 
				
			|||
                if (model_is_discrete_time()) { | 
				
			|||
                    if (model_is_deterministic()) { | 
				
			|||
                        return new storm::models::sparse::Dtmc<ValueType>(std::move(this->transitionMatrixBuilder.build()), std::move(this->stateLabeling), std::move(this->rewardModels), std::move(this->choiceLabeling)); | 
				
			|||
                    } else { | 
				
			|||
                        return nullptr; | 
				
			|||
                    } | 
				
			|||
                } else { | 
				
			|||
                    return nullptr; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        }; | 
				
			|||
                     | 
				
			|||
        class JitBuilder : public JitModelBuilderInterface<ValueType> { | 
				
			|||
        public: | 
				
			|||
            JitBuilder() : currentRow(0), modelComponents() { | 
				
			|||
                {% for state in initialStates %}{ | 
				
			|||
                    StateType state; | 
				
			|||
                    {% for assignment in state %}state.{$assignment.variable} = {$assignment.value}; | 
				
			|||
                    {% endfor %}initialStates.push_back(state); | 
				
			|||
                } | 
				
			|||
                {% endfor %} | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            virtual storm::models::sparse::Model<ValueType>* build() override { | 
				
			|||
                std::cout << "starting building process" << std::endl; | 
				
			|||
                explore(initialStates); | 
				
			|||
                std::cout << "finished building process with " << stateIds.size() << " states" << std::endl; | 
				
			|||
                return modelComponents.createModel(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            void explore(std::vector<StateType> const& initialStates) { | 
				
			|||
                for (auto const& state : initialStates) { | 
				
			|||
                    explore(state); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            void explore(StateType const& initialState) { | 
				
			|||
                StateSet statesToExplore; | 
				
			|||
                getOrAddIndex(initialState, statesToExplore); | 
				
			|||
 | 
				
			|||
                std::vector<Choice> choices; | 
				
			|||
                while (!statesToExplore.empty()) { | 
				
			|||
                    StateType currentState = statesToExplore.get(); | 
				
			|||
                    IndexType currentIndex = getIndex(currentState); | 
				
			|||
#ifndef NDEBUG
 | 
				
			|||
                    std::cout << "Exploring state " << currentState << ", id " << currentIndex << std::endl; | 
				
			|||
#endif
 | 
				
			|||
                     | 
				
			|||
                    exploreNonSynchronizingEdges(currentState, currentIndex, choices, statesToExplore); | 
				
			|||
                     | 
				
			|||
                    addChoicesForState(currentIndex, choices); | 
				
			|||
                    choices.clear(); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            void exploreNonSynchronizingEdges(StateType const& sourceState, IndexType const& currentIndex, std::vector<Choice>& choices, StateSet& statesToExplore) { | 
				
			|||
                {% for edge in nonSynchronizingEdges %}if ({$edge.guard}) { | 
				
			|||
                    choices.emplace_back(); | 
				
			|||
                    {% for destination in edge.destinations %}{ | 
				
			|||
                        StateType targetState(sourceState); | 
				
			|||
                        {% for assignment in destination.nonTransientAssignments %}targetState.{$assignment.variable} = {$assignment.value}; | 
				
			|||
                        {% endfor %} | 
				
			|||
                        IndexType targetStateIndex = getOrAddIndex(targetState, statesToExplore); | 
				
			|||
                        choices.back().add(targetStateIndex, {$destination.value}); | 
				
			|||
                    } | 
				
			|||
                    {% endfor %} | 
				
			|||
                } | 
				
			|||
                {% endfor %} | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            void addChoicesForState(IndexType const& stateId, std::vector<Choice>& choices) { | 
				
			|||
                // If there is more than one choice in a deterministic model, we need to combine the choices into one
 | 
				
			|||
                // global choice.
 | 
				
			|||
                bool choiceIsGuaranteedDistribution = false; | 
				
			|||
                if (model_is_deterministic() && choices.size() > 1) { | 
				
			|||
                    uint64_t choiceCount = choices.size(); | 
				
			|||
                     | 
				
			|||
                    // We do this by adding the entries of choices after the first one to the first one and then making
 | 
				
			|||
                    // the distribution unique again.
 | 
				
			|||
                    for (auto it = ++choices.begin(), ite = choices.end(); it != ite; ++it) { | 
				
			|||
                        choices.front().add(std::move(*it)); | 
				
			|||
                    } | 
				
			|||
                    choices.resize(1); | 
				
			|||
                    choices.front().makeUniqueAndShrink(); | 
				
			|||
                     | 
				
			|||
                    // If we are dealing with a discrete-time model, we need to scale the probabilities such that they
 | 
				
			|||
                    // form a probability distribution.
 | 
				
			|||
                    if (model_is_discrete_time()) { | 
				
			|||
                        for (auto& element : choices.front().getDistribution()) { | 
				
			|||
                            element.scaleValue(choiceCount); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    choiceIsGuaranteedDistribution = true; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                for (auto& choice : choices) { | 
				
			|||
                    if (!choiceIsGuaranteedDistribution) { | 
				
			|||
                        // Create a proper distribution without duplicate entries.
 | 
				
			|||
                        choice.makeUniqueAndShrink(); | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // Add the elements to the transition matrix.
 | 
				
			|||
                    for (auto const& element : choice.getDistribution()) { | 
				
			|||
                        modelComponents.transitionMatrixBuilder.addNextValue(currentRow, element.getColumn(), element.getValue()); | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // Proceed to next row.
 | 
				
			|||
                    ++currentRow; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            IndexType getOrAddIndex(StateType const& state, StateSet& statesToExplore) { | 
				
			|||
                auto it = stateIds.find(state); | 
				
			|||
                if (it != stateIds.end()) { | 
				
			|||
                    return it->second; | 
				
			|||
                } else { | 
				
			|||
                    IndexType newIndex = static_cast<IndexType>(stateIds.size()); | 
				
			|||
                    stateIds.insert(std::make_pair(state, newIndex)); | 
				
			|||
#ifndef NDEBUG
 | 
				
			|||
                    std::cout << "inserting state " << state << std::endl; | 
				
			|||
#endif
 | 
				
			|||
                    statesToExplore.add(state); | 
				
			|||
                    return newIndex; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            IndexType getIndex(StateType const& state) const { | 
				
			|||
                auto it = stateIds.find(state); | 
				
			|||
                if (it != stateIds.end()) { | 
				
			|||
                    return it->second; | 
				
			|||
                } else { | 
				
			|||
                    return stateIds.at(state); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            static JitModelBuilderInterface<ValueType>* create() { | 
				
			|||
                return new JitBuilder(); | 
				
			|||
            } | 
				
			|||
                         | 
				
			|||
            private: | 
				
			|||
                spp::sparse_hash_map<StateType, IndexType> stateIds; | 
				
			|||
                std::vector<StateType> initialStates; | 
				
			|||
             | 
				
			|||
                uint64_t currentRow; | 
				
			|||
                ModelComponents modelComponents; | 
				
			|||
            }; | 
				
			|||
         | 
				
			|||
        BOOST_DLL_ALIAS(storm::builder::JitBuilder::create, create_builder) | 
				
			|||
                     | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
)"; | 
				
			|||
             | 
				
			|||
            cpptempl::data_map modelData; | 
				
			|||
            modelData["stateVariables"] = generateStateVariables(); | 
				
			|||
            cpptempl::data_list initialStates = generateInitialStates(); | 
				
			|||
            modelData["initialStates"] = cpptempl::make_data(initialStates); | 
				
			|||
            cpptempl::data_list nonSynchronizingEdges = generateNonSynchronizingEdges(); | 
				
			|||
            modelData["nonSynchronizingEdges"] = cpptempl::make_data(nonSynchronizingEdges); | 
				
			|||
            modelData["deterministic_model"] = model.isDeterministicModel() ? "true" : "false"; | 
				
			|||
            modelData["discrete_time_model"] = model.isDiscreteTimeModel() ? "true" : "false"; | 
				
			|||
            return cpptempl::parse(sourceTemplate, modelData); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        cpptempl::data_list ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateInitialStates() { | 
				
			|||
            cpptempl::data_list initialStates; | 
				
			|||
             | 
				
			|||
            // Prepare an SMT solver to enumerate all initial states.
 | 
				
			|||
            storm::utility::solver::SmtSolverFactory factory; | 
				
			|||
            std::unique_ptr<storm::solver::SmtSolver> solver = factory.create(model.getExpressionManager()); | 
				
			|||
             | 
				
			|||
            std::vector<storm::expressions::Expression> rangeExpressions = model.getAllRangeExpressions(); | 
				
			|||
            for (auto const& expression : rangeExpressions) { | 
				
			|||
                solver->add(expression); | 
				
			|||
            } | 
				
			|||
            solver->add(model.getInitialStatesExpression(true)); | 
				
			|||
             | 
				
			|||
            // Proceed as long as the solver can still enumerate initial states.
 | 
				
			|||
            while (solver->check() == storm::solver::SmtSolver::CheckResult::Sat) { | 
				
			|||
                // Create fresh state.
 | 
				
			|||
                cpptempl::data_list initialStateAssignment; | 
				
			|||
                 | 
				
			|||
                // Read variable assignment from the solution of the solver. Also, create an expression we can use to
 | 
				
			|||
                // prevent the variable assignment from being enumerated again.
 | 
				
			|||
                storm::expressions::Expression blockingExpression; | 
				
			|||
                std::shared_ptr<storm::solver::SmtSolver::ModelReference> model = solver->getModel(); | 
				
			|||
                for (auto const& variable : this->model.getGlobalVariables().getBooleanVariables()) { | 
				
			|||
                    storm::expressions::Variable const& expressionVariable = variable.getExpressionVariable(); | 
				
			|||
                    bool variableValue = model->getBooleanValue(expressionVariable); | 
				
			|||
                    initialStateAssignment.push_back(generateAssignment(variable, variableValue)); | 
				
			|||
                     | 
				
			|||
                    storm::expressions::Expression localBlockingExpression = variableValue ? !expressionVariable : expressionVariable; | 
				
			|||
                    blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; | 
				
			|||
                } | 
				
			|||
                for (auto const& variable : this->model.getGlobalVariables().getBoundedIntegerVariables()) { | 
				
			|||
                    storm::expressions::Variable const& expressionVariable = variable.getExpressionVariable(); | 
				
			|||
                    int_fast64_t variableValue = model->getIntegerValue(expressionVariable); | 
				
			|||
                    initialStateAssignment.push_back(generateAssignment(variable, variableValue)); | 
				
			|||
                     | 
				
			|||
                    storm::expressions::Expression localBlockingExpression = expressionVariable != model->getManager().integer(variableValue); | 
				
			|||
                    blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; | 
				
			|||
                } | 
				
			|||
                for (auto const& automaton : this->model.getAutomata()) { | 
				
			|||
                    for (auto const& variable : automaton.getVariables().getBooleanVariables()) { | 
				
			|||
                        storm::expressions::Variable const& expressionVariable = variable.getExpressionVariable(); | 
				
			|||
                        bool variableValue = model->getBooleanValue(expressionVariable); | 
				
			|||
                        initialStateAssignment.push_back(generateAssignment(variable, variableValue)); | 
				
			|||
                         | 
				
			|||
                        storm::expressions::Expression localBlockingExpression = variableValue ? !expressionVariable : expressionVariable; | 
				
			|||
                        blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; | 
				
			|||
                    } | 
				
			|||
                    for (auto const& variable : automaton.getVariables().getBoundedIntegerVariables()) { | 
				
			|||
                        storm::expressions::Variable const& expressionVariable = variable.getExpressionVariable(); | 
				
			|||
                        int_fast64_t variableValue = model->getIntegerValue(expressionVariable); | 
				
			|||
                        initialStateAssignment.push_back(generateAssignment(variable, variableValue)); | 
				
			|||
                         | 
				
			|||
                        storm::expressions::Expression localBlockingExpression = expressionVariable != model->getManager().integer(variableValue); | 
				
			|||
                        blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Gather iterators to the initial locations of all the automata.
 | 
				
			|||
                std::vector<std::set<uint64_t>::const_iterator> initialLocationsIterators; | 
				
			|||
                for (auto const& automaton : this->model.getAutomata()) { | 
				
			|||
                    initialLocationsIterators.push_back(automaton.getInitialLocationIndices().cbegin()); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Now iterate through all combinations of initial locations.
 | 
				
			|||
                while (true) { | 
				
			|||
                    cpptempl::data_list completeAssignment(initialStateAssignment); | 
				
			|||
                     | 
				
			|||
                    for (uint64_t index = 0; index < initialLocationsIterators.size(); ++index) { | 
				
			|||
                        storm::jani::Automaton const& automaton = this->model.getAutomata()[index]; | 
				
			|||
                        if (automaton.getNumberOfLocations() > 1) { | 
				
			|||
                            completeAssignment.push_back(generateLocationAssignment(automaton, *initialLocationsIterators[index])); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    initialStates.push_back(cpptempl::make_data(completeAssignment)); | 
				
			|||
                     | 
				
			|||
                    uint64_t index = 0; | 
				
			|||
                    for (; index < initialLocationsIterators.size(); ++index) { | 
				
			|||
                        ++initialLocationsIterators[index]; | 
				
			|||
                        if (initialLocationsIterators[index] == this->model.getAutomata()[index].getInitialLocationIndices().cend()) { | 
				
			|||
                            initialLocationsIterators[index] = this->model.getAutomata()[index].getInitialLocationIndices().cbegin(); | 
				
			|||
                        } else { | 
				
			|||
                            break; | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // If we are at the end, leave the loop.
 | 
				
			|||
                    if (index == initialLocationsIterators.size()) { | 
				
			|||
                        break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Block the current initial state to search for the next one.
 | 
				
			|||
                if (!blockingExpression.isInitialized()) { | 
				
			|||
                    break; | 
				
			|||
                } | 
				
			|||
                solver->add(blockingExpression); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            return initialStates; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        cpptempl::data_map ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateStateVariables() { | 
				
			|||
            cpptempl::data_list booleanVariables; | 
				
			|||
            cpptempl::data_list boundedIntegerVariables; | 
				
			|||
            cpptempl::data_list locationVariables; | 
				
			|||
             | 
				
			|||
            for (auto const& variable : model.getGlobalVariables().getBooleanVariables()) { | 
				
			|||
                cpptempl::data_map booleanVariable; | 
				
			|||
                std::string variableName = getQualifiedVariableName(variable); | 
				
			|||
                variableToName[variable.getExpressionVariable()] = variableName; | 
				
			|||
                booleanVariable["name"] = variableName; | 
				
			|||
                booleanVariables.push_back(booleanVariable); | 
				
			|||
            } | 
				
			|||
            for (auto const& variable : model.getGlobalVariables().getBoundedIntegerVariables()) { | 
				
			|||
                cpptempl::data_map boundedIntegerVariable; | 
				
			|||
                std::string variableName = getQualifiedVariableName(variable); | 
				
			|||
                variableToName[variable.getExpressionVariable()] = variableName; | 
				
			|||
 | 
				
			|||
                uint64_t range = static_cast<uint64_t>(variable.getUpperBound().evaluateAsInt() - variable.getLowerBound().evaluateAsInt() + 1); | 
				
			|||
                uint64_t numberOfBits = static_cast<uint64_t>(std::ceil(std::log2(range))); | 
				
			|||
                 | 
				
			|||
                boundedIntegerVariable["name"] = variableName; | 
				
			|||
                boundedIntegerVariable["numberOfBits"] = std::to_string(numberOfBits); | 
				
			|||
                boundedIntegerVariables.push_back(boundedIntegerVariable); | 
				
			|||
            } | 
				
			|||
            for (auto const& automaton : model.getAutomata()) { | 
				
			|||
                for (auto const& variable : automaton.getVariables().getBooleanVariables()) { | 
				
			|||
                    cpptempl::data_map booleanVariable; | 
				
			|||
                    std::string variableName = getQualifiedVariableName(automaton, variable); | 
				
			|||
                    variableToName[variable.getExpressionVariable()] = variableName; | 
				
			|||
                    booleanVariable["name"] = variableName; | 
				
			|||
                    booleanVariables.push_back(booleanVariable); | 
				
			|||
                } | 
				
			|||
                for (auto const& variable : automaton.getVariables().getBoundedIntegerVariables()) { | 
				
			|||
                    cpptempl::data_map boundedIntegerVariable; | 
				
			|||
                    std::string variableName = getQualifiedVariableName(automaton, variable); | 
				
			|||
                    variableToName[variable.getExpressionVariable()] = variableName; | 
				
			|||
                     | 
				
			|||
                    uint64_t range = static_cast<uint64_t>(variable.getUpperBound().evaluateAsInt() - variable.getLowerBound().evaluateAsInt()); | 
				
			|||
                    uint64_t numberOfBits = static_cast<uint64_t>(std::ceil(std::log2(range))); | 
				
			|||
                     | 
				
			|||
                    boundedIntegerVariable["name"] = variableName; | 
				
			|||
                    boundedIntegerVariable["numberOfBits"] = std::to_string(numberOfBits); | 
				
			|||
                    boundedIntegerVariables.push_back(boundedIntegerVariable); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Only generate a location variable if there is more than one location for the automaton.
 | 
				
			|||
                if (automaton.getNumberOfLocations() > 1) { | 
				
			|||
                    cpptempl::data_map locationVariable; | 
				
			|||
                    locationVariable["name"] = getLocationVariableName(automaton); | 
				
			|||
                    locationVariable["numberOfBits"] = static_cast<uint64_t>(std::ceil(std::log2(automaton.getNumberOfLocations()))); | 
				
			|||
                    locationVariables.push_back(locationVariable); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            cpptempl::data_map stateVariables; | 
				
			|||
            stateVariables["boolean"] = cpptempl::make_data(booleanVariables); | 
				
			|||
            stateVariables["boundedInteger"] = cpptempl::make_data(boundedIntegerVariables); | 
				
			|||
            stateVariables["locations"] = cpptempl::make_data(locationVariables); | 
				
			|||
            return stateVariables; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        cpptempl::data_list ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateNonSynchronizingEdges() { | 
				
			|||
            cpptempl::data_list edges; | 
				
			|||
            for (auto const& automaton : this->model.getAutomata()) { | 
				
			|||
                for (auto const& edge : automaton.getEdges()) { | 
				
			|||
                    if (edge.getActionIndex() == storm::jani::Model::SILENT_ACTION_INDEX) { | 
				
			|||
                        edges.push_back(generateEdge(edge)); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            return edges; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        cpptempl::data_map ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateEdge(storm::jani::Edge const& edge) { | 
				
			|||
            cpptempl::data_map edgeData; | 
				
			|||
             | 
				
			|||
            cpptempl::data_list destinations; | 
				
			|||
            for (auto const& destination : edge.getDestinations()) { | 
				
			|||
                destinations.push_back(generateDestination(destination)); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            edgeData["guard"] = expressionTranslator.translate(edge.getGuard(), storm::expressions::ToCppTranslationOptions("sourceState.")); | 
				
			|||
            edgeData["destinations"] = cpptempl::make_data(destinations); | 
				
			|||
            return edgeData; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        cpptempl::data_map ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateDestination(storm::jani::EdgeDestination const& destination) { | 
				
			|||
            cpptempl::data_map destinationData; | 
				
			|||
             | 
				
			|||
            cpptempl::data_list nonTransientAssignments; | 
				
			|||
            for (auto const& assignment : destination.getOrderedAssignments().getNonTransientAssignments()) { | 
				
			|||
                nonTransientAssignments.push_back(generateAssignment(assignment, "targetState.")); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            destinationData["nonTransientAssignments"] = cpptempl::make_data(nonTransientAssignments); | 
				
			|||
            destinationData["value"] = expressionTranslator.translate(destination.getProbability(), storm::expressions::ToCppTranslationOptions("sourceState.", "double")); | 
				
			|||
            return destinationData; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        template <typename ValueTypePrime> | 
				
			|||
        cpptempl::data_map ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateAssignment(storm::jani::Variable const& variable, ValueTypePrime value) const { | 
				
			|||
            cpptempl::data_map result; | 
				
			|||
            result["variable"] = getVariableName(variable.getExpressionVariable()); | 
				
			|||
            result["value"] = asString(value); | 
				
			|||
            return result; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        cpptempl::data_map ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateLocationAssignment(storm::jani::Automaton const& automaton, uint64_t value) const { | 
				
			|||
            cpptempl::data_map result; | 
				
			|||
            result["variable"] = getLocationVariableName(automaton); | 
				
			|||
            result["value"] = asString(value); | 
				
			|||
            return result; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        cpptempl::data_map ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::generateAssignment(storm::jani::Assignment const& assignment, std::string const& prefix) { | 
				
			|||
            cpptempl::data_map result; | 
				
			|||
            result["variable"] = getVariableName(assignment.getExpressionVariable()); | 
				
			|||
            result["value"] = expressionTranslator.translate(assignment.getAssignedExpression(), prefix); | 
				
			|||
            return result; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        std::string const& ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::getVariableName(storm::expressions::Variable const& variable) const { | 
				
			|||
            return variableToName.at(variable); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        std::string ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::getQualifiedVariableName(storm::jani::Variable const& variable) const { | 
				
			|||
            return variable.getName(); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        std::string ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::getQualifiedVariableName(storm::jani::Automaton const& automaton, storm::jani::Variable const& variable) const { | 
				
			|||
            return automaton.getName() + variable.getName(); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        std::string ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::getLocationVariableName(storm::jani::Automaton const& automaton) const { | 
				
			|||
            return automaton.getName() + "_location"; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        std::string ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::asString(bool value) const { | 
				
			|||
            std::stringstream out; | 
				
			|||
            out << std::boolalpha << value; | 
				
			|||
            return out.str(); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        template <typename ValueTypePrime> | 
				
			|||
        std::string ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::asString(ValueTypePrime value) const { | 
				
			|||
            return std::to_string(value); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        boost::optional<std::string> ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::execute(std::string command) { | 
				
			|||
            auto start = std::chrono::high_resolution_clock::now(); | 
				
			|||
            char buffer[128]; | 
				
			|||
            std::stringstream output; | 
				
			|||
            command += " 2>&1"; | 
				
			|||
             | 
				
			|||
            std::cout << "executing " << command << std::endl; | 
				
			|||
             | 
				
			|||
            std::unique_ptr<FILE> pipe(popen(command.c_str(), "r")); | 
				
			|||
            STORM_LOG_THROW(pipe, storm::exceptions::InvalidStateException, "Call to popen failed."); | 
				
			|||
             | 
				
			|||
            while (!feof(pipe.get())) { | 
				
			|||
                if (fgets(buffer, 128, pipe.get()) != nullptr) | 
				
			|||
                    output << buffer; | 
				
			|||
            } | 
				
			|||
            int result = pclose(pipe.get()); | 
				
			|||
            pipe.release(); | 
				
			|||
 | 
				
			|||
            auto end = std::chrono::high_resolution_clock::now(); | 
				
			|||
            std::cout << "Executing command took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl; | 
				
			|||
 | 
				
			|||
            if (WEXITSTATUS(result) == 0) { | 
				
			|||
                return boost::none; | 
				
			|||
            } else { | 
				
			|||
                return "Executing command failed. Got response: " + output.str(); | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        void ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::createBuilder(boost::filesystem::path const& dynamicLibraryPath) { | 
				
			|||
            jitBuilderGetFunction = boost::dll::import_alias<typename ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::CreateFunctionType>(dynamicLibraryPath, "create_builder"); | 
				
			|||
            builder = std::unique_ptr<JitModelBuilderInterface<ValueType>>(jitBuilderGetFunction()); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        boost::filesystem::path ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::writeSourceToTemporaryFile(std::string const& source) { | 
				
			|||
            boost::filesystem::path temporaryFile = boost::filesystem::unique_path("%%%%-%%%%-%%%%-%%%%.cpp"); | 
				
			|||
            std::ofstream out(temporaryFile.native()); | 
				
			|||
            out << source << std::endl; | 
				
			|||
            out.close(); | 
				
			|||
            return temporaryFile; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        boost::filesystem::path ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::compileSourceToSharedLibrary(boost::filesystem::path const& sourceFile) { | 
				
			|||
            std::string sourceFilename = boost::filesystem::absolute(sourceFile).string(); | 
				
			|||
            auto dynamicLibraryPath = sourceFile; | 
				
			|||
            dynamicLibraryPath += DYLIB_EXTENSION; | 
				
			|||
            std::string dynamicLibraryFilename = boost::filesystem::absolute(dynamicLibraryPath).string(); | 
				
			|||
             | 
				
			|||
            std::string command = CXX_COMPILER + " " + sourceFilename + " " + COMPILER_FLAGS + " -I" + STORM_ROOT + " -I" + STORM_ROOT + "/build_xcode/include -I" + L3PP_ROOT + " -I" + BOOST_ROOT + " -I" + GMP_ROOT + "/include -I" + CARL_ROOT + "/src -I" + CLN_ROOT + "/include -I" + GINAC_ROOT + "/include -o " + dynamicLibraryFilename; | 
				
			|||
            boost::optional<std::string> error = execute(command); | 
				
			|||
             | 
				
			|||
            if (error) { | 
				
			|||
                boost::filesystem::remove(sourceFile); | 
				
			|||
                STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Compiling shared library failed. Error: " << error.get()); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            return dynamicLibraryPath; | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType> | 
				
			|||
        std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::build() { | 
				
			|||
             | 
				
			|||
            // (1) generate the source code of the shared library
 | 
				
			|||
            std::string source; | 
				
			|||
            try { | 
				
			|||
                source = createSourceCode(); | 
				
			|||
            } catch (std::exception const& e) { | 
				
			|||
                STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "The model could not be successfully built (error: " << e.what() << ")."); | 
				
			|||
            } | 
				
			|||
            std::cout << "created source code: " << source << std::endl; | 
				
			|||
             | 
				
			|||
            // (2) write the source code to a temporary file
 | 
				
			|||
            boost::filesystem::path temporarySourceFile = writeSourceToTemporaryFile(source); | 
				
			|||
            std::cout << "wrote source to file " << temporarySourceFile.native() << std::endl; | 
				
			|||
             | 
				
			|||
            // (3) compile the shared library
 | 
				
			|||
            boost::filesystem::path dynamicLibraryPath = compileSourceToSharedLibrary(temporarySourceFile); | 
				
			|||
            std::cout << "successfully compiled shared library" << std::endl; | 
				
			|||
             | 
				
			|||
            // (4) remove the source code we just compiled
 | 
				
			|||
            boost::filesystem::remove(temporarySourceFile); | 
				
			|||
             | 
				
			|||
            // (5) create the loader from the shared library
 | 
				
			|||
            createBuilder(dynamicLibraryPath); | 
				
			|||
             | 
				
			|||
            // (6) execute the function in the shared lib
 | 
				
			|||
            auto sparseModel = builder->build(); | 
				
			|||
             | 
				
			|||
            // (7) delete the shared library
 | 
				
			|||
            boost::filesystem::remove(dynamicLibraryPath); | 
				
			|||
             | 
				
			|||
            // Return the constructed model.
 | 
				
			|||
            return std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>(sparseModel); | 
				
			|||
        } | 
				
			|||
         | 
				
			|||
        template class ExplicitJitJaniModelBuilder<double, storm::models::sparse::StandardRewardModel<double>>; | 
				
			|||
        template class ExplicitJitJaniModelBuilder<storm::RationalNumber, storm::models::sparse::StandardRewardModel<storm::RationalNumber>>; | 
				
			|||
        template class ExplicitJitJaniModelBuilder<storm::RationalFunction, storm::models::sparse::StandardRewardModel<storm::RationalFunction>>; | 
				
			|||
         | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -1,83 +0,0 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <memory> | 
				
			|||
 | 
				
			|||
#include <boost/filesystem.hpp> | 
				
			|||
#include <boost/dll/import.hpp> | 
				
			|||
#include <boost/function.hpp> | 
				
			|||
 | 
				
			|||
#include "cpptempl.h" | 
				
			|||
 | 
				
			|||
#include "src/storage/jani/Model.h" | 
				
			|||
#include "src/storage/expressions/ToCppVisitor.h" | 
				
			|||
 | 
				
			|||
#include "src/models/sparse/StandardRewardModel.h" | 
				
			|||
 | 
				
			|||
#include "src/builder/JitModelBuilderInterface.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace models { | 
				
			|||
        namespace sparse { | 
				
			|||
            template <typename ValueType, typename RewardModelType> | 
				
			|||
            class Model; | 
				
			|||
             | 
				
			|||
            template <typename ValueType> | 
				
			|||
            class StandardRewardModel; | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
     | 
				
			|||
    namespace builder { | 
				
			|||
         | 
				
			|||
        template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>> | 
				
			|||
        class ExplicitJitJaniModelBuilder { | 
				
			|||
        public: | 
				
			|||
            typedef JitModelBuilderInterface<ValueType>* (CreateFunctionType)(); | 
				
			|||
            typedef boost::function<CreateFunctionType> ImportFunctionType; | 
				
			|||
             | 
				
			|||
            ExplicitJitJaniModelBuilder(storm::jani::Model const& model); | 
				
			|||
             | 
				
			|||
            std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> build(); | 
				
			|||
             | 
				
			|||
        private: | 
				
			|||
            void createBuilder(boost::filesystem::path const& dynamicLibraryPath); | 
				
			|||
            std::string createSourceCode(); | 
				
			|||
            boost::filesystem::path writeSourceToTemporaryFile(std::string const& source); | 
				
			|||
            boost::filesystem::path compileSourceToSharedLibrary(boost::filesystem::path const& sourceFile); | 
				
			|||
 | 
				
			|||
            static boost::optional<std::string> execute(std::string command); | 
				
			|||
             | 
				
			|||
            // Functions that generate data maps or data templates. | 
				
			|||
            cpptempl::data_list generateInitialStates(); | 
				
			|||
            cpptempl::data_map generateStateVariables(); | 
				
			|||
            cpptempl::data_list generateNonSynchronizingEdges(); | 
				
			|||
 | 
				
			|||
            cpptempl::data_map generateEdge(storm::jani::Edge const& edge); | 
				
			|||
            cpptempl::data_map generateDestination(storm::jani::EdgeDestination const& destination); | 
				
			|||
             | 
				
			|||
            template <typename ValueTypePrime> | 
				
			|||
            cpptempl::data_map generateAssignment(storm::jani::Variable const& variable, ValueTypePrime value) const; | 
				
			|||
             | 
				
			|||
            cpptempl::data_map generateLocationAssignment(storm::jani::Automaton const& automaton, uint64_t value) const; | 
				
			|||
 | 
				
			|||
            cpptempl::data_map generateAssignment(storm::jani::Assignment const& assignment, std::string const& prefix = ""); | 
				
			|||
             | 
				
			|||
            // Auxiliary functions that perform regularly needed steps. | 
				
			|||
            std::string const& getVariableName(storm::expressions::Variable const& variable) const; | 
				
			|||
            std::string getQualifiedVariableName(storm::jani::Automaton const& automaton, storm::jani::Variable const& variable) const; | 
				
			|||
            std::string getQualifiedVariableName(storm::jani::Variable const& variable) const; | 
				
			|||
            std::string getLocationVariableName(storm::jani::Automaton const& automaton) const; | 
				
			|||
            std::string asString(bool value) const; | 
				
			|||
             | 
				
			|||
            template <typename ValueTypePrime> | 
				
			|||
            std::string asString(ValueTypePrime value) const; | 
				
			|||
             | 
				
			|||
            storm::jani::Model model; | 
				
			|||
            typename ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::ImportFunctionType jitBuilderGetFunction; | 
				
			|||
            std::unique_ptr<JitModelBuilderInterface<ValueType>> builder; | 
				
			|||
             | 
				
			|||
            std::unordered_map<storm::expressions::Variable, std::string> variableToName; | 
				
			|||
            storm::expressions::ToCppVisitor expressionTranslator; | 
				
			|||
        }; | 
				
			|||
         | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -1,23 +0,0 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <memory> | 
				
			|||
 | 
				
			|||
#include "src/models/sparse/Model.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
         | 
				
			|||
        template <typename ValueType> | 
				
			|||
        class JitModelBuilderInterface { | 
				
			|||
        public: | 
				
			|||
            virtual ~JitModelBuilderInterface() { | 
				
			|||
                // Intentionally left empty. | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            virtual storm::models::sparse::Model<ValueType>* build() { | 
				
			|||
                return nullptr; | 
				
			|||
            } | 
				
			|||
        }; | 
				
			|||
         | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,19 @@ | 
				
			|||
#include "src/builder/jit/Choice.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            void Choice<IndexType, ValueType>::add(DistributionEntry<IndexType, ValueType> const& entry) { | 
				
			|||
                distribution.add(entry); | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            Distribution<IndexType, ValueType> const& Choice<IndexType, ValueType>::getDistribution() const { | 
				
			|||
                return distribution; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,22 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include "src/builder/jit/Distribution.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            class Choice { | 
				
			|||
            public: | 
				
			|||
                void add(DistributionEntry<IndexType, ValueType> const& entry); | 
				
			|||
                 | 
				
			|||
                Distribution<IndexType, ValueType> const& getDistribution() const; | 
				
			|||
                 | 
				
			|||
            private: | 
				
			|||
                Distribution<IndexType, ValueType> distribution; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,43 @@ | 
				
			|||
#include "src/builder/jit/Distribution.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            void Distribution<IndexType, ValueType>::add(DistributionEntry<IndexType, ValueType> const& entry) { | 
				
			|||
                storage.push_back(entry); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            void Distribution<IndexType, ValueType>::compress() { | 
				
			|||
                std::sort(storage.begin(), storage.end(), | 
				
			|||
                          [] (DistributionEntry<IndexType, ValueType> const& a, DistributionEntry<IndexType, ValueType> const& b) { | 
				
			|||
                              return a.getIndex() < b.getIndex(); | 
				
			|||
                          } | 
				
			|||
                ); | 
				
			|||
                 | 
				
			|||
                // Code taken from std::unique and modified to fit needs.
 | 
				
			|||
                auto first = storage.begin(); | 
				
			|||
                auto last = storage.end(); | 
				
			|||
                 | 
				
			|||
                if (first != last) { | 
				
			|||
                    auto result = first; | 
				
			|||
                    while (++first != last) { | 
				
			|||
                        if (!(result->getColumn() == first->getColumn())) { | 
				
			|||
                            if (++result != first) { | 
				
			|||
                                *result = std::move(*first); | 
				
			|||
                            } | 
				
			|||
                        } else { | 
				
			|||
                            result->addToValue(first->getValue()); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    ++result; | 
				
			|||
                     | 
				
			|||
                    storage.resize(std::distance(storage.begin(), result)); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,44 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <vector> | 
				
			|||
 | 
				
			|||
#include "src/builder/jit/DistributionEntry.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            class Distribution { | 
				
			|||
            public: | 
				
			|||
                typedef std::vector<DistributionEntry<IndexType, ValueType>> ContainerType; | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Adds the given entry to the distribution. | 
				
			|||
                 */ | 
				
			|||
                void add(DistributionEntry<IndexType, ValueType> const& entry); | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Compresses the internal storage by summing the values of entries which agree on the index. As a side | 
				
			|||
                 * effect, this sorts the entries in the distribution by their index. | 
				
			|||
                 */ | 
				
			|||
                void compress(); | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Access to iterators over the entries of the distribution. Note that there may be multiple entries for | 
				
			|||
                 * the same index. Also, no order is guaranteed. After a call to compress, the order is guaranteed to be | 
				
			|||
                 * ascending wrt. index and there are no elements with the same index. | 
				
			|||
                 */ | 
				
			|||
                typename ContainerType::iterator begin(); | 
				
			|||
                typename ContainerType::const_iterator begin() const; | 
				
			|||
                typename ContainerType::iterator end(); | 
				
			|||
                typename ContainerType::const_iterator end() const; | 
				
			|||
                 | 
				
			|||
            private: | 
				
			|||
                // The underlying storage of the distribution. | 
				
			|||
                ContainerType storage; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,24 @@ | 
				
			|||
#include "src/builder/jit/DistributionEntry.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            DistributionEntry<IndexType, ValueType>::DistributionEntry(IndexType const& index, ValueType const& value) : index(index), value(value) { | 
				
			|||
                // Intentionally left empty.
 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            IndexType const& DistributionEntry<IndexType, ValueType>::getIndex() const { | 
				
			|||
                return index; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            ValueType const& DistributionEntry<IndexType, ValueType>::getValue() const { | 
				
			|||
                return value; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,22 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            class DistributionEntry { | 
				
			|||
            public: | 
				
			|||
                DistributionEntry(IndexType const& index, ValueType const& value); | 
				
			|||
                 | 
				
			|||
                IndexType const& getIndex() const; | 
				
			|||
                ValueType const& getValue() const; | 
				
			|||
                 | 
				
			|||
            private: | 
				
			|||
                IndexType index; | 
				
			|||
                ValueType value; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,24 @@ | 
				
			|||
#include "src/builder/jit/JitModelBuilderInterface.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            JitModelBuilderInterface<IndexType, ValueType>::JitModelBuilderInterface(ModelComponentsBuilder<IndexType, ValueType>& modelComponentsBuilder) : modelComponentsBuilder(modelComponentsBuilder) { | 
				
			|||
                // Intentionally left empty.
 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            JitModelBuilderInterface<IndexType, ValueType>::~JitModelBuilderInterface() { | 
				
			|||
                // Intentionally left empty.
 | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            void JitModelBuilderInterface<IndexType, ValueType>::addStateBehaviour(StateBehaviour<IndexType, ValueType> const& behaviour) { | 
				
			|||
                modelComponentsBuilder.addStateBehaviour(behaviour); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,64 @@ | 
				
			|||
#include "src/builder/jit/ModelComponentBuilder.h"
 | 
				
			|||
 | 
				
			|||
#include "src/storage/SparseMatrix.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            ModelComponentsBuilder<IndexType, ValueType>::ModelComponentsBuilder(storm::jani::ModelType const& modelType) : modelType(modelType), isDeterministicModel(storm::jani::isDeterministicModel(modelType)), isDiscreteTimeModel(storm::jani::isDiscreteTimeModel(modelType)), transitionMatrixBuilder(std::make_unique<storm::storage::SparseMatrixBuilder<ValueType>>(0, 0, 0, true, !isDeterministicModel)) { | 
				
			|||
                // Intentionally left empty.
 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            void ModelComponentsBuilder<IndexType, ValueType>::addStateBehaviour(StateBehaviour<IndexType, ValueType> const& behaviour) { | 
				
			|||
                // If there is more than one choice in a deterministic model, we need to combine the choices into one
 | 
				
			|||
                // global choice.
 | 
				
			|||
                bool choiceIsGuaranteedDistribution = false; | 
				
			|||
                if (model_is_deterministic() && choices.size() > 1) { | 
				
			|||
                    uint64_t choiceCount = choices.size(); | 
				
			|||
                     | 
				
			|||
                    // We do this by adding the entries of choices after the first one to the first one and then making
 | 
				
			|||
                    // the distribution unique again.
 | 
				
			|||
                    for (auto it = ++choices.begin(), ite = choices.end(); it != ite; ++it) { | 
				
			|||
                        choices.front().add(std::move(*it)); | 
				
			|||
                    } | 
				
			|||
                    choices.resize(1); | 
				
			|||
                    choices.front().makeUniqueAndShrink(); | 
				
			|||
                     | 
				
			|||
                    // If we are dealing with a discrete-time model, we need to scale the probabilities such that they
 | 
				
			|||
                    // form a probability distribution.
 | 
				
			|||
                    if (model_is_discrete_time()) { | 
				
			|||
                        for (auto& element : choices.front().getDistribution()) { | 
				
			|||
                            element.scaleValue(choiceCount); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    choiceIsGuaranteedDistribution = true; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                for (auto& choice : choices) { | 
				
			|||
                    if (!choiceIsGuaranteedDistribution) { | 
				
			|||
                        // Create a proper distribution without duplicate entries.
 | 
				
			|||
                        choice.makeUniqueAndShrink(); | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // Add the elements to the transition matrix.
 | 
				
			|||
                    for (auto const& element : choice.getDistribution()) { | 
				
			|||
                        modelComponents.transitionMatrixBuilder.addNextValue(currentRow, element.getColumn(), element.getValue()); | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // Proceed to next row.
 | 
				
			|||
                    ++currentRow; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            storm::models::sparse::Model<ValueType, storm::models::sparse::StandardRewardModel<ValueType>>* ModelComponentsBuilder<IndexType, ValueType>::build() { | 
				
			|||
                // FIXME
 | 
				
			|||
                return nullptr; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,46 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <memory> | 
				
			|||
 | 
				
			|||
#include "src/builder/jit/StateBehaviour.h" | 
				
			|||
 | 
				
			|||
#include "src/storage/jani/ModelType.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace storage { | 
				
			|||
        template <typename ValueType> | 
				
			|||
        class SparseMatrixBuilder; | 
				
			|||
    } | 
				
			|||
     | 
				
			|||
    namespace models { | 
				
			|||
        namespace sparse { | 
				
			|||
            template <typename ValueType> | 
				
			|||
            class StandardRewardModel; | 
				
			|||
             | 
				
			|||
            template <typename ValueType, typename RewardModelType> | 
				
			|||
            class Model; | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
     | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            class ModelComponentsBuilder { | 
				
			|||
            public: | 
				
			|||
                ModelComponentsBuilder(storm::jani::ModelType const& modelType); | 
				
			|||
                 | 
				
			|||
                void addStateBehaviour(StateBehaviour<IndexType, ValueType> const& behaviour); | 
				
			|||
 | 
				
			|||
                storm::models::sparse::Model<ValueType, storm::models::sparse::StandardRewardModel<ValueType>>* build(); | 
				
			|||
                 | 
				
			|||
            private: | 
				
			|||
                storm::jani::ModelType modelType; | 
				
			|||
                bool isDeterministicModel; | 
				
			|||
                bool isDiscreteTimeModel; | 
				
			|||
                std::unique_ptr<storm::storage::SparseMatrixBuilder<ValueType>> transitionMatrixBuilder; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,25 @@ | 
				
			|||
#include "src/builder/jit/StateBehaviour.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            void StateBehaviour<IndexType, ValueType>::addChoice(Choice<IndexType, ValueType>&& choice) { | 
				
			|||
                choices.emplace_back(std::move(choice)); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            Choice<IndexType, ValueType>& StateBehaviour<IndexType, ValueType>::addChoice() { | 
				
			|||
                choices.emplace_back(); | 
				
			|||
                return choices.back(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            void StateBehaviour<IndexType, ValueType>::clear() { | 
				
			|||
                choices.clear(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,25 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include "src/builder/jit/Choice.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace builder { | 
				
			|||
        namespace jit { | 
				
			|||
          | 
				
			|||
            template <typename IndexType, typename ValueType> | 
				
			|||
            class StateBehaviour { | 
				
			|||
            public: | 
				
			|||
                typedef std::vector<Choice<IndexType, ValueType>> ContainerType; | 
				
			|||
                 | 
				
			|||
                void addChoice(Choice<IndexType, ValueType>&& choice); | 
				
			|||
                Choice<IndexType, ValueType>& addChoice(); | 
				
			|||
                 | 
				
			|||
                void clear(); | 
				
			|||
                 | 
				
			|||
            private: | 
				
			|||
                ContainerType choices; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue