diff --git a/CMakeLists.txt b/CMakeLists.txt index c9b078811..13ccb71fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required (VERSION 2.8.6) - +cmake_policy(VERSION 3.2) # Set project name project (storm CXX C) @@ -29,6 +29,7 @@ option(USE_LIBCXX "Sets whether the standard library is libc++." OFF) option(USE_CARL "Sets whether carl should be included." ON) option(USE_XERCES "Sets whether xerces should be used." OFF) option(FORCE_COLOR "Force color output" OFF) +option(STORM_PYTHON "Builds the API for Python" OFF) option(STORM_COMPILE_WITH_CCACHE "Compile using CCache" ON) option(STORM_LOG_DISABLE_DEBUG "Disable log and trace message support" OFF) set(BOOST_ROOT "" CACHE STRING "A hint to the root directory of Boost (optional).") @@ -61,6 +62,9 @@ endif() # Base path for test files set(STORM_CPP_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/test") +set(STORMPY_OUTPUT_DIR "${PROJECT_BINARY_DIR}/stormpy") +set(STORMPY_SOURCE_DIR "${PROJECT_SOURCE_DIR}/stormpy") + # Auto-detect operating system. set(MACOSX 0) set(LINUX 0) @@ -95,6 +99,7 @@ endif() message(STATUS "Assuming extension for shared libraries: ${DYNAMIC_EXT}") message(STATUS "Assuming extension for static libraries: ${STATIC_EXT}") + ############################################################# ## ## Compiler specific settings and definitions @@ -221,7 +226,7 @@ find_package(GMP QUIET) ############################################################# # Boost Option variables -set(Boost_USE_STATIC_LIBS ON) +set(Boost_USE_STATIC_LIBS ${USE_BOOST_STATIC_LIBRARIES}) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) diff --git a/install.sh b/install.sh new file mode 100755 index 000000000..86e8ffcb0 --- /dev/null +++ b/install.sh @@ -0,0 +1,2 @@ +#!/bin/bash +pip install -ve . --install-option="--cmake=" --install-option="--make=" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 345efa36c..d75204355 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -110,7 +110,7 @@ endif(ADDITIONAL_LINK_DIRS) ## All link_directories() calls MUST be made before this point # ## # ############################################################################### -add_library(storm STATIC ${STORM_LIB_SOURCES} ${STORM_LIB_HEADERS}) # Adding headers for xcode +add_library(storm SHARED ${STORM_LIB_SOURCES} ${STORM_LIB_HEADERS}) # Adding headers for xcode add_dependencies(storm sylvan) add_dependencies(storm resources) add_executable(storm-main ${STORM_MAIN_SOURCES} ${STORM_MAIN_HEADERS}) diff --git a/src/adapters/AddExpressionAdapter.h b/src/adapters/AddExpressionAdapter.h index 9e74fd49d..ad82146f3 100644 --- a/src/adapters/AddExpressionAdapter.h +++ b/src/adapters/AddExpressionAdapter.h @@ -3,7 +3,7 @@ #include "src/storage/expressions/Variable.h" #include "src/storage/expressions/Expressions.h" -#include "storage/expressions/ExpressionVisitor.h" +#include "src/storage/expressions/ExpressionVisitor.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" diff --git a/src/builder/DdPrismModelBuilder.cpp b/src/builder/DdPrismModelBuilder.cpp index 6bf7284b2..a9230dbcb 100644 --- a/src/builder/DdPrismModelBuilder.cpp +++ b/src/builder/DdPrismModelBuilder.cpp @@ -201,7 +201,7 @@ namespace storm { } template - DdPrismModelBuilder::Options::Options(std::vector> const& formulas) : buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() { + DdPrismModelBuilder::Options::Options(std::vector> const& formulas) : buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() { if (formulas.empty()) { this->buildAllRewardModels = true; this->buildAllLabels = true; diff --git a/src/builder/DdPrismModelBuilder.h b/src/builder/DdPrismModelBuilder.h index 279548172..3a468d6bc 100644 --- a/src/builder/DdPrismModelBuilder.h +++ b/src/builder/DdPrismModelBuilder.h @@ -48,7 +48,7 @@ namespace storm { * * @param formula Thes formula based on which to choose the building options. */ - Options(std::vector> const& formulas); + Options(std::vector> const& formulas); /*! * Sets the constants definitions from the given string. The string must be of the form 'X=a,Y=b,Z=c', diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index d5b8660b2..687e9fb41 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -79,7 +79,7 @@ namespace storm { } template - ExplicitPrismModelBuilder::Options::Options(std::vector> const& formulas) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { + ExplicitPrismModelBuilder::Options::Options(std::vector> const& formulas) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { if (formulas.empty()) { this->buildAllRewardModels = true; this->buildAllLabels = true; @@ -489,4 +489,4 @@ namespace storm { template class ExplicitPrismModelBuilder, uint32_t>; #endif } -} \ No newline at end of file +} diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index d790f0bb1..92de20f2f 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "src/storage/prism/Program.h" @@ -87,7 +88,7 @@ namespace storm { * * @param formula Thes formula based on which to choose the building options. */ - Options(std::vector> const& formulas); + Options(std::vector> const& formulas); /*! * Sets the constants definitions from the given string. The string must be of the form 'X=a,Y=b,Z=c', diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 0b384b539..3b5a5fcc2 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -216,7 +216,7 @@ namespace storm { } // Then proceed to parsing the property (if given), since the model we are building may depend on the property. - std::vector> parsedFormulas; + std::vector> parsedFormulas; if (settings.isPropertySet()) { std::string properties = settings.getProperty(); @@ -227,7 +227,7 @@ namespace storm { } } - std::vector> formulas(parsedFormulas.begin(), parsedFormulas.end()); + std::vector> formulas(parsedFormulas.begin(), parsedFormulas.end()); if (settings.isSymbolicSet()) { #ifdef STORM_HAVE_CARL @@ -247,4 +247,4 @@ namespace storm { } } - } \ No newline at end of file + } diff --git a/src/cli/entrypoints.h b/src/cli/entrypoints.h index 8748c5a17..c1f88a9b4 100644 --- a/src/cli/entrypoints.h +++ b/src/cli/entrypoints.h @@ -9,7 +9,7 @@ namespace storm { namespace cli { template - void verifySparseModel(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void verifySparseModel(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { for (auto const& formula : formulas) { std::cout << std::endl << "Model checking property: " << *formula << " ..."; std::unique_ptr result(storm::verifySparseModel(model, formula, onlyInitialStatesRelevant)); @@ -26,7 +26,7 @@ namespace storm { #ifdef STORM_HAVE_CARL template<> - inline void verifySparseModel(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant) { + inline void verifySparseModel(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant) { for (auto const& formula : formulas) { STORM_LOG_THROW(model->getType() == storm::models::ModelType::Dtmc, storm::exceptions::InvalidSettingsException, "Currently parametric verification is only available for DTMCs."); @@ -50,12 +50,12 @@ namespace storm { #endif template - void verifySymbolicModelWithAbstractionRefinementEngine(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void verifySymbolicModelWithAbstractionRefinementEngine(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Abstraction Refinement is not yet implemented."); } template - void verifySymbolicModelWithExplorationEngine(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void verifySymbolicModelWithExplorationEngine(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { for (auto const& formula : formulas) { STORM_LOG_THROW(program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::InvalidSettingsException, "Currently exploration-based verification is only available for DTMCs and MDPs."); @@ -80,13 +80,13 @@ namespace storm { #ifdef STORM_HAVE_CARL template<> - void verifySymbolicModelWithExplorationEngine(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant) { + void verifySymbolicModelWithExplorationEngine(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Exploration-based verification does currently not support parametric models."); } #endif template - void verifySymbolicModelWithHybridEngine(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void verifySymbolicModelWithHybridEngine(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { for (auto const& formula : formulas) { std::cout << std::endl << "Model checking property: " << *formula << " ..."; std::unique_ptr result(storm::verifySymbolicModelWithHybridEngine(model, formula, onlyInitialStatesRelevant)); @@ -103,7 +103,7 @@ namespace storm { } template - void verifySymbolicModelWithSymbolicEngine(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void verifySymbolicModelWithSymbolicEngine(std::shared_ptr> model, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { for (auto const& formula : formulas) { std::cout << std::endl << "Model checking property: " << *formula << " ..."; std::unique_ptr result(storm::verifySymbolicModelWithDdEngine(model, formula, onlyInitialStatesRelevant)); @@ -145,7 +145,7 @@ namespace storm { } template - void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { storm::settings::modules::GeneralSettings const& settings = storm::settings::generalSettings(); @@ -191,7 +191,7 @@ namespace storm { } template - void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { if (storm::settings::generalSettings().getDdLibraryType() == storm::dd::DdType::CUDD) { buildAndCheckSymbolicModel(program, formulas, onlyInitialStatesRelevant); } else if (storm::settings::generalSettings().getDdLibraryType() == storm::dd::DdType::Sylvan) { @@ -200,7 +200,7 @@ namespace storm { } template - void buildAndCheckExplicitModel(std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { + void buildAndCheckExplicitModel(std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { storm::settings::modules::GeneralSettings const& settings = storm::settings::generalSettings(); STORM_LOG_THROW(settings.isExplicitSet(), storm::exceptions::InvalidStateException, "Unable to build explicit model without model files."); diff --git a/src/counterexamples/MILPMinimalLabelSetGenerator.h b/src/counterexamples/MILPMinimalLabelSetGenerator.h index ffc398e34..3c805d7fe 100644 --- a/src/counterexamples/MILPMinimalLabelSetGenerator.h +++ b/src/counterexamples/MILPMinimalLabelSetGenerator.h @@ -974,7 +974,7 @@ namespace storm { * @param formulaPtr A pointer to a safety formula. The outermost operator must be a probabilistic bound operator with a strict upper bound. The nested * formula can be either an unbounded until formula or an eventually formula. */ - static void computeCounterexample(storm::prism::Program const& program, storm::models::sparse::Mdp const& labeledMdp, std::shared_ptr const& formula) { + static void computeCounterexample(storm::prism::Program const& program, storm::models::sparse::Mdp const& labeledMdp, std::shared_ptr const& formula) { std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; STORM_LOG_THROW(formula->isProbabilityOperatorFormula(), storm::exceptions::InvalidPropertyException, "Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element."); diff --git a/src/counterexamples/SMTMinimalCommandSetGenerator.h b/src/counterexamples/SMTMinimalCommandSetGenerator.h index f7a2704b5..6cf9e9e8a 100644 --- a/src/counterexamples/SMTMinimalCommandSetGenerator.h +++ b/src/counterexamples/SMTMinimalCommandSetGenerator.h @@ -1751,7 +1751,7 @@ namespace storm { #endif } - static void computeCounterexample(storm::prism::Program program, std::string const& constantDefinitionString, storm::models::sparse::Mdp const& labeledMdp, std::shared_ptr const& formula) { + static void computeCounterexample(storm::prism::Program program, std::string const& constantDefinitionString, storm::models::sparse::Mdp const& labeledMdp, std::shared_ptr const& formula) { #ifdef STORM_HAVE_Z3 std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; diff --git a/src/exceptions/BaseException.h b/src/exceptions/BaseException.h index cfb97580d..9b7cabd5f 100644 --- a/src/exceptions/BaseException.h +++ b/src/exceptions/BaseException.h @@ -4,7 +4,7 @@ #include #include -#include "utility/OsDetection.h" +#include "src/utility/OsDetection.h" namespace storm { namespace exceptions { diff --git a/src/logic/BinaryStateFormula.cpp b/src/logic/BinaryStateFormula.cpp index 9fcdad992..f70abed3e 100644 --- a/src/logic/BinaryStateFormula.cpp +++ b/src/logic/BinaryStateFormula.cpp @@ -9,7 +9,7 @@ namespace storm { bool BinaryStateFormula::isBinaryStateFormula() const { return true; } - + Formula const& BinaryStateFormula::getLeftSubformula() const { return *leftSubformula; } @@ -33,4 +33,4 @@ namespace storm { this->getRightSubformula().gatherReferencedRewardModels(referencedRewardModels); } } -} \ No newline at end of file +} diff --git a/src/models/ModelBase.cpp b/src/models/ModelBase.cpp index 00a566b9b..92a2bb560 100644 --- a/src/models/ModelBase.cpp +++ b/src/models/ModelBase.cpp @@ -18,8 +18,16 @@ namespace storm { return this->getType() == modelType; } - bool ModelBase::isParametric() const { + bool ModelBase::supportsParameters() const { + return false; + } + + bool ModelBase::hasParameters() const { + return false; + } + + bool ModelBase::isExact() const { return false; } } -} \ No newline at end of file +} diff --git a/src/models/ModelBase.h b/src/models/ModelBase.h index 9fd80171a..eaa3c2b65 100644 --- a/src/models/ModelBase.h +++ b/src/models/ModelBase.h @@ -98,9 +98,25 @@ namespace storm { bool isOfType(storm::models::ModelType const& modelType) const; /*! - * Checks whether the model is parametric + * Checks whether the model supports parameters. + * + * @return True iff the model supports parameters. + */ + virtual bool supportsParameters() const; + + /*! + * Checks whether the model has parameters. + * + * @return True iff the model has parameters. + */ + virtual bool hasParameters() const; + + /*! + * Checks whether the model is exact. + * + * @return True iff the model is exact. */ - virtual bool isParametric() const; + virtual bool isExact() const; private: // The type of the model. diff --git a/src/models/sparse/Model.cpp b/src/models/sparse/Model.cpp index f0cf38e1c..265f0d8b0 100644 --- a/src/models/sparse/Model.cpp +++ b/src/models/sparse/Model.cpp @@ -311,10 +311,31 @@ namespace storm { } template - bool Model::isParametric() const { + bool Model::supportsParameters() const { return std::is_same::value; } + template + bool Model::hasParameters() const { + if (!this->supportsParameters()) { + return false; + } + // Check for parameters + for (auto const& entry : this->getTransitionMatrix()) { + if (!storm::utility::isConstant(entry.getValue())) { + return true; + } + } + // Only constant values present + return false; + } + + template + bool Model::isExact() const { + // TODO: change when dedicated data-structure for exact values is present + return this->supportsParameters(); + } + template std::unordered_map& Model::getRewardModels() { return this->rewardModels; @@ -342,4 +363,4 @@ namespace storm { } } -} \ No newline at end of file +} diff --git a/src/models/sparse/Model.h b/src/models/sparse/Model.h index a458bdff7..a73b10c8f 100644 --- a/src/models/sparse/Model.h +++ b/src/models/sparse/Model.h @@ -293,7 +293,17 @@ namespace storm { virtual bool isSparseModel() const override; - virtual bool isParametric() const override; + virtual bool supportsParameters() const override; + + /*! + * Checks whether the model has parameters. + * Performance warning: the worst-case complexity is linear in the number of transitions. + * + * @return True iff the model has parameters. + */ + virtual bool hasParameters() const override; + + virtual bool isExact() const override; protected: RewardModelType & rewardModel(std::string const& rewardModelName); diff --git a/src/parser/FormulaParser.cpp b/src/parser/FormulaParser.cpp index dd0137d9a..80aa2f421 100644 --- a/src/parser/FormulaParser.cpp +++ b/src/parser/FormulaParser.cpp @@ -10,7 +10,7 @@ namespace storm { namespace parser { - class FormulaParserGrammar : public qi::grammar>(), Skipper> { + class FormulaParserGrammar : public qi::grammar>(), Skipper> { public: FormulaParserGrammar(std::shared_ptr const& manager = std::shared_ptr(new storm::expressions::ExpressionManager())); @@ -106,66 +106,66 @@ namespace storm { // they are to be replaced with. qi::symbols identifiers_; - qi::rule>(), Skipper> start; + qi::rule>(), Skipper> start; qi::rule, boost::optional, boost::optional>, Skipper> operatorInformation; qi::rule rewardMeasureType; - qi::rule(), Skipper> probabilityOperator; - qi::rule(), Skipper> rewardOperator; - qi::rule(), Skipper> timeOperator; - qi::rule(), Skipper> longRunAverageOperator; - - qi::rule(), Skipper> simpleFormula; - qi::rule(), Skipper> stateFormula; - qi::rule(storm::logic::FormulaContext), Skipper> pathFormula; - qi::rule(storm::logic::FormulaContext), Skipper> pathFormulaWithoutUntil; - qi::rule(), Skipper> simplePathFormula; - qi::rule(), Skipper> atomicStateFormula; - qi::rule(), Skipper> operatorFormula; + qi::rule(), Skipper> probabilityOperator; + qi::rule(), Skipper> rewardOperator; + qi::rule(), Skipper> timeOperator; + qi::rule(), Skipper> longRunAverageOperator; + + qi::rule(), Skipper> simpleFormula; + qi::rule(), Skipper> stateFormula; + qi::rule(storm::logic::FormulaContext), Skipper> pathFormula; + qi::rule(storm::logic::FormulaContext), Skipper> pathFormulaWithoutUntil; + qi::rule(), Skipper> simplePathFormula; + qi::rule(), Skipper> atomicStateFormula; + qi::rule(), Skipper> operatorFormula; qi::rule label; qi::rule rewardModelName; - qi::rule(), Skipper> andStateFormula; - qi::rule(), Skipper> orStateFormula; - qi::rule(), Skipper> notStateFormula; - qi::rule(), Skipper> labelFormula; - qi::rule(), Skipper> expressionFormula; - qi::rule(), qi::locals, Skipper> booleanLiteralFormula; - - qi::rule(storm::logic::FormulaContext), Skipper> conditionalFormula; - qi::rule(storm::logic::FormulaContext), Skipper> eventuallyFormula; - qi::rule(storm::logic::FormulaContext), Skipper> nextFormula; - qi::rule(storm::logic::FormulaContext), Skipper> globallyFormula; - qi::rule(storm::logic::FormulaContext), Skipper> untilFormula; + qi::rule(), Skipper> andStateFormula; + qi::rule(), Skipper> orStateFormula; + qi::rule(), Skipper> notStateFormula; + qi::rule(), Skipper> labelFormula; + qi::rule(), Skipper> expressionFormula; + qi::rule(), qi::locals, Skipper> booleanLiteralFormula; + + qi::rule(storm::logic::FormulaContext), Skipper> conditionalFormula; + qi::rule(storm::logic::FormulaContext), Skipper> eventuallyFormula; + qi::rule(storm::logic::FormulaContext), Skipper> nextFormula; + qi::rule(storm::logic::FormulaContext), Skipper> globallyFormula; + qi::rule(storm::logic::FormulaContext), Skipper> untilFormula; qi::rule, uint_fast64_t>(), Skipper> timeBound; - qi::rule(), Skipper> rewardPathFormula; - qi::rule(), Skipper> cumulativeRewardFormula; - qi::rule(), Skipper> instantaneousRewardFormula; - qi::rule(), Skipper> longRunAverageRewardFormula; + qi::rule(), Skipper> rewardPathFormula; + qi::rule(), Skipper> cumulativeRewardFormula; + qi::rule(), Skipper> instantaneousRewardFormula; + qi::rule(), Skipper> longRunAverageRewardFormula; // Parser that is used to recognize doubles only (as opposed to Spirit's double_ parser). boost::spirit::qi::real_parser> strict_double; // Methods that actually create the expression objects. - std::shared_ptr createInstantaneousRewardFormula(boost::variant const& timeBound) const; - std::shared_ptr createCumulativeRewardFormula(boost::variant const& timeBound) const; - std::shared_ptr createLongRunAverageRewardFormula() const; - std::shared_ptr createAtomicExpressionFormula(storm::expressions::Expression const& expression) const; - std::shared_ptr createBooleanLiteralFormula(bool literal) const; - std::shared_ptr createAtomicLabelFormula(std::string const& label) const; - std::shared_ptr createEventuallyFormula(boost::optional, uint_fast64_t>> const& timeBound, storm::logic::FormulaContext context, std::shared_ptr const& subformula) const; - std::shared_ptr createGloballyFormula(std::shared_ptr const& subformula) const; - std::shared_ptr createNextFormula(std::shared_ptr const& subformula) const; - std::shared_ptr createUntilFormula(std::shared_ptr const& leftSubformula, boost::optional, uint_fast64_t>> const& timeBound, std::shared_ptr const& rightSubformula); - std::shared_ptr createConditionalFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::FormulaContext context) const; + std::shared_ptr createInstantaneousRewardFormula(boost::variant const& timeBound) const; + std::shared_ptr createCumulativeRewardFormula(boost::variant const& timeBound) const; + std::shared_ptr createLongRunAverageRewardFormula() const; + std::shared_ptr createAtomicExpressionFormula(storm::expressions::Expression const& expression) const; + std::shared_ptr createBooleanLiteralFormula(bool literal) const; + std::shared_ptr createAtomicLabelFormula(std::string const& label) const; + std::shared_ptr createEventuallyFormula(boost::optional, uint_fast64_t>> const& timeBound, storm::logic::FormulaContext context, std::shared_ptr const& subformula) const; + std::shared_ptr createGloballyFormula(std::shared_ptr const& subformula) const; + std::shared_ptr createNextFormula(std::shared_ptr const& subformula) const; + std::shared_ptr createUntilFormula(std::shared_ptr const& leftSubformula, boost::optional, uint_fast64_t>> const& timeBound, std::shared_ptr const& rightSubformula); + std::shared_ptr createConditionalFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::FormulaContext context) const; storm::logic::OperatorInformation createOperatorInformation(boost::optional const& optimizationDirection, boost::optional const& comparisonType, boost::optional const& threshold) const; - std::shared_ptr createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const; - std::shared_ptr createRewardOperatorFormula(boost::optional const& rewardMeasureType, boost::optional const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const; - std::shared_ptr createTimeOperatorFormula(boost::optional const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const; - std::shared_ptr createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula); - std::shared_ptr createBinaryBooleanStateFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType); - std::shared_ptr createUnaryBooleanStateFormula(std::shared_ptr const& subformula, boost::optional const& operatorType); + std::shared_ptr createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const; + std::shared_ptr createRewardOperatorFormula(boost::optional const& rewardMeasureType, boost::optional const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const; + std::shared_ptr createTimeOperatorFormula(boost::optional const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const; + std::shared_ptr createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula); + std::shared_ptr createBinaryBooleanStateFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType); + std::shared_ptr createUnaryBooleanStateFormula(std::shared_ptr const& subformula, boost::optional const& operatorType); // An error handler function. phoenix::function handler; @@ -193,18 +193,18 @@ namespace storm { return *this; } - std::shared_ptr FormulaParser::parseSingleFormulaFromString(std::string const& formulaString) const { - std::vector> formulas = parseFromString(formulaString); + std::shared_ptr FormulaParser::parseSingleFormulaFromString(std::string const& formulaString) const { + std::vector> formulas = parseFromString(formulaString); STORM_LOG_THROW(formulas.size() == 1, storm::exceptions::WrongFormatException, "Expected exactly one formula, but found " << formulas.size() << " instead."); return formulas.front(); } - std::vector> FormulaParser::parseFromFile(std::string const& filename) const { + std::vector> FormulaParser::parseFromFile(std::string const& filename) const { // Open file and initialize result. std::ifstream inputFileStream(filename, std::ios::in); STORM_LOG_THROW(inputFileStream.good(), storm::exceptions::WrongFormatException, "Unable to read from file '" << filename << "'."); - std::vector> formulas; + std::vector> formulas; // Now try to parse the contents of the file. try { @@ -221,13 +221,13 @@ namespace storm { return formulas; } - std::vector> FormulaParser::parseFromString(std::string const& formulaString) const { + std::vector> FormulaParser::parseFromString(std::string const& formulaString) const { PositionIteratorType first(formulaString.begin()); PositionIteratorType iter = first; PositionIteratorType last(formulaString.end()); // Create empty result; - std::vector> result; + std::vector> result; // Create grammar. try { @@ -399,79 +399,79 @@ namespace storm { this->identifiers_.add(identifier, expression); } - std::shared_ptr FormulaParserGrammar::createInstantaneousRewardFormula(boost::variant const& timeBound) const { + std::shared_ptr FormulaParserGrammar::createInstantaneousRewardFormula(boost::variant const& timeBound) const { if (timeBound.which() == 0) { - return std::shared_ptr(new storm::logic::InstantaneousRewardFormula(static_cast(boost::get(timeBound)))); + return std::shared_ptr(new storm::logic::InstantaneousRewardFormula(static_cast(boost::get(timeBound)))); } else { double timeBoundAsDouble = boost::get(timeBound); STORM_LOG_THROW(timeBoundAsDouble >= 0, storm::exceptions::WrongFormatException, "Cumulative reward property must have non-negative bound."); - return std::shared_ptr(new storm::logic::InstantaneousRewardFormula(static_cast(timeBoundAsDouble))); + return std::shared_ptr(new storm::logic::InstantaneousRewardFormula(static_cast(timeBoundAsDouble))); } } - std::shared_ptr FormulaParserGrammar::createCumulativeRewardFormula(boost::variant const& timeBound) const { + std::shared_ptr FormulaParserGrammar::createCumulativeRewardFormula(boost::variant const& timeBound) const { if (timeBound.which() == 0) { - return std::shared_ptr(new storm::logic::CumulativeRewardFormula(static_cast(boost::get(timeBound)))); + return std::shared_ptr(new storm::logic::CumulativeRewardFormula(static_cast(boost::get(timeBound)))); } else { double timeBoundAsDouble = boost::get(timeBound); STORM_LOG_THROW(timeBoundAsDouble >= 0, storm::exceptions::WrongFormatException, "Cumulative reward property must have non-negative bound."); - return std::shared_ptr(new storm::logic::CumulativeRewardFormula(static_cast(timeBoundAsDouble))); + return std::shared_ptr(new storm::logic::CumulativeRewardFormula(static_cast(timeBoundAsDouble))); } } - std::shared_ptr FormulaParserGrammar::createLongRunAverageRewardFormula() const { - return std::shared_ptr(new storm::logic::LongRunAverageRewardFormula()); + std::shared_ptr FormulaParserGrammar::createLongRunAverageRewardFormula() const { + return std::shared_ptr(new storm::logic::LongRunAverageRewardFormula()); } - std::shared_ptr FormulaParserGrammar::createAtomicExpressionFormula(storm::expressions::Expression const& expression) const { + std::shared_ptr FormulaParserGrammar::createAtomicExpressionFormula(storm::expressions::Expression const& expression) const { STORM_LOG_THROW(expression.hasBooleanType(), storm::exceptions::WrongFormatException, "Expected expression of boolean type."); - return std::shared_ptr(new storm::logic::AtomicExpressionFormula(expression)); + return std::shared_ptr(new storm::logic::AtomicExpressionFormula(expression)); } - std::shared_ptr FormulaParserGrammar::createBooleanLiteralFormula(bool literal) const { - return std::shared_ptr(new storm::logic::BooleanLiteralFormula(literal)); + std::shared_ptr FormulaParserGrammar::createBooleanLiteralFormula(bool literal) const { + return std::shared_ptr(new storm::logic::BooleanLiteralFormula(literal)); } - std::shared_ptr FormulaParserGrammar::createAtomicLabelFormula(std::string const& label) const { - return std::shared_ptr(new storm::logic::AtomicLabelFormula(label)); + std::shared_ptr FormulaParserGrammar::createAtomicLabelFormula(std::string const& label) const { + return std::shared_ptr(new storm::logic::AtomicLabelFormula(label)); } - std::shared_ptr FormulaParserGrammar::createEventuallyFormula(boost::optional, uint_fast64_t>> const& timeBound, storm::logic::FormulaContext context, std::shared_ptr const& subformula) const { + std::shared_ptr FormulaParserGrammar::createEventuallyFormula(boost::optional, uint_fast64_t>> const& timeBound, storm::logic::FormulaContext context, std::shared_ptr const& subformula) const { if (timeBound) { if (timeBound.get().which() == 0) { std::pair const& bounds = boost::get>(timeBound.get()); - return std::shared_ptr(new storm::logic::BoundedUntilFormula(createBooleanLiteralFormula(true), subformula, bounds.first, bounds.second)); + return std::shared_ptr(new storm::logic::BoundedUntilFormula(createBooleanLiteralFormula(true), subformula, bounds.first, bounds.second)); } else { - return std::shared_ptr(new storm::logic::BoundedUntilFormula(createBooleanLiteralFormula(true), subformula, static_cast(boost::get(timeBound.get())))); + return std::shared_ptr(new storm::logic::BoundedUntilFormula(createBooleanLiteralFormula(true), subformula, static_cast(boost::get(timeBound.get())))); } } else { - return std::shared_ptr(new storm::logic::EventuallyFormula(subformula, context)); + return std::shared_ptr(new storm::logic::EventuallyFormula(subformula, context)); } } - std::shared_ptr FormulaParserGrammar::createGloballyFormula(std::shared_ptr const& subformula) const { - return std::shared_ptr(new storm::logic::GloballyFormula(subformula)); + std::shared_ptr FormulaParserGrammar::createGloballyFormula(std::shared_ptr const& subformula) const { + return std::shared_ptr(new storm::logic::GloballyFormula(subformula)); } - std::shared_ptr FormulaParserGrammar::createNextFormula(std::shared_ptr const& subformula) const { - return std::shared_ptr(new storm::logic::NextFormula(subformula)); + std::shared_ptr FormulaParserGrammar::createNextFormula(std::shared_ptr const& subformula) const { + return std::shared_ptr(new storm::logic::NextFormula(subformula)); } - std::shared_ptr FormulaParserGrammar::createUntilFormula(std::shared_ptr const& leftSubformula, boost::optional, uint_fast64_t>> const& timeBound, std::shared_ptr const& rightSubformula) { + std::shared_ptr FormulaParserGrammar::createUntilFormula(std::shared_ptr const& leftSubformula, boost::optional, uint_fast64_t>> const& timeBound, std::shared_ptr const& rightSubformula) { if (timeBound) { if (timeBound.get().which() == 0) { std::pair const& bounds = boost::get>(timeBound.get()); - return std::shared_ptr(new storm::logic::BoundedUntilFormula(leftSubformula, rightSubformula, bounds.first, bounds.second)); + return std::shared_ptr(new storm::logic::BoundedUntilFormula(leftSubformula, rightSubformula, bounds.first, bounds.second)); } else { - return std::shared_ptr(new storm::logic::BoundedUntilFormula(leftSubformula, rightSubformula, static_cast(boost::get(timeBound.get())))); + return std::shared_ptr(new storm::logic::BoundedUntilFormula(leftSubformula, rightSubformula, static_cast(boost::get(timeBound.get())))); } } else { - return std::shared_ptr(new storm::logic::UntilFormula(leftSubformula, rightSubformula)); + return std::shared_ptr(new storm::logic::UntilFormula(leftSubformula, rightSubformula)); } } - std::shared_ptr FormulaParserGrammar::createConditionalFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::FormulaContext context) const { - return std::shared_ptr(new storm::logic::ConditionalFormula(leftSubformula, rightSubformula, context)); + std::shared_ptr FormulaParserGrammar::createConditionalFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::FormulaContext context) const { + return std::shared_ptr(new storm::logic::ConditionalFormula(leftSubformula, rightSubformula, context)); } storm::logic::OperatorInformation FormulaParserGrammar::createOperatorInformation(boost::optional const& optimizationDirection, boost::optional const& comparisonType, boost::optional const& threshold) const { @@ -482,37 +482,37 @@ namespace storm { } } - std::shared_ptr FormulaParserGrammar::createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const { - return std::shared_ptr(new storm::logic::LongRunAverageOperatorFormula(subformula, operatorInformation)); + std::shared_ptr FormulaParserGrammar::createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const { + return std::shared_ptr(new storm::logic::LongRunAverageOperatorFormula(subformula, operatorInformation)); } - std::shared_ptr FormulaParserGrammar::createRewardOperatorFormula(boost::optional const& rewardMeasureType, boost::optional const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const { + std::shared_ptr FormulaParserGrammar::createRewardOperatorFormula(boost::optional const& rewardMeasureType, boost::optional const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const { storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation; if (rewardMeasureType) { measureType = rewardMeasureType.get(); } - return std::shared_ptr(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation, measureType)); + return std::shared_ptr(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation, measureType)); } - std::shared_ptr FormulaParserGrammar::createTimeOperatorFormula(boost::optional const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const { + std::shared_ptr FormulaParserGrammar::createTimeOperatorFormula(boost::optional const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) const { storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation; if (rewardMeasureType) { measureType = rewardMeasureType.get(); } - return std::shared_ptr(new storm::logic::TimeOperatorFormula(subformula, operatorInformation, measureType)); + return std::shared_ptr(new storm::logic::TimeOperatorFormula(subformula, operatorInformation, measureType)); } - std::shared_ptr FormulaParserGrammar::createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) { - return std::shared_ptr(new storm::logic::ProbabilityOperatorFormula(subformula, operatorInformation)); + std::shared_ptr FormulaParserGrammar::createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr const& subformula) { + return std::shared_ptr(new storm::logic::ProbabilityOperatorFormula(subformula, operatorInformation)); } - std::shared_ptr FormulaParserGrammar::createBinaryBooleanStateFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType) { - return std::shared_ptr(new storm::logic::BinaryBooleanStateFormula(operatorType, leftSubformula, rightSubformula)); + std::shared_ptr FormulaParserGrammar::createBinaryBooleanStateFormula(std::shared_ptr const& leftSubformula, std::shared_ptr const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType) { + return std::shared_ptr(new storm::logic::BinaryBooleanStateFormula(operatorType, leftSubformula, rightSubformula)); } - std::shared_ptr FormulaParserGrammar::createUnaryBooleanStateFormula(std::shared_ptr const& subformula, boost::optional const& operatorType) { + std::shared_ptr FormulaParserGrammar::createUnaryBooleanStateFormula(std::shared_ptr const& subformula, boost::optional const& operatorType) { if (operatorType) { - return std::shared_ptr(new storm::logic::UnaryBooleanStateFormula(operatorType.get(), subformula)); + return std::shared_ptr(new storm::logic::UnaryBooleanStateFormula(operatorType.get(), subformula)); } else { return subformula; } diff --git a/src/parser/FormulaParser.h b/src/parser/FormulaParser.h index 68ee3c5ab..86570c4f6 100644 --- a/src/parser/FormulaParser.h +++ b/src/parser/FormulaParser.h @@ -31,7 +31,7 @@ namespace storm { * @param formulaString The formula as a string. * @return The resulting formula. */ - std::shared_ptr parseSingleFormulaFromString(std::string const& formulaString) const; + std::shared_ptr parseSingleFormulaFromString(std::string const& formulaString) const; /*! * Parses the formula given by the provided string. @@ -39,7 +39,7 @@ namespace storm { * @param formulaString The formula as a string. * @return The contained formulas. */ - std::vector> parseFromString(std::string const& formulaString) const; + std::vector> parseFromString(std::string const& formulaString) const; /*! * Parses the formulas in the given file. @@ -47,7 +47,7 @@ namespace storm { * @param filename The name of the file to parse. * @return The contained formulas. */ - std::vector> parseFromFile(std::string const& filename) const; + std::vector> parseFromFile(std::string const& filename) const; /*! * Adds an identifier and the expression it is supposed to be replaced with. This can, for example be used diff --git a/src/settings/SettingsManager.cpp b/src/settings/SettingsManager.cpp index a8ce73080..a13adb9e4 100644 --- a/src/settings/SettingsManager.cpp +++ b/src/settings/SettingsManager.cpp @@ -74,11 +74,12 @@ namespace storm { void SettingsManager::setFromString(std::string const& commandLineString) { if (commandLineString.empty()) { - return; + this->setFromExplodedString({}); + } else { + std::vector argumentVector; + boost::split(argumentVector, commandLineString, boost::is_any_of("\t ")); + this->setFromExplodedString(argumentVector); } - std::vector argumentVector; - boost::split(argumentVector, commandLineString, boost::is_any_of("\t ")); - this->setFromExplodedString(argumentVector); } void SettingsManager::setFromExplodedString(std::vector const& commandLineArguments) { @@ -554,4 +555,4 @@ namespace storm { return dynamic_cast(manager().getModule(storm::settings::modules::ExplorationSettings::moduleName)); } } -} \ No newline at end of file +} diff --git a/src/storage/ModelFormulasPair.h b/src/storage/ModelFormulasPair.h index fab8cb3d1..48af93f73 100644 --- a/src/storage/ModelFormulasPair.h +++ b/src/storage/ModelFormulasPair.h @@ -10,7 +10,7 @@ namespace storm { namespace storage { struct ModelFormulasPair { std::shared_ptr model; - std::vector> formulas; + std::vector> formulas; }; } -} \ No newline at end of file +} diff --git a/src/storage/bisimulation/BisimulationDecomposition.cpp b/src/storage/bisimulation/BisimulationDecomposition.cpp index 5c5b3e667..730480fd6 100644 --- a/src/storage/bisimulation/BisimulationDecomposition.cpp +++ b/src/storage/bisimulation/BisimulationDecomposition.cpp @@ -33,7 +33,7 @@ namespace storm { } template - BisimulationDecomposition::Options::Options(ModelType const& model, std::vector> const& formulas) : Options() { + BisimulationDecomposition::Options::Options(ModelType const& model, std::vector> const& formulas) : Options() { if (formulas.empty()) { this->respectedAtomicPropositions = model.getStateLabeling().getLabels(); this->keepRewards = true; diff --git a/src/storage/bisimulation/BisimulationDecomposition.h b/src/storage/bisimulation/BisimulationDecomposition.h index dc1c73261..2c4279f91 100644 --- a/src/storage/bisimulation/BisimulationDecomposition.h +++ b/src/storage/bisimulation/BisimulationDecomposition.h @@ -9,6 +9,7 @@ #include "src/storage/Decomposition.h" #include "src/storage/StateBlock.h" #include "src/storage/bisimulation/Partition.h" +#include "src/solver/OptimizationDirection.h" #include "src/logic/Formulas.h" @@ -79,7 +80,7 @@ namespace storm { * derive a suitable initial partition. * @param formulas The formulas that need to be preserved. */ - Options(ModelType const& model, std::vector> const& formulas); + Options(ModelType const& model, std::vector> const& formulas); /*! * Changes the options in a way that the given formula is preserved. diff --git a/src/storage/expressions/ToExprtkStringVisitor.cpp b/src/storage/expressions/ToExprtkStringVisitor.cpp index c0cea43ac..51d9c1f34 100644 --- a/src/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storage/expressions/ToExprtkStringVisitor.cpp @@ -217,4 +217,4 @@ namespace storm { return boost::any(); } } -} \ No newline at end of file +} diff --git a/src/utility/graph.h b/src/utility/graph.h index 54e541ac9..611d983bb 100644 --- a/src/utility/graph.h +++ b/src/utility/graph.h @@ -4,7 +4,7 @@ #include #include -#include "utility/OsDetection.h" +#include "src/utility/OsDetection.h" #include "src/storage/sparse/StateType.h" #include "src/storage/PartialScheduler.h" diff --git a/src/utility/storm.cpp b/src/utility/storm.cpp index a690af6f8..3f1c713b5 100644 --- a/src/utility/storm.cpp +++ b/src/utility/storm.cpp @@ -19,7 +19,7 @@ namespace storm { * @param FormulaParser * @return The formulas. */ - std::vector> parseFormulas(storm::parser::FormulaParser & formulaParser, std::string const& inputString) { + std::vector> parseFormulas(storm::parser::FormulaParser & formulaParser, std::string const& inputString) { // If the given property looks like a file (containing a dot and there exists a file with that name), // we try to parse it as a file, otherwise we assume it's a property. if (inputString.find(".") != std::string::npos && std::ifstream(inputString).good()) { @@ -29,13 +29,13 @@ namespace storm { } } - std::vector> parseFormulasForExplicit(std::string const& inputString) { + std::vector> parseFormulasForExplicit(std::string const& inputString) { storm::parser::FormulaParser formulaParser; return parseFormulas(formulaParser, inputString); } - std::vector> parseFormulasForProgram(std::string const& inputString, storm::prism::Program const& program) { + std::vector> parseFormulasForProgram(std::string const& inputString, storm::prism::Program const& program) { storm::parser::FormulaParser formulaParser(program); return parseFormulas(formulaParser, inputString); } -} \ No newline at end of file +} diff --git a/src/utility/storm.h b/src/utility/storm.h index 48020630a..4bbe5152b 100644 --- a/src/utility/storm.h +++ b/src/utility/storm.h @@ -75,6 +75,9 @@ #include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/NotImplementedException.h" +// Notice: The implementation for the template functions must stay in the header. +// Otherwise the linker complains. + namespace storm { template @@ -83,12 +86,12 @@ namespace storm { } storm::prism::Program parseProgram(std::string const& path); - std::vector> parseFormulasForExplicit(std::string const& inputString); - std::vector> parseFormulasForProgram(std::string const& inputString, storm::prism::Program const& program); + std::vector> parseFormulasForExplicit(std::string const& inputString); + std::vector> parseFormulasForProgram(std::string const& inputString, storm::prism::Program const& program); template - storm::storage::ModelFormulasPair buildSymbolicModel(storm::prism::Program const& program, std::vector> const& formulas) { + storm::storage::ModelFormulasPair buildSymbolicModel(storm::prism::Program const& program, std::vector> const& formulas) { storm::storage::ModelFormulasPair result; storm::prism::Program translatedProgram; @@ -138,8 +141,8 @@ namespace storm { } template - std::shared_ptr performDeterministicSparseBisimulationMinimization(std::shared_ptr model, std::vector> const& formulas, storm::storage::BisimulationType type) { - std::cout << "Performing bisimulation minimization... "; + std::shared_ptr performDeterministicSparseBisimulationMinimization(std::shared_ptr model, std::vector> const& formulas, storm::storage::BisimulationType type) { + STORM_LOG_INFO("Performing bisimulation minimization... "); typename storm::storage::DeterministicModelBisimulationDecomposition::Options options; if (!formulas.empty()) { options = typename storm::storage::DeterministicModelBisimulationDecomposition::Options(*model, formulas); @@ -149,13 +152,13 @@ namespace storm { storm::storage::DeterministicModelBisimulationDecomposition bisimulationDecomposition(*model, options); bisimulationDecomposition.computeBisimulationDecomposition(); model = bisimulationDecomposition.getQuotient(); - std::cout << "done." << std::endl << std::endl; + STORM_LOG_INFO("Bisimulation done. "); return model; } template - std::shared_ptr performNondeterministicSparseBisimulationMinimization(std::shared_ptr model, std::vector> const& formulas, storm::storage::BisimulationType type) { - std::cout << "Performing bisimulation minimization... "; + std::shared_ptr performNondeterministicSparseBisimulationMinimization(std::shared_ptr model, std::vector> const& formulas, storm::storage::BisimulationType type) { + STORM_LOG_INFO("Performing bisimulation minimization... "); typename storm::storage::DeterministicModelBisimulationDecomposition::Options options; if (!formulas.empty()) { options = typename storm::storage::NondeterministicModelBisimulationDecomposition::Options(*model, formulas); @@ -166,12 +169,12 @@ namespace storm { storm::storage::NondeterministicModelBisimulationDecomposition bisimulationDecomposition(*model, options); bisimulationDecomposition.computeBisimulationDecomposition(); model = bisimulationDecomposition.getQuotient(); - std::cout << "done." << std::endl << std::endl; + STORM_LOG_INFO("Bisimulation done."); return model; } template - std::shared_ptr> performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType type) { + std::shared_ptr> performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType type) { using ValueType = typename ModelType::ValueType; STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::Mdp), storm::exceptions::InvalidSettingsException, "Bisimulation minimization is currently only available for DTMCs, CTMCs and MDPs."); @@ -187,14 +190,14 @@ namespace storm { } template - std::shared_ptr> performBisimulationMinimization(std::shared_ptr> const& model, std::shared_ptr const& formula, storm::storage::BisimulationType type) { - std::vector> formulas = { formula }; + std::shared_ptr> performBisimulationMinimization(std::shared_ptr> const& model, std::shared_ptr const& formula, storm::storage::BisimulationType type) { + std::vector> formulas = { formula }; return performBisimulationMinimization(model, formulas , type); } template - std::shared_ptr preprocessModel(std::shared_ptr model, std::vector> const& formulas) { + std::shared_ptr preprocessModel(std::shared_ptr model, std::vector> const& formulas) { if (model->isSparseModel() && storm::settings::generalSettings().isBisimulationSet()) { storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong; if (storm::settings::bisimulationSettings().isWeakBisimulationSet()) { @@ -209,7 +212,7 @@ namespace storm { template - void generateCounterexample(storm::prism::Program const& program, std::shared_ptr> model, std::shared_ptr const& formula) { + void generateCounterexample(storm::prism::Program const& program, std::shared_ptr> model, std::shared_ptr const& formula) { if (storm::settings::counterexampleGeneratorSettings().isMinimalCommandSetGenerationSet()) { STORM_LOG_THROW(model->getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for MDPs."); STORM_LOG_THROW(storm::settings::generalSettings().isSymbolicSet(), storm::exceptions::InvalidSettingsException, "Minimal command set generation is only available for symbolic models."); @@ -232,13 +235,13 @@ namespace storm { #ifdef STORM_HAVE_CARL template<> - inline void generateCounterexample(storm::prism::Program const& program, std::shared_ptr> model, std::shared_ptr const& formula) { + inline void generateCounterexample(storm::prism::Program const& program, std::shared_ptr> model, std::shared_ptr const& formula) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for parametric model."); } #endif template - std::unique_ptr verifyModel(std::shared_ptr model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { + std::unique_ptr verifyModel(std::shared_ptr model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { storm::settings::modules::GeneralSettings const& settings = storm::settings::generalSettings(); switch(settings.getEngine()) { case storm::settings::modules::GeneralSettings::Engine::Sparse: { @@ -263,7 +266,7 @@ namespace storm { } template - std::unique_ptr verifySparseModel(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { + std::unique_ptr verifySparseModel(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { std::unique_ptr result; storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); @@ -330,7 +333,7 @@ namespace storm { } template<> - inline std::unique_ptr verifySparseModel(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { + inline std::unique_ptr verifySparseModel(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { std::unique_ptr result; std::shared_ptr> dtmc = model->template as>(); @@ -347,7 +350,7 @@ namespace storm { #endif template - std::unique_ptr verifySymbolicModelWithHybridEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { + std::unique_ptr verifySymbolicModelWithHybridEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { std::unique_ptr result; storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); if (model->getType() == storm::models::ModelType::Dtmc) { @@ -376,7 +379,7 @@ namespace storm { template - std::unique_ptr verifySymbolicModelWithDdEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { + std::unique_ptr verifySymbolicModelWithDdEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { std::unique_ptr result; storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); if (model->getType() == storm::models::ModelType::Dtmc) { diff --git a/stormpy/MANIFEST.in b/stormpy/MANIFEST.in new file mode 100644 index 000000000..0e6f51f28 --- /dev/null +++ b/stormpy/MANIFEST.in @@ -0,0 +1 @@ +recursive-include src *.h diff --git a/stormpy/lib/.gitignore b/stormpy/lib/.gitignore new file mode 100644 index 000000000..c70bcf8ef --- /dev/null +++ b/stormpy/lib/.gitignore @@ -0,0 +1,3 @@ +*.so +__pycache__/ +stormpy.egg-info/ diff --git a/stormpy/lib/stormpy/__init__.py b/stormpy/lib/stormpy/__init__.py new file mode 100644 index 000000000..b959014b9 --- /dev/null +++ b/stormpy/lib/stormpy/__init__.py @@ -0,0 +1,36 @@ +from . import core +from .core import * + +core.set_up("") + +def build_model(program, formulae): + intermediate = core._build_model(program, formulae) + assert not intermediate.supports_parameters() + if intermediate.model_type() == ModelType.DTMC: + return intermediate.as_dtmc() + elif intermediate.model_type() == ModelType.MDP: + return intermediate.as_mdp() + else: + raise RuntimeError("Not supported non-parametric model constructed") + +def build_parametric_model(program, formulae): + intermediate = core._build_parametric_model(program, formulae) + assert intermediate.supports_parameters() + if intermediate.model_type() == ModelType.DTMC: + return intermediate.as_pdtmc() + elif intermediate.model_type() == ModelType.MDP: + return intermediate.as_pmdp() + else: + raise RuntimeError("Not supported parametric model constructed") + +def perform_bisimulation(model, formula, bisimulation_type): + if model.supports_parameters(): + return core._perform_parametric_bisimulation(model, formula, bisimulation_type) + else: + return core._perform_bisimulation(model, formula, bisimulation_type) + +def model_checking(model, formula): + if model.supports_parameters(): + return core._parametric_model_checking(model, formula) + else: + return core._model_checking(model, formula) diff --git a/stormpy/lib/stormpy/expressions/__init__.py b/stormpy/lib/stormpy/expressions/__init__.py new file mode 100644 index 000000000..b185f368c --- /dev/null +++ b/stormpy/lib/stormpy/expressions/__init__.py @@ -0,0 +1,2 @@ +from . import expressions +from .expressions import * diff --git a/stormpy/lib/stormpy/info/__init__.py b/stormpy/lib/stormpy/info/__init__.py new file mode 100644 index 000000000..d8e3cfa68 --- /dev/null +++ b/stormpy/lib/stormpy/info/__init__.py @@ -0,0 +1,2 @@ +from . import info +from .info import * diff --git a/stormpy/lib/stormpy/logic/__init__.py b/stormpy/lib/stormpy/logic/__init__.py new file mode 100644 index 000000000..9ab762097 --- /dev/null +++ b/stormpy/lib/stormpy/logic/__init__.py @@ -0,0 +1,2 @@ +from . import logic +from .logic import * diff --git a/stormpy/resources/pybind11/.appveyor.yml b/stormpy/resources/pybind11/.appveyor.yml new file mode 100644 index 000000000..5e283af1e --- /dev/null +++ b/stormpy/resources/pybind11/.appveyor.yml @@ -0,0 +1,26 @@ +version: 1.0.{build} +os: Visual Studio 2015 +clone_folder: C:\projects\pybind11 +test: off +configuration: + - Release + - Debug +branches: + only: + - master +environment: + matrix: + - CMAKE_PLATFORM: "Visual Studio 14 2015" + PYTHON_DIR: "C:\\Python34" + - CMAKE_PLATFORM: "Visual Studio 14 2015 Win64" + PYTHON_DIR: "C:\\Python34-x64" +install: + - cinstall: python +build_script: + - echo Running cmake... + - cd c:\projects\pybind11 + - cmake -G "%CMAKE_PLATFORM%" -DPYTHON_INCLUDE_DIR:PATH=%PYTHON_DIR%/include -DPYTHON_LIBRARY:FILEPATH=%PYTHON_DIR%/libs/python34.lib -DPYTHON_EXECUTABLE:FILEPATH=%PYTHON_DIR%/python.exe + - set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - set MSBuildOptions=/v:m /p:Configuration=%Configuration% /logger:%MSBuildLogger% + - msbuild %MSBuildOptions% pybind11.sln + - ctest -C %Configuration% diff --git a/stormpy/resources/pybind11/.gitignore b/stormpy/resources/pybind11/.gitignore new file mode 100644 index 000000000..a7a49560d --- /dev/null +++ b/stormpy/resources/pybind11/.gitignore @@ -0,0 +1,31 @@ +CMakeCache.txt +CMakeFiles +Makefile +cmake_install.cmake +.DS_Store +/example/example.so +/example/example.pyd +*.sln +*.sdf +*.opensdf +*.vcxproj +*.filters +example.dir +Win32 +x64 +Release +Debug +.vs +CTestTestfile.cmake +Testing +autogen +MANIFEST +/.ninja_* +/*.ninja +/docs/.build +*.py[co] +*.egg-info +*~ +.DS_Store +/dist +/build diff --git a/stormpy/resources/pybind11/.gitmodules b/stormpy/resources/pybind11/.gitmodules new file mode 100644 index 000000000..5191885e7 --- /dev/null +++ b/stormpy/resources/pybind11/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools/clang"] + path = tools/clang + url = https://github.com/wjakob/clang-cindex-python3 diff --git a/stormpy/resources/pybind11/.travis.yml b/stormpy/resources/pybind11/.travis.yml new file mode 100644 index 000000000..9a9088fa8 --- /dev/null +++ b/stormpy/resources/pybind11/.travis.yml @@ -0,0 +1,41 @@ +language: cpp +sudo: false +cache: + directories: + - $HOME/.cache/pip +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - deadsnakes + packages: + - g++-4.8 + - g++-4.8-multilib + - g++-multilib + - python3.5 + - python3.5-dev + - python3.5-venv + - python3.5-dev:i386 +matrix: + include: + - os: linux + compiler: gcc-4.8 + script: + - pyvenv-3.5 venv + - cmake -DPYBIND11_PYTHON_VERSION=3.5 -DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.5m -DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.5m.so -DPYTHON_EXECUTABLE:FILEPATH=`pwd`/venv/bin/python3.5 -DCMAKE_CXX_COMPILER=g++-4.8 + - make -j 2 + - source venv/bin/activate + - pip install numpy + - CTEST_OUTPUT_ON_FAILURE=TRUE make test + - os: osx + compiler: clang + script: + - cmake -DPYBIND11_PYTHON_VERSION=2.7 + - make -j 2 + - CTEST_OUTPUT_ON_FAILURE=TRUE make test + #- os: linux + #compiler: gcc-4.8 + #script: + #- pyvenv-3.5 venv + #- cmake -DPYBIND11_PYTHON_VERSION=3.5 -DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.5m -DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.5m.so -DPYTHON_EXECUTABLE:FILEPATH=`pwd`/venv/bin/python3.5 -DCMAKE_CXX_COMPILER=g++-4.8 -DCMAKE_CXX_FLAGS=-m32 + #- make -j 2 diff --git a/stormpy/resources/pybind11/CMakeLists.txt b/stormpy/resources/pybind11/CMakeLists.txt new file mode 100644 index 000000000..2996e537b --- /dev/null +++ b/stormpy/resources/pybind11/CMakeLists.txt @@ -0,0 +1,220 @@ +# CMakeLists.txt -- Build system for the pybind11 examples +# +# Copyright (c) 2015 Wenzel Jakob +# +# All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +cmake_minimum_required(VERSION 2.8) + +project(pybind11) + +option(PYBIND11_INSTALL "Install pybind11 header files?" ON) + +# Add a CMake parameter for choosing a desired Python version +set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling the example application") + +include(CheckCXXCompilerFlag) + +# Set a default build configuration if none is specified. 'MinSizeRel' produces the smallest binaries +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'MinSizeRel' as none was specified.") + set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" + "MinSizeRel" "RelWithDebInfo") +endif() +string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) + +set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) +if (NOT ${PYBIND11_PYTHON_VERSION} STREQUAL "") + find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} EXACT) + if (NOT PythonLibs_FOUND) + find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} REQUIRED) + endif() +else() + find_package(PythonLibs REQUIRED) +endif() +# The above sometimes returns version numbers like "3.4.3+"; the "+" must be removed for the next line to work +string(REPLACE "+" "" PYTHONLIBS_VERSION_STRING "+${PYTHONLIBS_VERSION_STRING}") +find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED) + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") + CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG) + CHECK_CXX_COMPILER_FLAG("-std=c++11" HAS_CPP11_FLAG) + + if (HAS_CPP14_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") + elseif (HAS_CPP11_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + else() + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + endif() + + # Enable link time optimization and set the default symbol + # visibility to hidden (very important to obtain small binaries) + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + # Default symbol visibility + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") + + # Check for Link Time Optimization support + # (GCC/Clang) + CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) + if (HAS_LTO_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") + endif() + + # Intel equivalent to LTO is called IPO + if (CMAKE_CXX_COMPILER_ID MATCHES "Intel") + CHECK_CXX_COMPILER_FLAG("-ipo" HAS_IPO_FLAG) + if (HAS_IPO_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") + endif() + endif() + endif() +endif() + +# Compile with compiler warnings turned on +if(MSVC) + if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") + string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") + endif() +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") +endif() + +# Include path for Python header files +include_directories(${PYTHON_INCLUDE_DIR}) + +# Include path for pybind11 header files +include_directories(include) + +set(PYBIND11_HEADERS + include/pybind11/attr.h + include/pybind11/cast.h + include/pybind11/common.h + include/pybind11/complex.h + include/pybind11/descr.h + include/pybind11/functional.h + include/pybind11/numpy.h + include/pybind11/operators.h + include/pybind11/pybind11.h + include/pybind11/pytypes.h + include/pybind11/stl.h + include/pybind11/typeid.h +) + +set(PYBIND11_EXAMPLES + example/example1.cpp + example/example2.cpp + example/example3.cpp + example/example4.cpp + example/example5.cpp + example/example6.cpp + example/example7.cpp + example/example8.cpp + example/example9.cpp + example/example10.cpp + example/example11.cpp + example/example12.cpp + example/example13.cpp + example/example14.cpp + example/example15.cpp + example/example16.cpp + example/issues.cpp +) + +# Create the binding library +add_library(example SHARED + ${PYBIND11_HEADERS} + example/example.cpp + ${PYBIND11_EXAMPLES} +) + +# Don't add a 'lib' prefix to the shared library +set_target_properties(example PROPERTIES PREFIX "") + +# Always write the output file directly into the 'example' directory (even on MSVC) +set(CompilerFlags + LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_DIRECTORY_DEBUG + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO + RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_DIRECTORY_DEBUG + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO) + +foreach(CompilerFlag ${CompilerFlags}) + set_target_properties(example PROPERTIES ${CompilerFlag} ${PROJECT_SOURCE_DIR}/example) +endforeach() + +if (WIN32) + if (MSVC) + # /bigobj is needed for bigger binding projects due to the limit to 64k + # addressable sections. /MP enables multithreaded builds (relevant when + # there are many files). + set_target_properties(example PROPERTIES COMPILE_FLAGS "/MP /bigobj ") + + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + # Enforce size-based optimization and link time code generation on MSVC + # (~30% smaller binaries in experiments). + set_target_properties(example APPEND_STRING PROPERTY COMPILE_FLAGS "/Os /GL ") + set_target_properties(example APPEND_STRING PROPERTY LINK_FLAGS "/LTCG ") + endif() + endif() + + # .PYD file extension on Windows + set_target_properties(example PROPERTIES SUFFIX ".pyd") + + # Link against the Python shared library + target_link_libraries(example ${PYTHON_LIBRARY}) +elseif (UNIX) + # It's quite common to have multiple copies of the same Python version + # installed on one's system. E.g.: one copy from the OS and another copy + # that's statically linked into an application like Blender or Maya. + # If we link our plugin library against the OS Python here and import it + # into Blender or Maya later on, this will cause segfaults when multiple + # conflicting Python instances are active at the same time (even when they + # are of the same version). + + # Windows is not affected by this issue since it handles DLL imports + # differently. The solution for Linux and Mac OS is simple: we just don't + # link against the Python library. The resulting shared library will have + # missing symbols, but that's perfectly fine -- they will be resolved at + # import time. + + # .SO file extension on Linux/Mac OS + set_target_properties(example PROPERTIES SUFFIX ".so") + + # Optimize for a small binary size + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + set_target_properties(example PROPERTIES COMPILE_FLAGS "-Os") + endif() + + # Strip unnecessary sections of the binary on Linux/Mac OS + if(APPLE) + set_target_properties(example PROPERTIES MACOSX_RPATH ".") + set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ") + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example.so) + endif() + else() + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + add_custom_command(TARGET example POST_BUILD COMMAND strip ${PROJECT_SOURCE_DIR}/example/example.so) + endif() + endif() +endif() + +enable_testing() + +set(RUN_TEST ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/run_test.py) +if (MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") + set(RUN_TEST ${RUN_TEST} --relaxed) +endif() + +foreach(VALUE ${PYBIND11_EXAMPLES}) + string(REGEX REPLACE "^example/(.+).cpp$" "\\1" EXAMPLE_NAME "${VALUE}") + add_test(NAME ${EXAMPLE_NAME} COMMAND ${RUN_TEST} ${EXAMPLE_NAME}) +endforeach() + +if (PYBIND11_INSTALL) + install(FILES ${PYBIND11_HEADERS} DESTINATION include/pybind11) +endif() diff --git a/stormpy/resources/pybind11/CONTRIBUTING.md b/stormpy/resources/pybind11/CONTRIBUTING.md new file mode 100644 index 000000000..d700c4ae7 --- /dev/null +++ b/stormpy/resources/pybind11/CONTRIBUTING.md @@ -0,0 +1,37 @@ +Thank you for your interest in this project! Please refer to the following +sections on how to contribute code and bug reports. + +### Reporting bugs + +At the moment, this project is run in the spare time of a single person +([Wenzel Jakob](http://rgl.epfl.ch/people/wjakob)) with very limited resources +for issue tracker tickets. Thus, before submitting a question or bug report, +please take a moment of your time and ensure that your issue isn't already +discussed in the project documentation provided at +[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest). + +Assuming that you have identified a previously unknown problem or an important +question, it's essential that you submit a self-contained and minimal piece of +code that reproduces the problem. In other words: no external dependencies, +isolate the function(s) that cause breakage, submit matched and complete C++ +and Python snippets that can be easily compiled and run on my end. + +## Pull requests +Contributions are submitted, reviewed, and accepted using Github pull requests. +Please refer to [this +article](https://help.github.com/articles/using-pull-requests) for details and +adhere to the following rules to make the process as smooth as possible: + +* Make a new branch for every feature you're working on. +* Make small and clean pull requests that are easy to review but make sure they + do add value by themselves. +* Add tests for any new functionality and run the test suite (``make test``) to + ensure that no existing features break. +* This project has a strong focus on providing general solutions using a + minimal amount of code, thus small pull requests are greatly preferred. + +### License + +pybind11 is provided under a BSD-style license that can be found in the +``LICENSE`` file. By using, distributing, or contributing to this project, you +agree to the terms and conditions of this license. diff --git a/stormpy/resources/pybind11/LICENSE b/stormpy/resources/pybind11/LICENSE new file mode 100644 index 000000000..d134ff5bc --- /dev/null +++ b/stormpy/resources/pybind11/LICENSE @@ -0,0 +1,36 @@ +Copyright (c) 2015 Wenzel Jakob , All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to the author of this software, without +imposing a separate written license agreement for such Enhancements, then you +hereby grant the following license: a non-exclusive, royalty-free perpetual +license to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such enhancements or +derivative works thereof, in binary and source code form. diff --git a/stormpy/resources/pybind11/MANIFEST.in b/stormpy/resources/pybind11/MANIFEST.in new file mode 100644 index 000000000..33c22c84c --- /dev/null +++ b/stormpy/resources/pybind11/MANIFEST.in @@ -0,0 +1 @@ +include include/pybind11/*.h diff --git a/stormpy/resources/pybind11/README.md b/stormpy/resources/pybind11/README.md new file mode 100644 index 000000000..baefb2baf --- /dev/null +++ b/stormpy/resources/pybind11/README.md @@ -0,0 +1,108 @@ +![pybind11 logo](https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png) + +# pybind11 — Seamless operability between C++11 and Python + +[![Documentation Status](https://readthedocs.org/projects/pybind11/badge/?version=latest)](http://pybind11.readthedocs.org/en/latest/?badge=latest) +[![Build Status](https://travis-ci.org/pybind/pybind11.svg?branch=master)](https://travis-ci.org/pybind/pybind11) +[![Build status](https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true)](https://ci.appveyor.com/project/wjakob/pybind11) + +**pybind11** is a lightweight header-only library that exposes C++ types in Python +and vice versa, mainly to create Python bindings of existing C++ code. Its +goals and syntax are similar to the excellent +[Boost.Python](http://www.boost.org/doc/libs/1_58_0/libs/python/doc/) library +by David Abrahams: to minimize boilerplate code in traditional extension +modules by inferring type information using compile-time introspection. + +The main issue with Boost.Python—and the reason for creating such a similar +project—is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~2.5K lines of code and depend on +Python (2.7 or 3.x) and the C++ standard library. This compact implementation +was possible thanks to some of the new C++11 language features (specifically: +tuples, lambda functions and variadic templates). Since its creation, this +library has grown beyond Boost.Python in many ways, leading to dramatically +simpler binding code in many common situations. + +Tutorial and reference documentation is provided at +[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest). + +## Core features +pybind11 can map the following core C++ features to Python + +- Functions accepting and returning custom data structures per value, reference, or pointer +- Instance methods and static methods +- Overloaded functions +- Instance attributes and static attributes +- Exceptions +- Enumerations +- Callbacks +- Custom operators +- STL data structures +- Iterators and ranges +- Smart pointers with reference counting like `std::shared_ptr` +- Internal references with correct reference counting +- C++ classes with virtual (and pure virtual) methods can be extended in Python + +## Goodies +In addition to the core functionality, pybind11 provides some extra goodies: + +- pybind11 uses C++11 move constructors and move assignment operators whenever + possible to efficiently transfer custom data types. + +- It is possible to bind C++11 lambda functions with captured variables. The + lambda capture data is stored inside the resulting Python function object. + +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between + C++ matrix classes like Eigen and NumPy without expensive copy operations. + +- pybind11 can automatically vectorize functions so that they are transparently + applied to all entries of one or more NumPy array arguments. + +- Python's slice-based access and assignment operations can be supported with + just a few lines of code. + +- Everything is contained in just a few header files; there is no need to link + against any additional libraries. + +- Binaries are generally smaller by a factor of 2 or more compared to + equivalent bindings generated by Boost.Python. + +- When supported by the compiler, two new C++14 features (relaxed constexpr and + return value deduction) are used to precompute function signatures at compile + time, leading to smaller binaries. + +- With little extra effort, C++ types can be pickled and unpickled similar to + regular Python objects. + +## Supported compilers + +1. Clang/LLVM (any non-ancient version with C++11 support) +2. GCC (any non-ancient version with C++11 support) +3. Microsoft Visual Studio 2015 or newer +4. Intel C++ compiler v15 or newer + +## About + +This project was created by [Wenzel Jakob](https://www.mitsuba-renderer.org/~wenzel/). +Significant features and/or improvements to the code were contributed by +Jonas Adler, +Sylvain Corlay, +Axel Huebl, +@hulucc, +Johan Mabille, +Tomasz MiÄ…sko, and +Ben Pritchard. + +### License + +pybind11 is provided under a BSD-style license that can be found in the +``LICENSE`` file. By using, distributing, or contributing to this project, +you agree to the terms and conditions of this license. diff --git a/stormpy/resources/pybind11/conda.recipe/bld.bat b/stormpy/resources/pybind11/conda.recipe/bld.bat new file mode 100644 index 000000000..b9cd616ce --- /dev/null +++ b/stormpy/resources/pybind11/conda.recipe/bld.bat @@ -0,0 +1,2 @@ +"%PYTHON%" setup.py install --single-version-externally-managed --record=record.txt +if errorlevel 1 exit 1 diff --git a/stormpy/resources/pybind11/conda.recipe/build.sh b/stormpy/resources/pybind11/conda.recipe/build.sh new file mode 100644 index 000000000..175d6f16e --- /dev/null +++ b/stormpy/resources/pybind11/conda.recipe/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash +${PYTHON} setup.py install --single-version-externally-managed --record=record.txt; + diff --git a/stormpy/resources/pybind11/conda.recipe/meta.yaml b/stormpy/resources/pybind11/conda.recipe/meta.yaml new file mode 100644 index 000000000..fbbb830b7 --- /dev/null +++ b/stormpy/resources/pybind11/conda.recipe/meta.yaml @@ -0,0 +1,26 @@ +package: + name: pybind11 + version: {{ environ.get('GIT_DESCRIBE_TAG', '').replace('v', '') }} + +build: + number: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} + {% if environ.get('GIT_DESCRIBE_NUMBER', '0') == '0' %}string: py{{ environ.get('PY_VER').replace('.', '') }}_0 + {% else %}string: py{{ environ.get('PY_VER').replace('.', '') }}_{{ environ.get('GIT_BUILD_STR', 'GIT_STUB') }}{% endif %} + +source: + git_url: ../ + +requirements: + build: + - python + + run: + - python + +test: + imports: + - pybind11 + +about: + home: https://github.com/pybind/pybind11/ + summary: Seamless operability between C++11 and Python diff --git a/stormpy/resources/pybind11/docs/_static/theme_overrides.css b/stormpy/resources/pybind11/docs/_static/theme_overrides.css new file mode 100644 index 000000000..f678ab548 --- /dev/null +++ b/stormpy/resources/pybind11/docs/_static/theme_overrides.css @@ -0,0 +1,7 @@ +.wy-table-responsive table td, +.wy-table-responsive table th { + white-space: initial !important; +} +.rst-content table.docutils td { + vertical-align: top !important; +} diff --git a/stormpy/resources/pybind11/docs/advanced.rst b/stormpy/resources/pybind11/docs/advanced.rst new file mode 100644 index 000000000..9df5cb3fe --- /dev/null +++ b/stormpy/resources/pybind11/docs/advanced.rst @@ -0,0 +1,1299 @@ +.. _advanced: + +Advanced topics +############### + +For brevity, the rest of this chapter assumes that the following two lines are +present: + +.. code-block:: cpp + + #include + + namespace py = pybind11; + +Exporting constants and mutable objects +======================================= + +To expose a C++ constant, use the ``attr`` function to register it in a module +as shown below. The ``int_`` class is one of many small wrapper objects defined +in ``pybind11/pytypes.h``. General objects (including integers) can also be +converted using the function ``cast``. + +.. code-block:: cpp + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + m.attr("MY_CONSTANT") = py::int_(123); + m.attr("MY_CONSTANT_2") = py::cast(new MyObject()); + } + +Operator overloading +==================== + +Suppose that we're given the following ``Vector2`` class with a vector addition +and scalar multiplication operation, all implemented using overloaded operators +in C++. + +.. code-block:: cpp + + class Vector2 { + public: + Vector2(float x, float y) : x(x), y(y) { } + + std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } + + Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } + Vector2 operator*(float value) const { return Vector2(x * value, y * value); } + Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } + Vector2& operator*=(float v) { x *= v; y *= v; return *this; } + + friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } + + private: + float x, y; + }; + +The following snippet shows how the above operators can be conveniently exposed +to Python. + +.. code-block:: cpp + + #include + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_(m, "Vector2") + .def(py::init()) + .def(py::self + py::self) + .def(py::self += py::self) + .def(py::self *= float()) + .def(float() * py::self) + .def("__repr__", &Vector2::toString); + + return m.ptr(); + } + +Note that a line like + +.. code-block:: cpp + + .def(py::self * float()) + +is really just short hand notation for + +.. code-block:: cpp + + .def("__mul__", [](const Vector2 &a, float b) { + return a * b; + }) + +This can be useful for exposing additional operators that don't exist on the +C++ side, or to perform other types of customization. + +.. note:: + + To use the more convenient ``py::self`` notation, the additional + header file :file:`pybind11/operators.h` must be included. + +.. seealso:: + + The file :file:`example/example3.cpp` contains a complete example that + demonstrates how to work with overloaded operators in more detail. + +Callbacks and passing anonymous functions +========================================= + +The C++11 standard brought lambda functions and the generic polymorphic +function wrapper ``std::function<>`` to the C++ programming language, which +enable powerful new ways of working with functions. Lambda functions come in +two flavors: stateless lambda function resemble classic function pointers that +link to an anonymous piece of code, while stateful lambda functions +additionally depend on captured variables that are stored in an anonymous +*lambda closure object*. + +Here is a simple example of a C++ function that takes an arbitrary function +(stateful or stateless) with signature ``int -> int`` as an argument and runs +it with the value 10. + +.. code-block:: cpp + + int func_arg(const std::function &f) { + return f(10); + } + +The example below is more involved: it takes a function of signature ``int -> int`` +and returns another function of the same kind. The return value is a stateful +lambda function, which stores the value ``f`` in the capture object and adds 1 to +its return value upon execution. + +.. code-block:: cpp + + std::function func_ret(const std::function &f) { + return [f](int i) { + return f(i) + 1; + }; + } + +After including the extra header file :file:`pybind11/functional.h`, it is almost +trivial to generate binding code for both of these functions. + +.. code-block:: cpp + + #include + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + m.def("func_arg", &func_arg); + m.def("func_ret", &func_ret); + + return m.ptr(); + } + +The following interactive session shows how to call them from Python. + +.. code-block:: python + + $ python + >>> import example + >>> def square(i): + ... return i * i + ... + >>> example.func_arg(square) + 100L + >>> square_plus_1 = example.func_ret(square) + >>> square_plus_1(4) + 17L + >>> + +.. note:: + + This functionality is very useful when generating bindings for callbacks in + C++ libraries (e.g. a graphical user interface library). + + The file :file:`example/example5.cpp` contains a complete example that + demonstrates how to work with callbacks and anonymous functions in more detail. + +.. warning:: + + Keep in mind that passing a function from C++ to Python (or vice versa) + will instantiate a piece of wrapper code that translates function + invocations between the two languages. Copying the same function back and + forth between Python and C++ many times in a row will cause these wrappers + to accumulate, which can decrease performance. + +Overriding virtual functions in Python +====================================== + +Suppose that a C++ class or interface has a virtual function that we'd like to +to override from within Python (we'll focus on the class ``Animal``; ``Dog`` is +given as a specific example of how one would do this with traditional C++ +code). + +.. code-block:: cpp + + class Animal { + public: + virtual ~Animal() { } + virtual std::string go(int n_times) = 0; + }; + + class Dog : public Animal { + public: + std::string go(int n_times) { + std::string result; + for (int i=0; igo(3); + } + +Normally, the binding code for these classes would look as follows: + +.. code-block:: cpp + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_ animal(m, "Animal"); + animal + .def("go", &Animal::go); + + py::class_(m, "Dog", animal) + .def(py::init<>()); + + m.def("call_go", &call_go); + + return m.ptr(); + } + +However, these bindings are impossible to extend: ``Animal`` is not +constructible, and we clearly require some kind of "trampoline" that +redirects virtual calls back to Python. + +Defining a new type of ``Animal`` from within Python is possible but requires a +helper class that is defined as follows: + +.. code-block:: cpp + + class PyAnimal : public Animal { + public: + /* Inherit the constructors */ + using Animal::Animal; + + /* Trampoline (need one for each virtual function) */ + std::string go(int n_times) { + PYBIND11_OVERLOAD_PURE( + std::string, /* Return type */ + Animal, /* Parent class */ + go, /* Name of function */ + n_times /* Argument(s) */ + ); + } + }; + +The macro :func:`PYBIND11_OVERLOAD_PURE` should be used for pure virtual +functions, and :func:`PYBIND11_OVERLOAD` should be used for functions which have +a default implementation. The binding code also needs a few minor adaptations +(highlighted): + +.. code-block:: cpp + :emphasize-lines: 4,6,7 + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_ animal(m, "Animal"); + animal + .alias() + .def(py::init<>()) + .def("go", &Animal::go); + + py::class_(m, "Dog", animal) + .def(py::init<>()); + + m.def("call_go", &call_go); + + return m.ptr(); + } + +Importantly, the trampoline helper class is used as the template argument to +:class:`class_`, and a call to :func:`class_::alias` informs the binding +generator that this is merely an alias for the underlying type ``Animal``. +Following this, we are able to define a constructor as usual. + +The Python session below shows how to override ``Animal::go`` and invoke it via +a virtual method call. + +.. code-block:: python + + >>> from example import * + >>> d = Dog() + >>> call_go(d) + u'woof! woof! woof! ' + >>> class Cat(Animal): + ... def go(self, n_times): + ... return "meow! " * n_times + ... + >>> c = Cat() + >>> call_go(c) + u'meow! meow! meow! ' + +.. seealso:: + + The file :file:`example/example12.cpp` contains a complete example that + demonstrates how to override virtual functions using pybind11 in more + detail. + + +Global Interpreter Lock (GIL) +============================= + +The classes :class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be +used to acquire and release the global interpreter lock in the body of a C++ +function call. In this way, long-running C++ code can be parallelized using +multiple Python threads. Taking the previous section as an example, this could +be realized as follows (important changes highlighted): + +.. code-block:: cpp + :emphasize-lines: 8,9,33,34 + + class PyAnimal : public Animal { + public: + /* Inherit the constructors */ + using Animal::Animal; + + /* Trampoline (need one for each virtual function) */ + std::string go(int n_times) { + /* Acquire GIL before calling Python code */ + py::gil_scoped_acquire acquire; + + PYBIND11_OVERLOAD_PURE( + std::string, /* Return type */ + Animal, /* Parent class */ + go, /* Name of function */ + n_times /* Argument(s) */ + ); + } + }; + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_ animal(m, "Animal"); + animal + .alias() + .def(py::init<>()) + .def("go", &Animal::go); + + py::class_(m, "Dog", animal) + .def(py::init<>()); + + m.def("call_go", [](Animal *animal) -> std::string { + /* Release GIL before calling into (potentially long-running) C++ code */ + py::gil_scoped_release release; + return call_go(animal); + }); + + return m.ptr(); + } + +Passing STL data structures +=========================== + +When including the additional header file :file:`pybind11/stl.h`, conversions +between ``std::vector<>``, ``std::list<>``, ``std::set<>``, and ``std::map<>`` +and the Python ``list``, ``set`` and ``dict`` data structures are automatically +enabled. The types ``std::pair<>`` and ``std::tuple<>`` are already supported +out of the box with just the core :file:`pybind11/pybind11.h` header. + +.. note:: + + Arbitrary nesting of any of these types is supported. + +.. seealso:: + + The file :file:`example/example2.cpp` contains a complete example that + demonstrates how to pass STL data types in more detail. + +Binding sequence data types, iterators, the slicing protocol, etc. +================================================================== + +Please refer to the supplemental example for details. + +.. seealso:: + + The file :file:`example/example6.cpp` contains a complete example that + shows how to bind a sequence data type, including length queries + (``__len__``), iterators (``__iter__``), the slicing protocol and other + kinds of useful operations. + +Return value policies +===================== + +Python and C++ use wildly different ways of managing the memory and lifetime of +objects managed by them. This can lead to issues when creating bindings for +functions that return a non-trivial type. Just by looking at the type +information, it is not clear whether Python should take charge of the returned +value and eventually free its resources, or if this is handled on the C++ side. +For this reason, pybind11 provides a several `return value policy` annotations +that can be passed to the :func:`module::def` and :func:`class_::def` +functions. The default policy is :enum:`return_value_policy::automatic`. + + ++--------------------------------------------------+---------------------------------------------------------------------------+ +| Return value policy | Description | ++==================================================+===========================================================================+ +| :enum:`return_value_policy::automatic` | Automatic: copy objects returned as values and take ownership of | +| | objects returned as pointers | ++--------------------------------------------------+---------------------------------------------------------------------------+ +| :enum:`return_value_policy::automatic_reference` | Automatic variant 2 : copy objects returned as values and reference | +| | objects returned as pointers | ++--------------------------------------------------+---------------------------------------------------------------------------+ +| :enum:`return_value_policy::copy` | Create a new copy of the returned object, which will be owned by Python | ++--------------------------------------------------+---------------------------------------------------------------------------+ +| :enum:`return_value_policy::take_ownership` | Reference the existing object and take ownership. Python will call | +| | the destructor and delete operator when the reference count reaches zero | ++--------------------------------------------------+---------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference` | Reference the object, but do not take ownership and defer responsibility | +| | for deleting it to C++ (dangerous when C++ code at some point decides to | +| | delete it while Python still has a nonzero reference count) | ++--------------------------------------------------+---------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference_internal` | Reference the object, but do not take ownership. The object is considered | +| | be owned by the C++ instance whose method or property returned it. The | +| | Python object will increase the reference count of this 'parent' by 1 | +| | to ensure that it won't be deallocated while Python is using the 'child' | ++--------------------------------------------------+---------------------------------------------------------------------------+ + +.. warning:: + + Code with invalid call policies might access unitialized memory and free + data structures multiple times, which can lead to hard-to-debug + non-determinism and segmentation faults, hence it is worth spending the + time to understand all the different options above. + +See below for an example that uses the +:enum:`return_value_policy::reference_internal` policy. + +.. code-block:: cpp + + class Example { + public: + Internal &get_internal() { return internal; } + private: + Internal internal; + }; + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_(m, "Example") + .def(py::init<>()) + .def("get_internal", &Example::get_internal, "Return the internal data", py::return_value_policy::reference_internal); + + return m.ptr(); + } + + +Additional call policies +======================== + +In addition to the above return value policies, further `call policies` can be +specified to indicate dependencies between parameters. There is currently just +one policy named ``keep_alive``, which indicates that the +argument with index ``Patient`` should be kept alive at least until the +argument with index ``Nurse`` is freed by the garbage collector; argument +indices start at one, while zero refers to the return value. Arbitrarily many +call policies can be specified. + +For instance, binding code for a a list append operation that ties the lifetime +of the newly added element to the underlying container might be declared as +follows: + +.. code-block:: cpp + + py::class_(m, "List") + .def("append", &List::append, py::keep_alive<1, 2>()); + +.. note:: + + ``keep_alive`` is analogous to the ``with_custodian_and_ward`` (if Nurse, + Patient != 0) and ``with_custodian_and_ward_postcall`` (if Nurse/Patient == + 0) policies from Boost.Python. + +.. seealso:: + + The file :file:`example/example13.cpp` contains a complete example that + demonstrates using :class:`keep_alive` in more detail. + +Implicit type conversions +========================= + +Suppose that instances of two types ``A`` and ``B`` are used in a project, and +that an ``A`` can easily be converted into a an instance of type ``B`` (examples of this +could be a fixed and an arbitrary precision number type). + +.. code-block:: cpp + + py::class_(m, "A") + /// ... members ... + + py::class_(m, "B") + .def(py::init()) + /// ... members ... + + m.def("func", + [](const B &) { /* .... */ } + ); + +To invoke the function ``func`` using a variable ``a`` containing an ``A`` +instance, we'd have to write ``func(B(a))`` in Python. On the other hand, C++ +will automatically apply an implicit type conversion, which makes it possible +to directly write ``func(a)``. + +In this situation (i.e. where ``B`` has a constructor that converts from +``A``), the following statement enables similar implicit conversions on the +Python side: + +.. code-block:: cpp + + py::implicitly_convertible(); + +Unique pointers +=============== + +Given a class ``Example`` with Python bindings, it's possible to return +instances wrapped in C++11 unique pointers, like so + +.. code-block:: cpp + + std::unique_ptr create_example() { return std::unique_ptr(new Example()); } + +.. code-block:: cpp + + m.def("create_example", &create_example); + +In other words, there is nothing special that needs to be done. While returning +unique pointers in this way is allowed, it is *illegal* to use them as function +arguments. For instance, the following function signature cannot be processed +by pybind11. + +.. code-block:: cpp + + void do_something_with_example(std::unique_ptr ex) { ... } + +The above signature would imply that Python needs to give up ownership of an +object that is passed to this function, which is generally not possible (for +instance, the object might be referenced elsewhere). + +Smart pointers +============== + +This section explains how to pass values that are wrapped in "smart" pointer +types with internal reference counting. For simpler C++11 unique pointers, +please refer to the previous section. + +The binding generator for classes (:class:`class_`) takes an optional second +template type, which denotes a special *holder* type that is used to manage +references to the object. When wrapping a type named ``Type``, the default +value of this template parameter is ``std::unique_ptr``, which means that +the object is deallocated when Python's reference count goes to zero. + +It is possible to switch to other types of reference counting wrappers or smart +pointers, which is useful in codebases that rely on them. For instance, the +following snippet causes ``std::shared_ptr`` to be used instead. + +.. code-block:: cpp + + py::class_ /* <- holder type */> obj(m, "Example"); + +Note that any particular class can only be associated with a single holder type. + +To enable transparent conversions for functions that take shared pointers as an +argument or that return them, a macro invocation similar to the following must +be declared at the top level before any binding code: + +.. code-block:: cpp + + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); + +.. note:: + + The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a + placeholder name that is used as a template parameter of the second + argument. Thus, feel free to use any identifier, but use it consistently on + both sides; also, don't use the name of a type that already exists in your + codebase. + +One potential stumbling block when using holder types is that they need to be +applied consistently. Can you guess what's broken about the following binding +code? + +.. code-block:: cpp + + class Child { }; + + class Parent { + public: + Parent() : child(std::make_shared()) { } + Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */ + private: + std::shared_ptr child; + }; + + PYBIND11_PLUGIN(example) { + py::module m("example"); + + py::class_>(m, "Child"); + + py::class_>(m, "Parent") + .def(py::init<>()) + .def("get_child", &Parent::get_child); + + return m.ptr(); + } + +The following Python code will cause undefined behavior (and likely a +segmentation fault). + +.. code-block:: python + + from example import Parent + print(Parent().get_child()) + +The problem is that ``Parent::get_child()`` returns a pointer to an instance of +``Child``, but the fact that this instance is already managed by +``std::shared_ptr<...>`` is lost when passing raw pointers. In this case, +pybind11 will create a second independent ``std::shared_ptr<...>`` that also +claims ownership of the pointer. In the end, the object will be freed **twice** +since these shared pointers have no way of knowing about each other. + +There are two ways to resolve this issue: + +1. For types that are managed by a smart pointer class, never use raw pointers + in function arguments or return values. In other words: always consistently + wrap pointers into their designated holder types (such as + ``std::shared_ptr<...>``). In this case, the signature of ``get_child()`` + should be modified as follows: + +.. code-block:: cpp + + std::shared_ptr get_child() { return child; } + +2. Adjust the definition of ``Child`` by specifying + ``std::enable_shared_from_this`` (see cppreference_ for details) as a + base class. This adds a small bit of information to ``Child`` that allows + pybind11 to realize that there is already an existing + ``std::shared_ptr<...>`` and communicate with it. In this case, the + declaration of ``Child`` should look as follows: + +.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this + +.. code-block:: cpp + + class Child : public std::enable_shared_from_this { }; + +.. seealso:: + + The file :file:`example/example8.cpp` contains a complete example that + demonstrates how to work with custom reference-counting holder types in + more detail. + +.. _custom_constructors: + +Custom constructors +=================== + +The syntax for binding constructors was previously introduced, but it only +works when a constructor with the given parameters actually exists on the C++ +side. To extend this to more general cases, let's take a look at what actually +happens under the hood: the following statement + +.. code-block:: cpp + + py::class_(m, "Example") + .def(py::init()); + +is short hand notation for + +.. code-block:: cpp + + py::class_(m, "Example") + .def("__init__", + [](Example &instance, int arg) { + new (&instance) Example(arg); + } + ); + +In other words, :func:`init` creates an anonymous function that invokes an +in-place constructor. Memory allocation etc. is already take care of beforehand +within pybind11. + +Catching and throwing exceptions +================================ + +When C++ code invoked from Python throws an ``std::exception``, it is +automatically converted into a Python ``Exception``. pybind11 defines multiple +special exception classes that will map to different types of Python +exceptions: + ++--------------------------------------+------------------------------+ +| C++ exception type | Python exception type | ++======================================+==============================+ +| :class:`std::exception` | ``RuntimeError`` | ++--------------------------------------+------------------------------+ +| :class:`std::bad_alloc` | ``MemoryError`` | ++--------------------------------------+------------------------------+ +| :class:`std::domain_error` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::invalid_argument` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::length_error` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::out_of_range` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::range_error` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`pybind11::stop_iteration` | ``StopIteration`` (used to | +| | implement custom iterators) | ++--------------------------------------+------------------------------+ +| :class:`pybind11::index_error` | ``IndexError`` (used to | +| | indicate out of bounds | +| | accesses in ``__getitem__``, | +| | ``__setitem__``, etc.) | ++--------------------------------------+------------------------------+ +| :class:`pybind11::error_already_set` | Indicates that the Python | +| | exception flag has already | +| | been initialized | ++--------------------------------------+------------------------------+ + +When a Python function invoked from C++ throws an exception, it is converted +into a C++ exception of type :class:`error_already_set` whose string payload +contains a textual summary. + +There is also a special exception :class:`cast_error` that is thrown by +:func:`handle::call` when the input arguments cannot be converted to Python +objects. + +Buffer protocol +=============== + +Python supports an extremely general and convenient approach for exchanging +data between plugin libraries. Types can expose a buffer view [#f1]_, +which provides fast direct access to the raw internal representation. Suppose +we want to bind the following simplistic Matrix class: + +.. code-block:: cpp + + class Matrix { + public: + Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) { + m_data = new float[rows*cols]; + } + float *data() { return m_data; } + size_t rows() const { return m_rows; } + size_t cols() const { return m_cols; } + private: + size_t m_rows, m_cols; + float *m_data; + }; + +The following binding code exposes the ``Matrix`` contents as a buffer object, +making it possible to cast Matrixes into NumPy arrays. It is even possible to +completely avoid copy operations with Python expressions like +``np.array(matrix_instance, copy = False)``. + +.. code-block:: cpp + + py::class_(m, "Matrix") + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor::value(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }); + +The snippet above binds a lambda function, which can create ``py::buffer_info`` +description records on demand describing a given matrix. The contents of +``py::buffer_info`` mirror the Python buffer protocol specification. + +.. code-block:: cpp + + struct buffer_info { + void *ptr; + size_t itemsize; + std::string format; + int ndim; + std::vector shape; + std::vector strides; + }; + +To create a C++ function that can take a Python buffer object as an argument, +simply use the type ``py::buffer`` as one of its arguments. Buffers can exist +in a great variety of configurations, hence some safety checks are usually +necessary in the function body. Below, you can see an basic example on how to +define a custom constructor for the Eigen double precision matrix +(``Eigen::MatrixXd``) type, which supports initialization from compatible +buffer +objects (e.g. a NumPy matrix). + +.. code-block:: cpp + + py::class_(m, "MatrixXd") + .def("__init__", [](Eigen::MatrixXd &m, py::buffer b) { + /* Request a buffer descriptor from Python */ + py::buffer_info info = b.request(); + + /* Some sanity checks ... */ + if (info.format != py::format_descriptor::value()) + throw std::runtime_error("Incompatible format: expected a double array!"); + + if (info.ndim != 2) + throw std::runtime_error("Incompatible buffer dimension!"); + + if (info.strides[0] == sizeof(double)) { + /* Buffer has the right layout -- directly copy. */ + new (&m) Eigen::MatrixXd(info.shape[0], info.shape[1]); + memcpy(m.data(), info.ptr, sizeof(double) * m.size()); + } else { + /* Oops -- the buffer is transposed */ + new (&m) Eigen::MatrixXd(info.shape[1], info.shape[0]); + memcpy(m.data(), info.ptr, sizeof(double) * m.size()); + m.transposeInPlace(); + } + }); + +.. seealso:: + + The file :file:`example/example7.cpp` contains a complete example that + demonstrates using the buffer protocol with pybind11 in more detail. + +.. [#f1] http://docs.python.org/3/c-api/buffer.html + +NumPy support +============= + +By exchanging ``py::buffer`` with ``py::array`` in the above snippet, we can +restrict the function so that it only accepts NumPy arrays (rather than any +type of Python object satisfying the buffer protocol). + +In many situations, we want to define a function which only accepts a NumPy +array of a certain data type. This is possible via the ``py::array_t`` +template. For instance, the following function requires the argument to be a +dense array of doubles in C-style ordering. + +.. code-block:: cpp + + void f(py::array_t array); + +When it is invoked with a different type (e.g. an integer), the binding code +will attempt to cast the input into a NumPy array of the requested type. Note +that this feature requires the :file:``pybind11/numpy.h`` header to be +included. + +Vectorizing functions +===================== + +Suppose we want to bind a function with the following signature to Python so +that it can process arbitrary NumPy array arguments (vectors, matrices, general +N-D arrays) in addition to its normal arguments: + +.. code-block:: cpp + + double my_func(int x, float y, double z); + +After including the ``pybind11/numpy.h`` header, this is extremely simple: + +.. code-block:: cpp + + m.def("vectorized_func", py::vectorize(my_func)); + +Invoking the function like below causes 4 calls to be made to ``my_func`` with +each of the the array elements. The significant advantage of this compared to +solutions like ``numpy.vectorize()`` is that the loop over the elements runs +entirely on the C++ side and can be crunched down into a tight, optimized loop +by the compiler. The result is returned as a NumPy array of type +``numpy.dtype.float64``. + +.. code-block:: python + + >>> x = np.array([[1, 3],[5, 7]]) + >>> y = np.array([[2, 4],[6, 8]]) + >>> z = 3 + >>> result = vectorized_func(x, y, z) + +The scalar argument ``z`` is transparently replicated 4 times. The input +arrays ``x`` and ``y`` are automatically converted into the right types (they +are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and +``numpy.dtype.float32``, respectively) + +Sometimes we might want to explitly exclude an argument from the vectorization +because it makes little sense to wrap it in a NumPy array. For instance, +suppose the function signature was + +.. code-block:: cpp + + double my_func(int x, float y, my_custom_type *z); + +This can be done with a stateful Lambda closure: + +.. code-block:: cpp + + // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) + m.def("vectorized_func", + [](py::array_t x, py::array_t y, my_custom_type *z) { + auto stateful_closure = [z](int x, float y) { return my_func(x, y, z); }; + return py::vectorize(stateful_closure)(x, y); + } + ); + +In cases where the computation is too complicated to be reduced to +``vectorize``, it will be necessary to create and access the buffer contents +manually. The following snippet contains a complete example that shows how this +works (the code is somewhat contrived, since it could have been done more +simply using ``vectorize``). + +.. code-block:: cpp + + #include + #include + + namespace py = pybind11; + + py::array_t add_arrays(py::array_t input1, py::array_t input2) { + auto buf1 = input1.request(), buf2 = input2.request(); + + if (buf1.ndim != 1 || buf2.ndim != 1) + throw std::runtime_error("Number of dimensions must be one"); + + if (buf1.shape[0] != buf2.shape[0]) + throw std::runtime_error("Input shapes must match"); + + auto result = py::array(py::buffer_info( + nullptr, /* Pointer to data (nullptr -> ask NumPy to allocate!) */ + sizeof(double), /* Size of one item */ + py::format_descriptor::value(), /* Buffer format */ + buf1.ndim, /* How many dimensions? */ + { buf1.shape[0] }, /* Number of elements for each dimension */ + { sizeof(double) } /* Strides for each dimension */ + )); + + auto buf3 = result.request(); + + double *ptr1 = (double *) buf1.ptr, + *ptr2 = (double *) buf2.ptr, + *ptr3 = (double *) buf3.ptr; + + for (size_t idx = 0; idx < buf1.shape[0]; idx++) + ptr3[idx] = ptr1[idx] + ptr2[idx]; + + return result; + } + + PYBIND11_PLUGIN(test) { + py::module m("test"); + m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); + return m.ptr(); + } + +.. seealso:: + + The file :file:`example/example10.cpp` contains a complete example that + demonstrates using :func:`vectorize` in more detail. + +Functions taking Python objects as arguments +============================================ + +pybind11 exposes all major Python types using thin C++ wrapper classes. These +wrapper classes can also be used as parameters of functions in bindings, which +makes it possible to directly work with native Python types on the C++ side. +For instance, the following statement iterates over a Python ``dict``: + +.. code-block:: cpp + + void print_dict(py::dict dict) { + /* Easily interact with Python types */ + for (auto item : dict) + std::cout << "key=" << item.first << ", " + << "value=" << item.second << std::endl; + } + +Available types include :class:`handle`, :class:`object`, :class:`bool_`, +:class:`int_`, :class:`float_`, :class:`str`, :class:`bytes`, :class:`tuple`, +:class:`list`, :class:`dict`, :class:`slice`, :class:`capsule`, +:class:`function`, :class:`buffer`, :class:`array`, and :class:`array_t`. + +In this kind of mixed code, it is often necessary to convert arbitrary C++ +types to Python, which can be done using :func:`cast`: + +.. code-block:: cpp + + MyClass *cls = ..; + py::object obj = py::cast(cls); + +The reverse direction uses the following syntax: + +.. code-block:: cpp + + py::object obj = ...; + MyClass *cls = obj.cast(); + +When conversion fails, both directions throw the exception :class:`cast_error`. + +.. seealso:: + + The file :file:`example/example2.cpp` contains a complete example that + demonstrates passing native Python types in more detail. + +Default arguments revisited +=========================== + +The section on :ref:`default_args` previously discussed basic usage of default +arguments using pybind11. One noteworthy aspect of their implementation is that +default arguments are converted to Python objects right at declaration time. +Consider the following example: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg("arg") = SomeType(123)); + +In this case, pybind11 must already be set up to deal with values of the type +``SomeType`` (via a prior instantiation of ``py::class_``), or an +exception will be thrown. + +Another aspect worth highlighting is that the "preview" of the default argument +in the function signature is generated using the object's ``__repr__`` method. +If not available, the signature may not be very helpful, e.g.: + +.. code-block:: python + + FUNCTIONS + ... + | myFunction(...) + | Signature : (MyClass, arg : SomeType = ) -> NoneType + ... + +The first way of addressing this is by defining ``SomeType.__repr__``. +Alternatively, it is possible to specify the human-readable preview of the +default argument manually using the ``arg_t`` notation: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg_t("arg", SomeType(123), "SomeType(123)")); + +Sometimes it may be necessary to pass a null pointer value as a default +argument. In this case, remember to cast it to the underlying type in question, +like so: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg("arg") = (SomeType *) nullptr); + +Partitioning code over multiple extension modules +================================================= + +It's straightforward to split binding code over multiple extension modules, +while referencing types that are declared elsewhere. Everything "just" works +without any special precautions. One exception to this rule occurs when +extending a type declared in another extension module. Recall the basic example +from Section :ref:`inheritance`. + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + pet.def(py::init()) + .def_readwrite("name", &Pet::name); + + py::class_(m, "Dog", pet /* <- specify parent */) + .def(py::init()) + .def("bark", &Dog::bark); + +Suppose now that ``Pet`` bindings are defined in a module named ``basic``, +whereas the ``Dog`` bindings are defined somewhere else. The challenge is of +course that the variable ``pet`` is not available anymore though it is needed +to indicate the inheritance relationship to the constructor of ``class_``. +However, it can be acquired as follows: + +.. code-block:: cpp + + py::object pet = (py::object) py::module::import("basic").attr("Pet"); + + py::class_(m, "Dog", pet) + .def(py::init()) + .def("bark", &Dog::bark); + +Alternatively, we can rely on the ``base`` tag, which performs an automated +lookup of the corresponding Python type. However, this also requires invoking +the ``import`` function once to ensure that the pybind11 binding code of the +module ``basic`` has been executed. + +.. code-block:: cpp + + py::module::import("basic"); + + py::class_(m, "Dog", py::base()) + .def(py::init()) + .def("bark", &Dog::bark); + +Naturally, both methods will fail when there are cyclic dependencies. + +Note that compiling code which has its default symbol visibility set to +*hidden* (e.g. via the command line flag ``-fvisibility=hidden`` on GCC/Clang) can interfere with the +ability to access types defined in another extension module. Workarounds +include changing the global symbol visibility (not recommended, because it will +lead unnecessarily large binaries) or manually exporting types that are +accessed by multiple extension modules: + +.. code-block:: cpp + + #ifdef _WIN32 + # define EXPORT_TYPE __declspec(dllexport) + #else + # define EXPORT_TYPE __attribute__ ((visibility("default"))) + #endif + + class EXPORT_TYPE Dog : public Animal { + ... + }; + + +Treating STL data structures as opaque objects +============================================== + +pybind11 heavily relies on a template matching mechanism to convert parameters +and return values that are constructed from STL data types such as vectors, +linked lists, hash tables, etc. This even works in a recursive manner, for +instance to deal with lists of hash maps of pairs of elementary and custom +types, etc. + +A fundamental limitation of this approach is that the internal conversion +between Python and C++ types involves a copy operation that prevents +pass-by-reference semantics. What does this mean? + +Suppose we bind the following function + +.. code-block:: cpp + + void append_1(std::vector &v) { + v.push_back(1); + } + +and call it as follows from Python: + +.. code-block:: python + + >>> v = [5, 6] + >>> append_1(v) + >>> print(v) + [5, 6] + +As you can see, when passing STL data structures by reference, modifications +are not propagated back the Python side. To deal with situations where this +desirable, pybind11 contains a simple template wrapper class named ``opaque``. + +``opaque`` disables the underlying template machinery for +``T`` and can be used to treat STL types as opaque objects, whose contents are +never inspected or extracted (thus, they can be passed by reference). +The downside of this approach is that it the binding code becomes a bit more +wordy. The above function can be bound using the following wrapper code: + +.. code-block:: cpp + + m.def("append_1", [](py::opaque> &v) { append_1(v); }); + +Opaque types must also have a dedicated ``class_`` declaration to define a +set of admissible operations. + +.. seealso:: + + The file :file:`example/example14.cpp` contains a complete example that + demonstrates how to create opaque types using pybind11 in more detail. + +Pickling support +================ + +Python's ``pickle`` module provides a powerful facility to serialize and +de-serialize a Python object graph into a binary data stream. To pickle and +unpickle C++ classes using pybind11, two additional functions must be provided. +Suppose the class in question has the following signature: + +.. code-block:: cpp + + class Pickleable { + public: + Pickleable(const std::string &value) : m_value(value) { } + const std::string &value() const { return m_value; } + + void setExtra(int extra) { m_extra = extra; } + int extra() const { return m_extra; } + private: + std::string m_value; + int m_extra = 0; + }; + +The binding code including the requisite ``__setstate__`` and ``__getstate__`` methods [#f2]_ +looks as follows: + +.. code-block:: cpp + + py::class_(m, "Pickleable") + .def(py::init()) + .def("value", &Pickleable::value) + .def("extra", &Pickleable::extra) + .def("setExtra", &Pickleable::setExtra) + .def("__getstate__", [](const Pickleable &p) { + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.value(), p.extra()); + }) + .def("__setstate__", [](Pickleable &p, py::tuple t) { + if (t.size() != 2) + throw std::runtime_error("Invalid state!"); + + /* Invoke the in-place constructor. Note that this is needed even + when the object just has a trivial default constructor */ + new (&p) Pickleable(t[0].cast()); + + /* Assign any additional state */ + p.setExtra(t[1].cast()); + }); + +An instance can now be pickled as follows: + +.. code-block:: python + + try: + import cPickle as pickle # Use cPickle on Python 2.7 + except ImportError: + import pickle + + p = Pickleable("test_value") + p.setExtra(15) + data = pickle.dumps(p, -1) + +Note that only the cPickle module is supported on Python 2.7. It is also +important to request usage of the highest protocol version using the ``-1`` +argument to ``dumps``. Failure to follow these two steps will lead to important +pybind11 memory allocation routines to be skipped during unpickling, which will +likely cause memory corruption and/or segmentation faults. + +.. seealso:: + + The file :file:`example/example15.cpp` contains a complete example that + demonstrates how to pickle and unpickle types using pybind11 in more detail. + +.. [#f2] http://docs.python.org/3/library/pickle.html#pickling-class-instances + +Generating documentation using Sphinx +===================================== + +Sphinx [#f3]_ has the ability to inspect the signatures and documentation +strings in pybind11-based extension modules to automatically generate beautiful +documentation in a variety formats. The pbtest repository [#f4]_ contains a +simple example repository which uses this approach. + +There are two potential gotchas when using this approach: first, make sure that +the resulting strings do not contain any :kbd:`TAB` characters, which break the +docstring parsing routines. You may want to use C++11 raw string literals, +which are convenient for multi-line comments. Conveniently, any excess +indentation will be automatically be removed by Sphinx. However, for this to +work, it is important that all lines are indented consistently, i.e.: + +.. code-block:: cpp + + // ok + m.def("foo", &foo, R"mydelimiter( + The foo function + + Parameters + ---------- + )mydelimiter"); + + // *not ok* + m.def("foo", &foo, R"mydelimiter(The foo function + + Parameters + ---------- + )mydelimiter"); + +.. [#f3] http://www.sphinx-doc.org +.. [#f4] http://github.com/pybind/pbtest + diff --git a/stormpy/resources/pybind11/docs/basics.rst b/stormpy/resources/pybind11/docs/basics.rst new file mode 100644 index 000000000..42ff6e42e --- /dev/null +++ b/stormpy/resources/pybind11/docs/basics.rst @@ -0,0 +1,280 @@ +.. _basics: + +First steps +########### + +This sections demonstrates the basic features of pybind11. Before getting +started, make sure that development environment is set up to compile the +included set of examples, which also double as test cases. + + +Compiling the test cases +======================== + +Linux/MacOS +----------- + +On Linux you'll need to install the **python-dev** or **python3-dev** packages as +well as **cmake**. On Mac OS, the included python version works out of the box, +but **cmake** must still be installed. + +After installing the prerequisites, run + +.. code-block:: bash + + cmake . + make -j 4 + +followed by + +.. code-block:: bash + + make test + +Windows +------- + +On Windows, use the `CMake GUI`_ to create a Visual Studio project. Note that +only the 2015 release and newer versions are supported since pybind11 relies on +various C++11 language features that break older versions of Visual Studio. +After running CMake, open the created :file:`pybind11.sln` file and perform a +release build, which will will produce a file named +:file:`Release\\example.pyd`. Copy this file to the :file:`example` directory +and run :file:`example\\run_test.py` using the targeted Python version. + +.. _`CMake GUI`: https://cmake.org/runningcmake + +.. Note:: + + When all tests fail, make sure that + + 1. The Python binary and the testcases are compiled for the same processor + type and bitness (i.e. either **i386** or **x86_64**) + + 2. The Python binary used to run :file:`example\\run_test.py` matches the + Python version specified in the CMake GUI. This is controlled via + the ``PYTHON_EXECUTABLE`` ``PYTHON_INCLUDE_DIR``, and + ``PYTHON_LIBRARY`` variables. + +.. seealso:: + + Advanced users who are already familiar with Boost.Python may want to skip + the tutorial and look at the test cases in the :file:`example` directory, + which exercise all features of pybind11. + +Creating bindings for a simple function +======================================= + +Let's start by creating Python bindings for an extremely simple function, which +adds two numbers and returns their result: + +.. code-block:: cpp + + int add(int i, int j) { + return i + j; + } + +For simplicity [#f1]_, we'll put both this function and the binding code into +a file named :file:`example.cpp` with the following contents: + +.. code-block:: cpp + + #include + + int add(int i, int j) { + return i + j; + } + + namespace py = pybind11; + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + m.def("add", &add, "A function which adds two numbers"); + + return m.ptr(); + } + +The :func:`PYBIND11_PLUGIN` macro creates a function that will be called when an +``import`` statement is issued from within Python. The next line creates a +module named ``example`` (with the supplied docstring). The method +:func:`module::def` generates binding code that exposes the +``add()`` function to Python. The last line returns the internal Python object +associated with ``m`` to the Python interpreter. + +.. note:: + + Notice how little code was needed to expose our function to Python: all + details regarding the function's parameters and return value were + automatically inferred using template metaprogramming. This overall + approach and the used syntax are borrowed from Boost.Python, though the + underlying implementation is very different. + +pybind11 is a header-only-library, hence it is not necessary to link against +any special libraries (other than Python itself). On Windows, use the CMake +build file discussed in section :ref:`cmake`. On Linux and Mac OS, the above +example can be compiled using the following command + +.. code-block:: bash + + $ c++ -O3 -shared -std=c++11 -I /include `python-config --cflags --ldflags --libs` example.cpp -o example.so + +In general, it is advisable to include several additional build parameters +that can considerably reduce the size of the created binary. Refer to section +:ref:`cmake` for a detailed example of a suitable cross-platform CMake-based +build system. + +Assuming that the created file :file:`example.so` (:file:`example.pyd` on Windows) +is located in the current directory, the following interactive Python session +shows how to load and execute the example. + +.. code-block:: python + + $ python + Python 2.7.10 (default, Aug 22 2015, 20:33:39) + [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin + Type "help", "copyright", "credits" or "license" for more information. + >>> import example + >>> example.add(1, 2) + 3L + >>> + +.. _keyword_args: + +Keyword arguments +================= + +With a simple modification code, it is possible to inform Python about the +names of the arguments ("i" and "j" in this case). + +.. code-block:: cpp + + m.def("add", &add, "A function which adds two numbers", + py::arg("i"), py::arg("j")); + +:class:`arg` is one of several special tag classes which can be used to pass +metadata into :func:`module::def`. With this modified binding code, we can now +call the function using keyword arguments, which is a more readable alternative +particularly for functions taking many parameters: + +.. code-block:: python + + >>> import example + >>> example.add(i=1, j=2) + 3L + +The keyword names also appear in the function signatures within the documentation. + +.. code-block:: python + + >>> help(example) + + .... + + FUNCTIONS + add(...) + Signature : (i: int, j: int) -> int + + A function which adds two numbers + +.. _default_args: + +Default arguments +================= + +Suppose now that the function to be bound has default arguments, e.g.: + +.. code-block:: cpp + + int add(int i = 1, int j = 2) { + return i + j; + } + +Unfortunately, pybind11 cannot automatically extract these parameters, since they +are not part of the function's type information. However, they are simple to specify +using an extension of :class:`arg`: + +.. code-block:: cpp + + m.def("add", &add, "A function which adds two numbers", + py::arg("i") = 1, py::arg("j") = 2); + +The default values also appear within the documentation. + +.. code-block:: python + + >>> help(example) + + .... + + FUNCTIONS + add(...) + Signature : (i: int = 1, j: int = 2) -> int + + A function which adds two numbers + +.. _supported_types: + +Supported data types +==================== + +The following basic data types are supported out of the box (some may require +an additional extension header to be included). To pass other data structures +as arguments and return values, refer to the section on binding :ref:`classes`. + ++----------------------------+--------------------------+-----------------------+ +| Data type | Description | Header file | ++============================+==========================+=======================+ +| int8_t, uint8_t | 8-bit integers | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| int16_t, uint16_t | 16-bit integers | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| int32_t, uint32_t | 32-bit integers | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| int64_t, uint64_t | 64-bit integers | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| ssize_t, size_t | Platform-dependent size | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| float, double | Floating point types | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| bool | Two-state Boolean type | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| char | Character literal | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| wchar_t | Wide character literal | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| const char * | UTF-8 string literal | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| const wchar_t * | Wide string literal | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| std::string | STL dynamic UTF-8 string | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| std::wstring | STL dynamic wide string | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| std::pair | Pair of two custom types | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| std::tuple<....> | Arbitrary tuple of types | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ +| std::complex | Complex numbers | pybind11/complex.h | ++----------------------------+--------------------------+-----------------------+ +| std::array | STL static array | pybind11/stl.h | ++----------------------------+--------------------------+-----------------------+ +| std::vector | STL dynamic array | pybind11/stl.h | ++----------------------------+--------------------------+-----------------------+ +| std::list | STL linked list | pybind11/stl.h | ++----------------------------+--------------------------+-----------------------+ +| std::map | STL ordered map | pybind11/stl.h | ++----------------------------+--------------------------+-----------------------+ +| std::unordered_map | STL unordered map | pybind11/stl.h | ++----------------------------+--------------------------+-----------------------+ +| std::set | STL ordered set | pybind11/stl.h | ++----------------------------+--------------------------+-----------------------+ +| std::unordered_set | STL unordered set | pybind11/stl.h | ++----------------------------+--------------------------+-----------------------+ +| std::function<...> | STL polymorphic function | pybind11/functional.h | ++----------------------------+--------------------------+-----------------------+ + + +.. [#f1] In practice, implementation and binding code will generally be located + in separate files. + diff --git a/stormpy/resources/pybind11/docs/benchmark.py b/stormpy/resources/pybind11/docs/benchmark.py new file mode 100644 index 000000000..6f02e92ff --- /dev/null +++ b/stormpy/resources/pybind11/docs/benchmark.py @@ -0,0 +1,90 @@ +import random +import os +import time +import datetime as dt + +nfns = 4 # Functions per class +nargs = 4 # Arguments per function + + +def generate_dummy_code_pybind11(nclasses=10): + decl = "" + bindings = "" + + for cl in range(nclasses): + decl += "class cl%03i;\n" % cl + decl += '\n' + + for cl in range(nclasses): + decl += "class cl%03i {\n" % cl + decl += "public:\n" + bindings += ' py::class_(m, "cl%03i")\n' % (cl, cl) + for fn in range(nfns): + ret = random.randint(0, nclasses - 1) + params = [random.randint(0, nclasses - 1) for i in range(nargs)] + decl += " cl%03i *fn_%03i(" % (ret, fn) + decl += ", ".join("cl%03i *" % p for p in params) + decl += ");\n" + bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % \ + (fn, cl, fn) + decl += "};\n\n" + bindings += ' ;\n' + + result = "#include \n\n" + result += "namespace py = pybind11;\n\n" + result += decl + '\n' + result += "PYBIND11_PLUGIN(example) {\n" + result += " py::module m(\"example\");" + result += bindings + result += " return m.ptr();" + result += "}" + return result + + +def generate_dummy_code_boost(nclasses=10): + decl = "" + bindings = "" + + for cl in range(nclasses): + decl += "class cl%03i;\n" % cl + decl += '\n' + + for cl in range(nclasses): + decl += "class cl%03i {\n" % cl + decl += "public:\n" + bindings += ' py::class_("cl%03i")\n' % (cl, cl) + for fn in range(nfns): + ret = random.randint(0, nclasses - 1) + params = [random.randint(0, nclasses - 1) for i in range(nargs)] + decl += " cl%03i *fn_%03i(" % (ret, fn) + decl += ", ".join("cl%03i *" % p for p in params) + decl += ");\n" + bindings += ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy())\n' % \ + (fn, cl, fn) + decl += "};\n\n" + bindings += ' ;\n' + + result = "#include \n\n" + result += "namespace py = boost::python;\n\n" + result += decl + '\n' + result += "BOOST_PYTHON_MODULE(example) {\n" + result += bindings + result += "}" + return result + + +for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: + print ("{") + for i in range(0, 10): + nclasses = 2 ** i + with open("test.cpp", "w") as f: + f.write(codegen(nclasses)) + n1 = dt.datetime.now() + os.system("g++ -Os -shared -rdynamic -undefined dynamic_lookup " + "-fvisibility=hidden -std=c++14 test.cpp -I include " + "-I /System/Library/Frameworks/Python.framework/Headers -o test.so") + n2 = dt.datetime.now() + elapsed = (n2 - n1).total_seconds() + size = os.stat('test.so').st_size + print(" {%i, %f, %i}," % (nclasses * nfns, elapsed, size)) + print ("}") diff --git a/stormpy/resources/pybind11/docs/benchmark.rst b/stormpy/resources/pybind11/docs/benchmark.rst new file mode 100644 index 000000000..c31e2902d --- /dev/null +++ b/stormpy/resources/pybind11/docs/benchmark.rst @@ -0,0 +1,83 @@ +Benchmark +========= + +The following is the result of a synthetic benchmark comparing both compilation +time and module size of pybind11 against Boost.Python. + +Setup +----- + +A python script (see the ``docs/benchmark.py`` file) was used to generate a set +of files with dummy classes whose count increases for each successive benchmark +(between 1 and 2048 classes in powers of two). Each class has four methods with +a randomly generated signature with a return value and four arguments. (There +was no particular reason for this setup other than the desire to generate many +unique function signatures whose count could be controlled in a simple way.) + +Here is an example of the binding code for one class: + +.. code-block:: cpp + + ... + class cl034 { + public: + cl279 *fn_000(cl084 *, cl057 *, cl065 *, cl042 *); + cl025 *fn_001(cl098 *, cl262 *, cl414 *, cl121 *); + cl085 *fn_002(cl445 *, cl297 *, cl145 *, cl421 *); + cl470 *fn_003(cl200 *, cl323 *, cl332 *, cl492 *); + }; + ... + + PYBIND11_PLUGIN(example) { + py::module m("example"); + ... + py::class_(m, "cl034") + .def("fn_000", &cl034::fn_000) + .def("fn_001", &cl034::fn_001) + .def("fn_002", &cl034::fn_002) + .def("fn_003", &cl034::fn_003) + ... + return m.ptr(); + } + +The Boost.Python version looks almost identical except that a return value +policy had to be specified as an argument to ``def()``. For both libraries, +compilation was done with + +.. code-block:: bash + + Apple LLVM version 7.0.2 (clang-700.1.81) + +and the following compilation flags + +.. code-block:: bash + + g++ -Os -shared -rdynamic -undefined dynamic_lookup -fvisibility=hidden -std=c++14 + +Compilation time +---------------- + +The following log-log plot shows how the compilation time grows for an +increasing number of class and function declarations. pybind11 includes many +fewer headers, which initially leads to shorter compilation times, but the +performance is ultimately fairly similar (pybind11 is 19.8 seconds faster for +the largest largest file with 2048 classes and a total of 8192 methods -- a +modest **1.2x** speedup relative to Boost.Python, which required 116.35 +seconds). + +.. image:: pybind11_vs_boost_python1.svg + +Module size +----------- + +Differences between the two libraries become much more pronounced when +considering the file size of the generated Python plugin: for the largest file, +the binary generated by Boost.Python required 16.8 MiB, which was **2.17 +times** / **9.1 megabytes** larger than the output generated by pybind11. For +very small inputs, Boost.Python has an edge in the plot below -- however, note +that it stores many definitions in an external library, whose size was not +included here, hence the comparison is slightly shifted in Boost.Python's +favor. + +.. image:: pybind11_vs_boost_python2.svg + diff --git a/stormpy/resources/pybind11/docs/changelog.rst b/stormpy/resources/pybind11/docs/changelog.rst new file mode 100644 index 000000000..92b23670b --- /dev/null +++ b/stormpy/resources/pybind11/docs/changelog.rst @@ -0,0 +1,93 @@ +.. _changelog: + +Changelog +######### + +1.5 (not yet released) +---------------------- +* For polymorphic types, use RTTI to try to return the closest type registered with pybind11. +* Pickling support for serializing and unserializing C++ instances to a byte stream in Python +* Added a convenience routine ``make_iterator()`` which turns a range indicated + by a pair of C++ iterators into a iterable Python object +* Added ``len()`` and a variadic ``make_tuple()`` function +* Addressed a rare issue that could confuse the current virtual function + dispatcher and another that could lead to crashes in multi-threaded + applications +* Added a ``get_include()`` function to the Python module that returns the path + of the directory containing the installed pybind11 header files +* Documentation improvements: import issues, symbol visibility, pickling, limitations + +1.4 (April 7, 2016) +-------------------------- +* Transparent type conversion for ``std::wstring`` and ``wchar_t`` +* Allow passing ``nullptr``-valued strings +* Transparent passing of ``void *`` pointers using capsules +* Transparent support for returning values wrapped in ``std::unique_ptr<>`` +* Improved docstring generation for compatibility with Sphinx +* Nicer debug error message when default parameter construction fails +* Support for "opaque" types that bypass the transparent conversion layer for STL containers +* Redesigned type casting interface to avoid ambiguities that could occasionally cause compiler errors +* Redesigned property implementation; fixes crashes due to an unfortunate default return value policy +* Anaconda package generation support + +1.3 (March 8, 2016) +-------------------------- + +* Added support for the Intel C++ compiler (v15+) +* Added support for the STL unordered set/map data structures +* Added support for the STL linked list data structure +* NumPy-style broadcasting support in ``pybind11::vectorize`` +* pybind11 now displays more verbose error messages when ``arg::operator=()`` fails +* pybind11 internal data structures now live in a version-dependent namespace to avoid ABI issues +* Many, many bugfixes involving corner cases and advanced usage + +1.2 (February 7, 2016) +-------------------------- + +* Optional: efficient generation of function signatures at compile time using C++14 +* Switched to a simpler and more general way of dealing with function default + arguments. Unused keyword arguments in function calls are now detected and + cause errors as expected +* New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward`` +* New ``pybind11::base<>`` attribute to indicate a subclass relationship +* Improved interface for RAII type wrappers in ``pytypes.h`` +* Use RAII type wrappers consistently within pybind11 itself. This + fixes various potential refcount leaks when exceptions occur +* Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7) +* Made handle and related RAII classes const correct, using them more + consistently everywhere now +* Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are + now stored in a C++ hash table that is not visible in Python +* Fixed refcount leaks involving NumPy arrays and bound functions +* Vastly improved handling of shared/smart pointers +* Removed an unnecessary copy operation in ``pybind11::vectorize`` +* Fixed naming clashes when both pybind11 and NumPy headers are included +* Added conversions for additional exception types +* Documentation improvements (using multiple extension modules, smart pointers, + other minor clarifications) +* unified infrastructure for parsing variadic arguments in ``class_`` and cpp_function +* Fixed license text (was: ZLIB, should have been: 3-clause BSD) +* Python 3.2 compatibility +* Fixed remaining issues when accessing types in another plugin module +* Added enum comparison and casting methods +* Improved SFINAE-based detection of whether types are copy-constructible +* Eliminated many warnings about unused variables and the use of ``offsetof()`` +* Support for ``std::array<>`` conversions + +1.1 (December 7, 2015) +-------------------------- + +* Documentation improvements (GIL, wrapping functions, casting, fixed many typos) +* Generalized conversion of integer types +* Improved support for casting function objects +* Improved support for ``std::shared_ptr<>`` conversions +* Initial support for ``std::set<>`` conversions +* Fixed type resolution issue for types defined in a separate plugin module +* Cmake build system improvements +* Factored out generic functionality to non-templated code (smaller code size) +* Added a code size / compile time benchmark vs Boost.Python +* Added an appveyor CI script + +1.0 (October 15, 2015) +------------------------ +* Initial release diff --git a/stormpy/resources/pybind11/docs/classes.rst b/stormpy/resources/pybind11/docs/classes.rst new file mode 100644 index 000000000..c98f8da2e --- /dev/null +++ b/stormpy/resources/pybind11/docs/classes.rst @@ -0,0 +1,331 @@ +.. _classes: + +Object-oriented code +#################### + +Creating bindings for a custom type +=================================== + +Let's now look at a more complex example where we'll create bindings for a +custom C++ data structure named ``Pet``. Its definition is given below: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name) : name(name) { } + void setName(const std::string &name_) { name = name_; } + const std::string &getName() const { return name; } + + std::string name; + }; + +The binding code for ``Pet`` looks as follows: + +.. code-block:: cpp + + #include + + namespace py = pybind11; + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_(m, "Pet") + .def(py::init()) + .def("setName", &Pet::setName) + .def("getName", &Pet::getName); + + return m.ptr(); + } + +:class:`class_` creates bindings for a C++ `class` or `struct`-style data +structure. :func:`init` is a convenience function that takes the types of a +constructor's parameters as template arguments and wraps the corresponding +constructor (see the :ref:`custom_constructors` section for details). An +interactive Python session demonstrating this example is shown below: + +.. code-block:: python + + % python + >>> import example + >>> p = example.Pet('Molly') + >>> print(p) + + >>> p.getName() + u'Molly' + >>> p.setName('Charly') + >>> p.getName() + u'Charly' + +.. seealso:: + + Static member functions can be bound in the same way using + :func:`class_::def_static`. + +Keyword and default arguments +============================= +It is possible to specify keyword and default arguments using the syntax +discussed in the previous chapter. Refer to the sections :ref:`keyword_args` +and :ref:`default_args` for details. + +Binding lambda functions +======================== + +Note how ``print(p)`` produced a rather useless summary of our data structure in the example above: + +.. code-block:: python + + >>> print(p) + + +To address this, we could bind an utility function that returns a human-readable +summary to the special method slot named ``__repr__``. Unfortunately, there is no +suitable functionality in the ``Pet`` data structure, and it would be nice if +we did not have to change it. This can easily be accomplished by binding a +Lambda function instead: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def("setName", &Pet::setName) + .def("getName", &Pet::getName) + .def("__repr__", + [](const Pet &a) { + return ""; + } + ); + +Both stateless [#f1]_ and stateful lambda closures are supported by pybind11. +With the above change, the same Python code now produces the following output: + +.. code-block:: python + + >>> print(p) + + +Instance and static fields +========================== + +We can also directly expose the ``name`` field using the +:func:`class_::def_readwrite` method. A similar :func:`class_::def_readonly` +method also exists for ``const`` fields. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_readwrite("name", &Pet::name) + // ... remainder ... + +This makes it possible to write + +.. code-block:: python + + >>> p = example.Pet('Molly') + >>> p.name + u'Molly' + >>> p.name = 'Charly' + >>> p.name + u'Charly' + +Now suppose that ``Pet::name`` was a private internal variable +that can only be accessed via setters and getters. + +.. code-block:: cpp + + class Pet { + public: + Pet(const std::string &name) : name(name) { } + void setName(const std::string &name_) { name = name_; } + const std::string &getName() const { return name; } + private: + std::string name; + }; + +In this case, the method :func:`class_::def_property` +(:func:`class_::def_property_readonly` for read-only data) can be used to +provide a field-like interface within Python that will transparently call +the setter and getter functions: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_property("name", &Pet::getName, &Pet::setName) + // ... remainder ... + +.. seealso:: + + Similar functions :func:`class_::def_readwrite_static`, + :func:`class_::def_readonly_static` :func:`class_::def_property_static`, + and :func:`class_::def_property_readonly_static` are provided for binding + static variables and properties. + +.. _inheritance: + +Inheritance +=========== + +Suppose now that the example consists of two data structures with an +inheritance relationship: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name) : name(name) { } + std::string name; + }; + + struct Dog : Pet { + Dog(const std::string &name) : Pet(name) { } + std::string bark() const { return "woof!"; } + }; + +There are two different ways of indicating a hierarchical relationship to +pybind11: the first is by specifying the C++ base class explicitly during +construction using the ``base`` attribute: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_readwrite("name", &Pet::name); + + py::class_(m, "Dog", py::base() /* <- specify C++ parent type */) + .def(py::init()) + .def("bark", &Dog::bark); + +Alternatively, we can also assign a name to the previously bound ``Pet`` +:class:`class_` object and reference it when binding the ``Dog`` class: + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + pet.def(py::init()) + .def_readwrite("name", &Pet::name); + + py::class_(m, "Dog", pet /* <- specify Python parent type */) + .def(py::init()) + .def("bark", &Dog::bark); + +Functionality-wise, both approaches are completely equivalent. Afterwards, +instances will expose fields and methods of both types: + +.. code-block:: python + + >>> p = example.Dog('Molly') + >>> p.name + u'Molly' + >>> p.bark() + u'woof!' + +Overloaded methods +================== + +Sometimes there are several overloaded C++ methods with the same name taking +different kinds of input arguments: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name, int age) : name(name), age(age) { } + + void set(int age) { age = age; } + void set(const std::string &name) { name = name; } + + std::string name; + int age; + }; + +Attempting to bind ``Pet::set`` will cause an error since the compiler does not +know which method the user intended to select. We can disambiguate by casting +them to function pointers. Binding multiple functions to the same Python name +automatically creates a chain of function overloads that will be tried in +sequence. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def("set", (void (Pet::*)(int)) &Pet::set, "Set the pet's age") + .def("set", (void (Pet::*)(const std::string &)) &Pet::set, "Set the pet's name"); + +The overload signatures are also visible in the method's docstring: + +.. code-block:: python + + >>> help(example.Pet) + + class Pet(__builtin__.object) + | Methods defined here: + | + | __init__(...) + | Signature : (Pet, str, int) -> NoneType + | + | set(...) + | 1. Signature : (Pet, int) -> NoneType + | + | Set the pet's age + | + | 2. Signature : (Pet, str) -> NoneType + | + | Set the pet's name + +.. note:: + + To define multiple overloaded constructors, simply declare one after the + other using the ``.def(py::init<...>())`` syntax. The existing machinery + for specifying keyword and default arguments also works. + +Enumerations and internal types +=============================== + +Let's now suppose that the example class contains an internal enumeration type, +e.g.: + +.. code-block:: cpp + + struct Pet { + enum Kind { + Dog = 0, + Cat + }; + + Pet(const std::string &name, Kind type) : name(name), type(type) { } + + std::string name; + Kind type; + }; + +The binding code for this example looks as follows: + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + + pet.def(py::init()) + .def_readwrite("name", &Pet::name) + .def_readwrite("type", &Pet::type); + + py::enum_(pet, "Kind") + .value("Dog", Pet::Kind::Dog) + .value("Cat", Pet::Kind::Cat) + .export_values(); + +To ensure that the ``Kind`` type is created within the scope of ``Pet``, the +``pet`` :class:`class_` instance must be supplied to the :class:`enum_`. +constructor. The :func:`enum_::export_values` function exports the enum entries +into the parent scope, which should be skipped for newer C++11-style strongly +typed enums. + +.. code-block:: python + + >>> p = Pet('Lucy', Pet.Cat) + >>> p.type + Kind.Cat + >>> int(p.type) + 1L + + +.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object. diff --git a/stormpy/resources/pybind11/docs/cmake.rst b/stormpy/resources/pybind11/docs/cmake.rst new file mode 100644 index 000000000..ace216758 --- /dev/null +++ b/stormpy/resources/pybind11/docs/cmake.rst @@ -0,0 +1,153 @@ +Build systems +############# + +Building with setuptools +======================== + +For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay +has kindly provided an example project which shows how to set up everything, +including automatic generation of documentation using Sphinx. Please refer to +the [pbtest]_ repository. + +.. [pbtest] https://github.com/pybind/pbtest + +.. _cmake: + +Building with CMake +=================== + +For C++ codebases that already have an existing CMake-based build system, the +following snippet should be a good starting point to create bindings across +platforms. It assumes that the code is located in a file named +:file:`example.cpp`, and that the pybind11 repository is located in a +subdirectory named :file:`pybind11`. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 2.8) + + project(example) + + # Add a CMake parameter for choosing a desired Python version + set(EXAMPLE_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling the example library") + + include(CheckCXXCompilerFlag) + + # Set a default build configuration if none is specified. 'MinSizeRel' produces the smallest binaries + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'MinSizeRel' as none was specified.") + set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" + "MinSizeRel" "RelWithDebInfo") + endif() + string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) + + # Try to autodetect Python (can be overridden manually if needed) + set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) + if (NOT ${EXAMPLE_PYTHON_VERSION} STREQUAL "") + find_package(PythonLibs ${EXAMPLE_PYTHON_VERSION} EXACT) + if (NOT PythonLibs_FOUND) + find_package(PythonLibs ${EXAMPLE_PYTHON_VERSION} REQUIRED) + endif() + else() + find_package(PythonLibs REQUIRED) + endif() + + # The above sometimes returns version numbers like "3.4.3+"; the "+" must be removed for the next lines to work + string(REPLACE "+" "" PYTHONLIBS_VERSION_STRING "+${PYTHONLIBS_VERSION_STRING}") + + # Uncomment the following line if you will also require a matching Python interpreter + # find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED) + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG) + CHECK_CXX_COMPILER_FLAG("-std=c++11" HAS_CPP11_FLAG) + + if (HAS_CPP14_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") + elseif (HAS_CPP11_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + else() + message(FATAL_ERROR "Unsupported compiler -- at least C++11 support is needed!") + endif() + + # Enable link time optimization and set the default symbol + # visibility to hidden (very important to obtain small binaries) + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + # Default symbol visibility + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") + + # Check for Link Time Optimization support + CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) + if (HAS_LTO_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") + endif() + endif() + endif() + + # Include path for Python header files + include_directories(${PYTHON_INCLUDE_DIR}) + + # Include path for pybind11 header files -- this may need to be changed depending on your setup + include_directories(${PROJECT_SOURCE_DIR}/pybind11/include) + + # Create the binding library + add_library(example SHARED + example.cpp + # ... extra files go here ... + ) + + # Don't add a 'lib' prefix to the shared library + set_target_properties(example PROPERTIES PREFIX "") + + if (WIN32) + if (MSVC) + # /bigobj is needed for bigger binding projects due to the limit to 64k + # addressable sections. /MP enables multithreaded builds (relevant when + # there are many files). + set_target_properties(example PROPERTIES COMPILE_FLAGS "/MP /bigobj ") + + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + # Enforce size-based optimization and link time code generation on MSVC + # (~30% smaller binaries in experiments). + set_target_properties(example APPEND_STRING PROPERTY COMPILE_FLAGS "/Os /GL ") + set_target_properties(example APPEND_STRING PROPERTY LINK_FLAGS "/LTCG ") + endif() + endif() + + # .PYD file extension on Windows + set_target_properties(example PROPERTIES SUFFIX ".pyd") + + # Link against the Python shared library + target_link_libraries(example ${PYTHON_LIBRARY}) + elseif (UNIX) + # It's quite common to have multiple copies of the same Python version + # installed on one's system. E.g.: one copy from the OS and another copy + # that's statically linked into an application like Blender or Maya. + # If we link our plugin library against the OS Python here and import it + # into Blender or Maya later on, this will cause segfaults when multiple + # conflicting Python instances are active at the same time (even when they + # are of the same version). + + # Windows is not affected by this issue since it handles DLL imports + # differently. The solution for Linux and Mac OS is simple: we just don't + # link against the Python library. The resulting shared library will have + # missing symbols, but that's perfectly fine -- they will be resolved at + # import time. + + # .SO file extension on Linux/Mac OS + set_target_properties(example PROPERTIES SUFFIX ".so") + + # Strip unnecessary sections of the binary on Linux/Mac OS + if(APPLE) + set_target_properties(example PROPERTIES MACOSX_RPATH ".") + set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ") + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so) + endif() + else() + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + add_custom_command(TARGET example POST_BUILD COMMAND strip ${PROJECT_BINARY_DIR}/example.so) + endif() + endif() + endif() diff --git a/stormpy/resources/pybind11/docs/conf.py b/stormpy/resources/pybind11/docs/conf.py new file mode 100644 index 000000000..a05acc33e --- /dev/null +++ b/stormpy/resources/pybind11/docs/conf.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# pybind11 documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 11 19:23:48 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['.templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'pybind11' +copyright = '2015, Wenzel Jakob' +author = 'Wenzel Jakob' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['.build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +#pygments_style = 'monokai' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + + html_context = { + 'css_files': [ + '_static/theme_overrides.css' + ] + } +else: + html_context = { + 'css_files': [ + '//media.readthedocs.org/css/sphinx_rtd_theme.css', + '//media.readthedocs.org/css/readthedocs-doc-embed.css', + '_static/theme_overrides.css' + ] + } + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['.static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pybind11doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'pybind11.tex', 'pybind11 Documentation', + 'Wenzel Jakob', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pybind11', 'pybind11 Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'pybind11', 'pybind11 Documentation', + author, 'pybind11', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +primary_domain = 'cpp' +highlight_language = 'cpp' diff --git a/stormpy/resources/pybind11/docs/faq.rst b/stormpy/resources/pybind11/docs/faq.rst new file mode 100644 index 000000000..12d28375e --- /dev/null +++ b/stormpy/resources/pybind11/docs/faq.rst @@ -0,0 +1,99 @@ +Frequently asked questions +########################## + +(under construction) + +ImportError: dynamic module does not define init function +========================================================= + +1. Make sure that the name specified in ``pybind::module`` and + ``PYBIND11_PLUGIN`` is consistent and identical to the filename of the + extension library. The latter should not contain any extra prefixes (e.g. + ``test.so`` instead of ``libtest.so``). + +2. If the above did not fix your issue, then you are likely using an + incompatible version of Python (for instance, the extension library was + compiled against Python 2, while the interpreter is running on top of some + version of Python 3) + +Limitations involving reference arguments +========================================= + +In C++, it's fairly common to pass arguments using mutable references or +mutable pointers, which allows both read and write access to the value +supplied by the caller. This is sometimes done for efficiency reasons, or to +realize functions that have multiple return values. Here are two very basic +examples: + +.. code-block:: cpp + + void increment(int &i) { i++; } + void increment_ptr(int *i) { (*i)++; } + +In Python, all arguments are passed by reference, so there is no general +issue in binding such code from Python. + +However, certain basic Python types (like ``str``, ``int``, ``bool``, +``float``, etc.) are **immutable**. This means that the following attempt +to port the function to Python doesn't have the same effect on the value +provided by the caller -- in fact, it does nothing at all. + +.. code-block:: python + + def increment(i): + i += 1 # nope.. + +pybind11 is also affected by such language-level conventions, which means that +binding ``increment`` or ``increment_ptr`` will also create Python functions +that don't modify their arguments. + +Although inconvenient, one workaround is to encapsulate the immutable types in +a custom type that does allow modifications. + +An other alternative involves binding a small wrapper lambda function that +returns a tuple with all output arguments (see the remainder of the +documentation for examples on binding lambda functions). An example: + +.. code-block:: cpp + + int foo(int &i) { i++; return 123; } + +and the binding code + +.. code-block:: cpp + + m.def("foo", [](int i) { int rv = foo(i); return std::make_tuple(rv, i); }); + +CMake doesn't detect the right Python version, or it finds mismatched interpreter and library versions +====================================================================================================== + +The Python detection logic of CMake is flawed and can sometimes fail to find +the desired Python version, or it chooses mismatched interpreter and library +versions. A longer discussion is available on the pybind11 issue tracker +[#f1]_, though this is ultimately not a pybind11 issue. + +To force the build system to choose a particular version, delete CMakeCache.txt +and then invoke CMake as follows: + +.. code-block:: bash + + cmake -DPYTHON_EXECUTABLE:FILEPATH=<...> \ + -DPYTHON_LIBRARY:FILEPATH=<...> \ + -DPYTHON_INCLUDE_DIR:PATH=<...> . + +.. [#f1] http://github.com/pybind/pybind11/issues/99 + +Working with ancient Visual Studio 2009 builds on Windows +========================================================= + +The official Windows distributions of Python are compiled using truly +ancient versions of Visual Studio that lack good C++11 support. Some users +implicitly assume that it would be impossible to load a plugin built with +Visual Studio 2015 into a Python distribution that was compiled using Visual +Studio 2009. However, no such issue exists: it's perfectly legitimate to +interface DLLs that are built with different compilers and/or C libraries. +Common gotchas to watch out for involve not ``free()``-ing memory region +that that were ``malloc()``-ed in another shared library, using data +structures with incompatible ABIs, and so on. pybind11 is very careful not +to make these types of mistakes. + diff --git a/stormpy/resources/pybind11/docs/index.rst b/stormpy/resources/pybind11/docs/index.rst new file mode 100644 index 000000000..56a9c0cfa --- /dev/null +++ b/stormpy/resources/pybind11/docs/index.rst @@ -0,0 +1,20 @@ +.. image:: pybind11-logo.png + +pybind11 --- Seamless operability between C++11 and Python +========================================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + intro + basics + classes + advanced + cmake + benchmark + limitations + faq + reference + changelog diff --git a/stormpy/resources/pybind11/docs/intro.rst b/stormpy/resources/pybind11/docs/intro.rst new file mode 100644 index 000000000..af35db9eb --- /dev/null +++ b/stormpy/resources/pybind11/docs/intro.rst @@ -0,0 +1,87 @@ +.. image:: pybind11-logo.png + +About this project +================== +**pybind11** is a lightweight header-only library that exposes C++ types in Python +and vice versa, mainly to create Python bindings of existing C++ code. Its +goals and syntax are similar to the excellent `Boost.Python`_ library by David +Abrahams: to minimize boilerplate code in traditional extension modules by +inferring type information using compile-time introspection. + +.. _Boost.Python: http://www.boost.org/doc/libs/release/libs/python/doc/index.html + +The main issue with Boost.Python—and the reason for creating such a similar +project—is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~2.5K lines of code and depend on +Python (2.7 or 3.x) and the C++ standard library. This compact implementation +was possible thanks to some of the new C++11 language features (specifically: +tuples, lambda functions and variadic templates). Since its creation, this +library has grown beyond Boost.Python in many ways, leading to dramatically +simpler binding code in many common situations. + +Core features +************* +The following core C++ features can be mapped to Python + +- Functions accepting and returning custom data structures per value, reference, or pointer +- Instance methods and static methods +- Overloaded functions +- Instance attributes and static attributes +- Exceptions +- Enumerations +- Iterators and ranges +- Callbacks +- Custom operators +- STL data structures +- Smart pointers with reference counting like ``std::shared_ptr`` +- Internal references with correct reference counting +- C++ classes with virtual (and pure virtual) methods can be extended in Python + +Goodies +******* +In addition to the core functionality, pybind11 provides some extra goodies: + +- It is possible to bind C++11 lambda functions with captured variables. The + lambda capture data is stored inside the resulting Python function object. + +- pybind11 uses C++11 move constructors and move assignment operators whenever + possible to efficiently transfer custom data types. + +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between + C++ matrix classes like Eigen and NumPy without expensive copy operations. + +- pybind11 can automatically vectorize functions so that they are transparently + applied to all entries of one or more NumPy array arguments. + +- Python's slice-based access and assignment operations can be supported with + just a few lines of code. + +- Everything is contained in just a few header files; there is no need to link + against any additional libraries. + +- Binaries are generally smaller by a factor of 2 or more compared to + equivalent bindings generated by Boost.Python. + +- When supported by the compiler, two new C++14 features (relaxed constexpr and + return value deduction) are used to precompute function signatures at compile + time, leading to smaller binaries. + +- With little extra effort, C++ types can be pickled and unpickled similar to + regular Python objects. + +Supported compilers +******************* + +1. Clang/LLVM (any non-ancient version with C++11 support) +2. GCC (any non-ancient version with C++11 support) +3. Microsoft Visual Studio 2015 or newer +4. Intel C++ compiler v15 or newer diff --git a/stormpy/resources/pybind11/docs/limitations.rst b/stormpy/resources/pybind11/docs/limitations.rst new file mode 100644 index 000000000..434d09b37 --- /dev/null +++ b/stormpy/resources/pybind11/docs/limitations.rst @@ -0,0 +1,19 @@ +Limitations +########### + +pybind11 strives to be a general solution to binding generation, but it also has +certain limitations: + +- pybind11 casts away ``const``-ness in function arguments and return values. + This is in line with the Python language, which has no concept of ``const`` + values. This means that some additional care is needed to avoid bugs that + would be caught by the type checker in a traditional C++ program. + +- Multiple inheritance relationships on the C++ side cannot be mapped to + Python. + +Both of these features could be implemented but would lead to a significant +increase in complexity. I've decided to draw the line here to keep this project +simple and compact. Users who absolutely require these features are encouraged +to fork pybind11. + diff --git a/stormpy/resources/pybind11/docs/pybind11-logo.png b/stormpy/resources/pybind11/docs/pybind11-logo.png new file mode 100644 index 000000000..4cbad54f7 Binary files /dev/null and b/stormpy/resources/pybind11/docs/pybind11-logo.png differ diff --git a/stormpy/resources/pybind11/docs/pybind11_vs_boost_python1.svg b/stormpy/resources/pybind11/docs/pybind11_vs_boost_python1.svg new file mode 100644 index 000000000..5bf950e6f --- /dev/null +++ b/stormpy/resources/pybind11/docs/pybind11_vs_boost_python1.svg @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stormpy/resources/pybind11/docs/pybind11_vs_boost_python2.svg b/stormpy/resources/pybind11/docs/pybind11_vs_boost_python2.svg new file mode 100644 index 000000000..5ed6530ca --- /dev/null +++ b/stormpy/resources/pybind11/docs/pybind11_vs_boost_python2.svg @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stormpy/resources/pybind11/docs/reference.rst b/stormpy/resources/pybind11/docs/reference.rst new file mode 100644 index 000000000..4df4344a8 --- /dev/null +++ b/stormpy/resources/pybind11/docs/reference.rst @@ -0,0 +1,246 @@ +.. _reference: + +.. warning:: + + Please be advised that the reference documentation discussing pybind11 + internals is currently incomplete. Please refer to the previous sections + and the pybind11 header files for the nitty gritty details. + +Reference +######### + +Macros +====== + +.. function:: PYBIND11_PLUGIN(const char *name) + + This macro creates the entry point that will be invoked when the Python + interpreter imports a plugin library. Please create a + :class:`module` in the function body and return the pointer to its + underlying Python object at the end. + + .. code-block:: cpp + + PYBIND11_PLUGIN(example) { + pybind11::module m("example", "pybind11 example plugin"); + /// Set up bindings here + return m.ptr(); + } + +.. _core_types: + +Convenience classes for arbitrary Python types +============================================== + +Without reference counting +-------------------------- + +.. class:: handle + + The :class:`handle` class is a thin wrapper around an arbitrary Python + object (i.e. a ``PyObject *`` in Python's C API). It does not perform any + automatic reference counting and merely provides a basic C++ interface to + various Python API functions. + +.. seealso:: + + The :class:`object` class inherits from :class:`handle` and adds automatic + reference counting features. + +.. function:: handle::handle() + + The default constructor creates a handle with a ``nullptr``-valued pointer. + +.. function:: handle::handle(const handle&) + + Copy constructor + +.. function:: handle::handle(PyObject *) + + Creates a :class:`handle` from the given raw Python object pointer. + +.. function:: PyObject * handle::ptr() const + + Return the ``PyObject *`` underlying a :class:`handle`. + +.. function:: const handle& handle::inc_ref() const + + Manually increase the reference count of the Python object. Usually, it is + preferable to use the :class:`object` class which derives from + :class:`handle` and calls this function automatically. Returns a reference + to itself. + +.. function:: const handle& handle::dec_ref() const + + Manually decrease the reference count of the Python object. Usually, it is + preferable to use the :class:`object` class which derives from + :class:`handle` and calls this function automatically. Returns a reference + to itself. + +.. function:: void handle::ref_count() const + + Return the object's current reference count + +.. function:: handle handle::get_type() const + + Return a handle to the Python type object underlying the instance + +.. function detail::accessor handle::operator[](handle key) const + + Return an internal functor to invoke the object's sequence protocol. + Casting the returned ``detail::accessor`` instance to a :class:`handle` or + :class:`object` subclass causes a corresponding call to ``__getitem__``. + Assigning a :class:`handle` or :class:`object` subclass causes a call to + ``__setitem__``. + +.. function detail::accessor handle::operator[](const char *key) const + + See the above function (the only difference is that they key is provided as + a string literal). + +.. function detail::accessor handle::attr(handle key) const + + Return an internal functor to access the object's attributes. + Casting the returned ``detail::accessor`` instance to a :class:`handle` or + :class:`object` subclass causes a corresponding call to ``__getattr``. + Assigning a :class:`handle` or :class:`object` subclass causes a call to + ``__setattr``. + +.. function detail::accessor handle::attr(const char *key) const + + See the above function (the only difference is that they key is provided as + a string literal). + +.. function operator handle::bool() const + + Return ``true`` when the :class:`handle` wraps a valid Python object. + +.. function str handle::str() const + + Return a string representation of the object. This is analogous to + the ``str()`` function in Python. + +.. function:: template T handle::cast() const + + Attempt to cast the Python object into the given C++ type. A + :class:`cast_error` will be throw upon failure. + +.. function:: template object handle::call(Args&&... args) const + + Assuming the Python object is a function or implements the ``__call__`` + protocol, ``call()`` invokes the underlying function, passing an arbitrary + set of parameters. The result is returned as a :class:`object` and may need + to be converted back into a Python object using :func:`handle::cast`. + + When some of the arguments cannot be converted to Python objects, the + function will throw a :class:`cast_error` exception. When the Python + function call fails, a :class:`error_already_set` exception is thrown. + +With reference counting +----------------------- + +.. class:: object : public handle + + Like :class:`handle`, the object class is a thin wrapper around an + arbitrary Python object (i.e. a ``PyObject *`` in Python's C API). In + contrast to :class:`handle`, it optionally increases the object's reference + count upon construction, and it *always* decreases the reference count when + the :class:`object` instance goes out of scope and is destructed. When + using :class:`object` instances consistently, it is much easier to get + reference counting right at the first attempt. + +.. function:: object::object(const object &o) + + Copy constructor; always increases the reference count + +.. function:: object::object(const handle &h, bool borrowed) + + Creates a :class:`object` from the given :class:`handle`. The reference + count is only increased if the ``borrowed`` parameter is set to ``true``. + +.. function:: object::object(PyObject *ptr, bool borrowed) + + Creates a :class:`object` from the given raw Python object pointer. The + reference count is only increased if the ``borrowed`` parameter is set to + ``true``. + +.. function:: object::object(object &&other) + + Move constructor; steals the object from ``other`` and preserves its + reference count. + +.. function:: handle object::release() + + Resets the internal pointer to ``nullptr`` without without decreasing the + object's reference count. The function returns a raw handle to the original + Python object. + +.. function:: object::~object() + + Destructor, which automatically calls :func:`handle::dec_ref()`. + +Convenience classes for specific Python types +============================================= + + +.. class:: module : public object + +.. function:: module::module(const char *name, const char *doc = nullptr) + + Create a new top-level Python module with the given name and docstring + +.. function:: module module::def_submodule(const char *name, const char *doc = nullptr) + + Create and return a new Python submodule with the given name and docstring. + This also works recursively, i.e. + + .. code-block:: cpp + + pybind11::module m("example", "pybind11 example plugin"); + pybind11::module m2 = m.def_submodule("sub", "A submodule of 'example'"); + pybind11::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); + +.. cpp:function:: template module& module::def(const char *name, Func && f, Extra && ... extra) + + Create Python binding for a new function within the module scope. ``Func`` + can be a plain C++ function, a function pointer, or a lambda function. For + details on the ``Extra&& ... extra`` argument, see section :ref:`extras`. + +.. _extras: + +Passing extra arguments to the def function +=========================================== + +.. class:: arg + +.. function:: arg::arg(const char *name) + +.. function:: template arg_t arg::operator=(const T &value) + +.. class:: template arg_t : public arg + + Represents a named argument with a default value + +.. class:: sibling + + Used to specify a handle to an existing sibling function; used internally + to implement function overloading in :func:`module::def` and + :func:`class_::def`. + +.. function:: sibling::sibling(handle handle) + +.. class doc + + This is class is internally used by pybind11. + +.. function:: doc::doc(const char *value) + + Create a new docstring with the specified value + +.. class name + + This is class is internally used by pybind11. + +.. function:: name::name(const char *value) + + Used to specify the function name diff --git a/stormpy/resources/pybind11/docs/release.rst b/stormpy/resources/pybind11/docs/release.rst new file mode 100644 index 000000000..591158e95 --- /dev/null +++ b/stormpy/resources/pybind11/docs/release.rst @@ -0,0 +1,21 @@ +To release a new version of pybind11: + +- Update the version number and push to pypi + - Update ``pybind11/_version.py`` (set release version, remove 'dev') + - ``git add`` and ``git commit``. + - ``python setup.py sdist upload``. + - ``python setup.py bdist_wheel upload``. + - Tag release date in ``doc/changelog.rst``. +- Tag the commit and push to anaconda.org + - ``git tag -a X.X -m '[Release comment]'``. + - ``conda-build conda.recipe --output`` + This should ouput the path of the generated tar.bz2 for the package + - ``conda-convert --platform all [path/to/tar.bz2] -o .`` + - ``for i in *-32/* *-64/*; do anaconda upload -u pybind $i; done`` +- Get back to work + - Update ``_version.py`` (add 'dev' and increment minor). + - Update version macros in ``include/pybind11/common.h`` + - ``git add`` and ``git commit``. ``git push``. ``git push --tags``. + +The remote for the last ``git push --tags`` should be the main repository for +pybind11. diff --git a/stormpy/resources/pybind11/example/example.cpp b/stormpy/resources/pybind11/example/example.cpp new file mode 100644 index 000000000..ba0ff2812 --- /dev/null +++ b/stormpy/resources/pybind11/example/example.cpp @@ -0,0 +1,52 @@ +/* + example/example.cpp -- pybind example plugin + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +void init_ex1(py::module &); +void init_ex2(py::module &); +void init_ex3(py::module &); +void init_ex4(py::module &); +void init_ex5(py::module &); +void init_ex6(py::module &); +void init_ex7(py::module &); +void init_ex8(py::module &); +void init_ex9(py::module &); +void init_ex10(py::module &); +void init_ex11(py::module &); +void init_ex12(py::module &); +void init_ex13(py::module &); +void init_ex14(py::module &); +void init_ex15(py::module &); +void init_ex16(py::module &); +void init_issues(py::module &); + +PYBIND11_PLUGIN(example) { + py::module m("example", "pybind example plugin"); + + init_ex1(m); + init_ex2(m); + init_ex3(m); + init_ex4(m); + init_ex5(m); + init_ex6(m); + init_ex7(m); + init_ex8(m); + init_ex9(m); + init_ex10(m); + init_ex11(m); + init_ex12(m); + init_ex13(m); + init_ex14(m); + init_ex15(m); + init_ex16(m); + init_issues(m); + + return m.ptr(); +} diff --git a/stormpy/resources/pybind11/example/example.h b/stormpy/resources/pybind11/example/example.h new file mode 100644 index 000000000..ab8fff796 --- /dev/null +++ b/stormpy/resources/pybind11/example/example.h @@ -0,0 +1,7 @@ +#include +#include + +using std::cout; +using std::endl; + +namespace py = pybind11; diff --git a/stormpy/resources/pybind11/example/example1.cpp b/stormpy/resources/pybind11/example/example1.cpp new file mode 100644 index 000000000..2a0038d82 --- /dev/null +++ b/stormpy/resources/pybind11/example/example1.cpp @@ -0,0 +1,92 @@ +/* + example/example1.cpp -- constructors, deconstructors, attribute access, + __str__, argument and return value conventions + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +class Example1 { +public: + Example1() { + cout << "Called Example1 default constructor.." << endl; + } + Example1(int value) : value(value) { + cout << "Called Example1 constructor with value " << value << ".." << endl; + } + Example1(const Example1 &e) : value(e.value) { + cout << "Called Example1 copy constructor with value " << value << ".." << endl; + } + Example1(Example1 &&e) : value(e.value) { + cout << "Called Example1 move constructor with value " << value << ".." << endl; + e.value = 0; + } + ~Example1() { + cout << "Called Example1 destructor (" << value << ")" << endl; + } + std::string toString() { + return "Example1[value=" + std::to_string(value) + "]"; + } + + void operator=(const Example1 &e) { cout << "Assignment operator" << endl; value = e.value; } + void operator=(Example1 &&e) { cout << "Move assignment operator" << endl; value = e.value; e.value = 0;} + + void add1(Example1 other) { value += other.value; } // passing by value + void add2(Example1 &other) { value += other.value; } // passing by reference + void add3(const Example1 &other) { value += other.value; } // passing by const reference + void add4(Example1 *other) { value += other->value; } // passing by pointer + void add5(const Example1 *other) { value += other->value; } // passing by const pointer + + void add6(int other) { value += other; } // passing by value + void add7(int &other) { value += other; } // passing by reference + void add8(const int &other) { value += other; } // passing by const reference + void add9(int *other) { value += *other; } // passing by pointer + void add10(const int *other) { value += *other; } // passing by const pointer + + Example1 self1() { return *this; } // return by value + Example1 &self2() { return *this; } // return by reference + const Example1 &self3() { return *this; } // return by const reference + Example1 *self4() { return this; } // return by pointer + const Example1 *self5() { return this; } // return by const pointer + + int internal1() { return value; } // return by value + int &internal2() { return value; } // return by reference + const int &internal3() { return value; } // return by const reference + int *internal4() { return &value; } // return by pointer + const int *internal5() { return &value; } // return by const pointer + + int value = 0; +}; + +void init_ex1(py::module &m) { + py::class_(m, "Example1") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def("add1", &Example1::add1) + .def("add2", &Example1::add2) + .def("add3", &Example1::add3) + .def("add4", &Example1::add4) + .def("add5", &Example1::add5) + .def("add6", &Example1::add6) + .def("add7", &Example1::add7) + .def("add8", &Example1::add8) + .def("add9", &Example1::add9) + .def("add10", &Example1::add10) + .def("self1", &Example1::self1) + .def("self2", &Example1::self2) + .def("self3", &Example1::self3) + .def("self4", &Example1::self4) + .def("self5", &Example1::self5) + .def("internal1", &Example1::internal1) + .def("internal2", &Example1::internal2) + .def("internal3", &Example1::internal3) + .def("internal4", &Example1::internal4) + .def("internal5", &Example1::internal5) + .def("__str__", &Example1::toString) + .def_readwrite("value", &Example1::value); +} diff --git a/stormpy/resources/pybind11/example/example1.py b/stormpy/resources/pybind11/example/example1.py new file mode 100755 index 000000000..f89b662d8 --- /dev/null +++ b/stormpy/resources/pybind11/example/example1.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import Example1 + +instance1 = Example1() +instance2 = Example1(32) +instance1.add1(instance2) +instance1.add2(instance2) +instance1.add3(instance2) +instance1.add4(instance2) +instance1.add5(instance2) +instance1.add6(32) +instance1.add7(32) +instance1.add8(32) +instance1.add9(32) +instance1.add10(32) + +print("Instance 1: " + str(instance1)) +print("Instance 2: " + str(instance2)) + +print(instance1.self1()) +print(instance1.self2()) +print(instance1.self3()) +print(instance1.self4()) +print(instance1.self5()) +print(instance1.internal1()) +print(instance1.internal2()) +print(instance1.internal3()) +print(instance1.internal4()) +print(instance1.internal5()) + +print("Instance 1, direct access = %i" % instance1.value) +instance1.value = 100 +print("Instance 1: " + str(instance1)) diff --git a/stormpy/resources/pybind11/example/example1.ref b/stormpy/resources/pybind11/example/example1.ref new file mode 100644 index 000000000..37c7fef9a --- /dev/null +++ b/stormpy/resources/pybind11/example/example1.ref @@ -0,0 +1,26 @@ +Called Example1 default constructor.. +Called Example1 constructor with value 32.. +Called Example1 copy constructor with value 32.. +Called Example1 copy constructor with value 32.. +Called Example1 destructor (32) +Called Example1 destructor (32) +Instance 1: Example1[value=320] +Instance 2: Example1[value=32] +Called Example1 copy constructor with value 320.. +Called Example1 copy constructor with value 320.. +Called Example1 destructor (320) +Example1[value=320] +Called Example1 destructor (320) +Example1[value=320] +Example1[value=320] +Example1[value=320] +Example1[value=320] +320 +320 +320 +320 +320 +Instance 1, direct access = 320 +Instance 1: Example1[value=100] +Called Example1 destructor (32) +Called Example1 destructor (100) diff --git a/stormpy/resources/pybind11/example/example10.cpp b/stormpy/resources/pybind11/example/example10.cpp new file mode 100644 index 000000000..1a377e569 --- /dev/null +++ b/stormpy/resources/pybind11/example/example10.cpp @@ -0,0 +1,36 @@ +/* + example/example10.cpp -- auto-vectorize functions over NumPy array + arguments + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include + +double my_func(int x, float y, double z) { + std::cout << "my_func(x:int=" << x << ", y:float=" << y << ", z:float=" << z << ")" << std::endl; + return x*y*z; +} + +std::complex my_func3(std::complex c) { + return c * std::complex(2.f); +} + +void init_ex10(py::module &m) { + // Vectorize all arguments of a function (though non-vector arguments are also allowed) + m.def("vectorized_func", py::vectorize(my_func)); + + // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) + m.def("vectorized_func2", + [](py::array_t x, py::array_t y, float z) { + return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(x, y); + } + ); + + // Vectorize a complex-valued function + m.def("vectorized_func3", py::vectorize(my_func3)); +} diff --git a/stormpy/resources/pybind11/example/example10.py b/stormpy/resources/pybind11/example/example10.py new file mode 100755 index 000000000..0d49fcaa7 --- /dev/null +++ b/stormpy/resources/pybind11/example/example10.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +import example +try: + import numpy as np +except ImportError: + print('NumPy missing') + exit(0) + +from example import vectorized_func +from example import vectorized_func2 +from example import vectorized_func3 + +print(vectorized_func3(np.array(3+7j))) + +for f in [vectorized_func, vectorized_func2]: + print(f(1, 2, 3)) + print(f(np.array(1), np.array(2), 3)) + print(f(np.array([1, 3]), np.array([2, 4]), 3)) + print(f(np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3)) + print(np.array([[1, 3, 5], [7, 9, 11]])* np.array([[2, 4, 6], [8, 10, 12]])*3) + print(f(np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2)) + print(np.array([[1, 2, 3], [4, 5, 6]])* np.array([2, 3, 4])* 2) + print(f(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2)) + print(np.array([[1, 2, 3], [4, 5, 6]])* np.array([[2], [3]])* 2) + diff --git a/stormpy/resources/pybind11/example/example10.ref b/stormpy/resources/pybind11/example/example10.ref new file mode 100644 index 000000000..9d48d7cfd --- /dev/null +++ b/stormpy/resources/pybind11/example/example10.ref @@ -0,0 +1,75 @@ +(6+14j) +my_func(x:int=1, y:float=2, z:float=3) +6.0 +my_func(x:int=1, y:float=2, z:float=3) +6.0 +my_func(x:int=1, y:float=2, z:float=3) +my_func(x:int=3, y:float=4, z:float=3) +[ 6. 36.] +my_func(x:int=1, y:float=2, z:float=3) +my_func(x:int=3, y:float=4, z:float=3) +my_func(x:int=5, y:float=6, z:float=3) +my_func(x:int=7, y:float=8, z:float=3) +my_func(x:int=9, y:float=10, z:float=3) +my_func(x:int=11, y:float=12, z:float=3) +[[ 6. 36. 90.] + [ 168. 270. 396.]] +[[ 6 36 90] + [168 270 396]] +my_func(x:int=1, y:float=2, z:float=2) +my_func(x:int=2, y:float=3, z:float=2) +my_func(x:int=3, y:float=4, z:float=2) +my_func(x:int=4, y:float=2, z:float=2) +my_func(x:int=5, y:float=3, z:float=2) +my_func(x:int=6, y:float=4, z:float=2) +[[ 4. 12. 24.] + [ 16. 30. 48.]] +[[ 4 12 24] + [16 30 48]] +my_func(x:int=1, y:float=2, z:float=2) +my_func(x:int=2, y:float=2, z:float=2) +my_func(x:int=3, y:float=2, z:float=2) +my_func(x:int=4, y:float=3, z:float=2) +my_func(x:int=5, y:float=3, z:float=2) +my_func(x:int=6, y:float=3, z:float=2) +[[ 4. 8. 12.] + [ 24. 30. 36.]] +[[ 4 8 12] + [24 30 36]] +my_func(x:int=1, y:float=2, z:float=3) +6.0 +my_func(x:int=1, y:float=2, z:float=3) +6.0 +my_func(x:int=1, y:float=2, z:float=3) +my_func(x:int=3, y:float=4, z:float=3) +[ 6. 36.] +my_func(x:int=1, y:float=2, z:float=3) +my_func(x:int=3, y:float=4, z:float=3) +my_func(x:int=5, y:float=6, z:float=3) +my_func(x:int=7, y:float=8, z:float=3) +my_func(x:int=9, y:float=10, z:float=3) +my_func(x:int=11, y:float=12, z:float=3) +[[ 6. 36. 90.] + [ 168. 270. 396.]] +[[ 6 36 90] + [168 270 396]] +my_func(x:int=1, y:float=2, z:float=2) +my_func(x:int=2, y:float=3, z:float=2) +my_func(x:int=3, y:float=4, z:float=2) +my_func(x:int=4, y:float=2, z:float=2) +my_func(x:int=5, y:float=3, z:float=2) +my_func(x:int=6, y:float=4, z:float=2) +[[ 4. 12. 24.] + [ 16. 30. 48.]] +[[ 4 12 24] + [16 30 48]] +my_func(x:int=1, y:float=2, z:float=2) +my_func(x:int=2, y:float=2, z:float=2) +my_func(x:int=3, y:float=2, z:float=2) +my_func(x:int=4, y:float=3, z:float=2) +my_func(x:int=5, y:float=3, z:float=2) +my_func(x:int=6, y:float=3, z:float=2) +[[ 4. 8. 12.] + [ 24. 30. 36.]] +[[ 4 8 12] + [24 30 36]] diff --git a/stormpy/resources/pybind11/example/example11.cpp b/stormpy/resources/pybind11/example/example11.cpp new file mode 100644 index 000000000..e7069def2 --- /dev/null +++ b/stormpy/resources/pybind11/example/example11.cpp @@ -0,0 +1,33 @@ +/* + example/example11.cpp -- keyword arguments and default values + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include + +void kw_func(int x, int y) { std::cout << "kw_func(x=" << x << ", y=" << y << ")" << std::endl; } + +void kw_func4(const std::vector &entries) { + std::cout << "kw_func4: "; + for (int i : entries) + std::cout << i << " "; + std::cout << endl; +} + +void init_ex11(py::module &m) { + m.def("kw_func", &kw_func, py::arg("x"), py::arg("y")); + m.def("kw_func2", &kw_func, py::arg("x") = 100, py::arg("y") = 200); + m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!")); + + /* A fancier default argument */ + std::vector list; + list.push_back(13); + list.push_back(17); + + m.def("kw_func4", &kw_func4, py::arg("myList") = list); +} diff --git a/stormpy/resources/pybind11/example/example11.py b/stormpy/resources/pybind11/example/example11.py new file mode 100755 index 000000000..04baa7bc9 --- /dev/null +++ b/stormpy/resources/pybind11/example/example11.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +import pydoc + +sys.path.append('.') + +from example import kw_func, kw_func2, kw_func3, kw_func4 + +print(pydoc.render_doc(kw_func, "Help on %s")) +print(pydoc.render_doc(kw_func2, "Help on %s")) +print(pydoc.render_doc(kw_func3, "Help on %s")) +print(pydoc.render_doc(kw_func4, "Help on %s")) + +kw_func(5, 10) +kw_func(5, y=10) +kw_func(y=10, x=5) + +kw_func2() + +kw_func2(5) +kw_func2(x=5) + +kw_func2(y=10) + +kw_func2(5, 10) +kw_func2(x=5, y=10) + +try: + kw_func2(x=5, y=10, z=12) +except Exception as e: + print("Caught expected exception: " + str(e)) + +kw_func4() +kw_func4(myList = [1, 2, 3]) diff --git a/stormpy/resources/pybind11/example/example11.ref b/stormpy/resources/pybind11/example/example11.ref new file mode 100644 index 000000000..54e4fef31 --- /dev/null +++ b/stormpy/resources/pybind11/example/example11.ref @@ -0,0 +1,34 @@ +Help on built-in function kw_func in module example + +kkww__ffuunncc(...) + kw_func(x : int, y : int) -> NoneType + +Help on built-in function kw_func2 in module example + +kkww__ffuunncc22(...) + kw_func2(x : int = 100L, y : int = 200L) -> NoneType + +Help on built-in function kw_func3 in module example + +kkww__ffuunncc33(...) + kw_func3(data : unicode = u'Hello world!') -> NoneType + +Help on built-in function kw_func4 in module example + +kkww__ffuunncc44(...) + kw_func4(myList : list = [13L, 17L]) -> NoneType + +kw_func(x=5, y=10) +kw_func(x=5, y=10) +kw_func(x=5, y=10) +kw_func(x=100, y=200) +kw_func(x=5, y=200) +kw_func(x=5, y=200) +kw_func(x=100, y=10) +kw_func(x=5, y=10) +kw_func(x=5, y=10) +Caught expected exception: Incompatible function arguments. The following argument types are supported: + 1. (x : int = 100L, y : int = 200L) -> NoneType + +kw_func4: 13 17 +kw_func4: 1 2 3 diff --git a/stormpy/resources/pybind11/example/example12.cpp b/stormpy/resources/pybind11/example/example12.cpp new file mode 100644 index 000000000..ab1b48294 --- /dev/null +++ b/stormpy/resources/pybind11/example/example12.cpp @@ -0,0 +1,98 @@ +/* + example/example12.cpp -- overriding virtual functions from Python + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include + +/* This is an example class that we'll want to be able to extend from Python */ +class Example12 { +public: + Example12(int state) : state(state) { + cout << "Constructing Example12.." << endl; + } + + ~Example12() { + cout << "Destructing Example12.." << endl; + } + + virtual int run(int value) { + std::cout << "Original implementation of Example12::run(state=" << state + << ", value=" << value << ")" << std::endl; + return state + value; + } + + virtual bool run_bool() = 0; + virtual void pure_virtual() = 0; +private: + int state; +}; + +/* This is a wrapper class that must be generated */ +class PyExample12 : public Example12 { +public: + using Example12::Example12; /* Inherit constructors */ + + virtual int run(int value) { + /* Generate wrapping code that enables native function overloading */ + PYBIND11_OVERLOAD( + int, /* Return type */ + Example12, /* Parent class */ + run, /* Name of function */ + value /* Argument(s) */ + ); + } + + virtual bool run_bool() { + PYBIND11_OVERLOAD_PURE( + bool, + Example12, + run_bool + ); + throw std::runtime_error("this will never be reached"); + } + + virtual void pure_virtual() { + PYBIND11_OVERLOAD_PURE( + void, /* Return type */ + Example12, /* Parent class */ + pure_virtual /* Name of function */ + /* This function has no arguments */ + ); + } +}; + +int runExample12(Example12 *ex, int value) { + return ex->run(value); +} + +bool runExample12Bool(Example12* ex) { + return ex->run_bool(); +} + +void runExample12Virtual(Example12 *ex) { + ex->pure_virtual(); +} + +void init_ex12(py::module &m) { + /* Important: use the wrapper type as a template + argument to class_<>, but use the original name + to denote the type */ + py::class_(m, "Example12") + /* Declare that 'PyExample12' is really an alias for the original type 'Example12' */ + .alias() + .def(py::init()) + /* Reference original class in function definitions */ + .def("run", &Example12::run) + .def("run_bool", &Example12::run_bool) + .def("pure_virtual", &Example12::pure_virtual); + + m.def("runExample12", &runExample12); + m.def("runExample12Bool", &runExample12Bool); + m.def("runExample12Virtual", &runExample12Virtual); +} diff --git a/stormpy/resources/pybind11/example/example12.py b/stormpy/resources/pybind11/example/example12.py new file mode 100644 index 000000000..eb175239f --- /dev/null +++ b/stormpy/resources/pybind11/example/example12.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import Example12, runExample12, runExample12Virtual, runExample12Bool + + +class ExtendedExample12(Example12): + def __init__(self, state): + super(ExtendedExample12, self).__init__(state + 1) + self.data = "Hello world" + + def run(self, value): + print('ExtendedExample12::run(%i), calling parent..' % value) + return super(ExtendedExample12, self).run(value + 1) + + def run_bool(self): + print('ExtendedExample12::run_bool()') + return False + + def pure_virtual(self): + print('ExtendedExample12::pure_virtual(): %s' % self.data) + + +ex12 = Example12(10) +print(runExample12(ex12, 20)) +try: + runExample12Virtual(ex12) +except Exception as e: + print("Caught expected exception: " + str(e)) + +ex12p = ExtendedExample12(10) +print(runExample12(ex12p, 20)) +print(runExample12Bool(ex12p)) +runExample12Virtual(ex12p) diff --git a/stormpy/resources/pybind11/example/example12.ref b/stormpy/resources/pybind11/example/example12.ref new file mode 100644 index 000000000..2274cddd2 --- /dev/null +++ b/stormpy/resources/pybind11/example/example12.ref @@ -0,0 +1,13 @@ +Constructing Example12.. +Original implementation of Example12::run(state=10, value=20) +30 +Caught expected exception: Tried to call pure virtual function "pure_virtual" +Constructing Example12.. +ExtendedExample12::run(20), calling parent.. +Original implementation of Example12::run(state=11, value=21) +32 +ExtendedExample12::run_bool() +False +ExtendedExample12::pure_virtual(): Hello world +Destructing Example12.. +Destructing Example12.. diff --git a/stormpy/resources/pybind11/example/example13.cpp b/stormpy/resources/pybind11/example/example13.cpp new file mode 100644 index 000000000..782db3109 --- /dev/null +++ b/stormpy/resources/pybind11/example/example13.cpp @@ -0,0 +1,37 @@ +/* + example/example13.cpp -- keep_alive modifier (pybind11's version + of Boost.Python's with_custodian_and_ward / with_custodian_and_ward_postcall) + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +class Child { +public: + Child() { std::cout << "Allocating child." << std::endl; } + ~Child() { std::cout << "Releasing child." << std::endl; } +}; + +class Parent { +public: + Parent() { std::cout << "Allocating parent." << std::endl; } + ~Parent() { std::cout << "Releasing parent." << std::endl; } + void addChild(Child *) { } + Child *returnChild() { return new Child(); } +}; + +void init_ex13(py::module &m) { + py::class_(m, "Parent") + .def(py::init<>()) + .def("addChild", &Parent::addChild) + .def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>()) + .def("returnChild", &Parent::returnChild) + .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()); + + py::class_(m, "Child") + .def(py::init<>()); +} diff --git a/stormpy/resources/pybind11/example/example13.py b/stormpy/resources/pybind11/example/example13.py new file mode 100644 index 000000000..ad0176ed4 --- /dev/null +++ b/stormpy/resources/pybind11/example/example13.py @@ -0,0 +1,46 @@ +from __future__ import print_function +import sys +import gc +sys.path.append('.') + +from example import Parent, Child + +if True: + p = Parent() + p.addChild(Child()) + gc.collect() + print(p) + p = None + +gc.collect() +print("") + +if True: + p = Parent() + p.returnChild() + gc.collect() + print(p) + p = None + +gc.collect() +print("") + +if True: + p = Parent() + p.addChildKeepAlive(Child()) + gc.collect() + print(p) + p = None +gc.collect() +print("") + +if True: + p = Parent() + p.returnChildKeepAlive() + gc.collect() + print(p) + p = None + +gc.collect() +print("") +print("Terminating..") diff --git a/stormpy/resources/pybind11/example/example13.ref b/stormpy/resources/pybind11/example/example13.ref new file mode 100644 index 000000000..7eb02c51f --- /dev/null +++ b/stormpy/resources/pybind11/example/example13.ref @@ -0,0 +1,25 @@ +Allocating parent. +Allocating child. +Releasing child. + +Releasing parent. + +Allocating parent. +Allocating child. +Releasing child. + +Releasing parent. + +Allocating parent. +Allocating child. + +Releasing parent. +Releasing child. + +Allocating parent. +Allocating child. + +Releasing parent. +Releasing child. + +Terminating.. diff --git a/stormpy/resources/pybind11/example/example14.cpp b/stormpy/resources/pybind11/example/example14.cpp new file mode 100644 index 000000000..abae02140 --- /dev/null +++ b/stormpy/resources/pybind11/example/example14.cpp @@ -0,0 +1,40 @@ +/* + example/example14.cpp -- opaque types, passing void pointers + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include +#include + +typedef std::vector StringList; + +void init_ex14(py::module &m) { + py::class_>(m, "StringList") + .def(py::init<>()) + .def("push_back", [](py::opaque &l, const std::string &str) { l->push_back(str); }) + .def("pop_back", [](py::opaque &l) { l->pop_back(); }) + .def("back", [](py::opaque &l) { return l->back(); }); + + m.def("print_opaque_list", [](py::opaque &_l) { + StringList &l = _l; + std::cout << "Opaque list: " << std::endl; + for (auto entry : l) + std::cout << " " << entry << std::endl; + }); + + m.def("return_void_ptr", []() { return (void *) 1234; }); + m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : " << (uint64_t) ptr << std::endl; }); + m.def("return_null_str", []() { return (char *) nullptr; }); + m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : " << (uint64_t) ptr << std::endl; }); + + m.def("return_unique_ptr", []() -> std::unique_ptr { + StringList *result = new StringList(); + result->push_back("some value"); + return std::unique_ptr(result); + }); +} diff --git a/stormpy/resources/pybind11/example/example14.py b/stormpy/resources/pybind11/example/example14.py new file mode 100644 index 000000000..82d14de84 --- /dev/null +++ b/stormpy/resources/pybind11/example/example14.py @@ -0,0 +1,24 @@ +from __future__ import print_function +import sys + +sys.path.append('.') + +from example import StringList, print_opaque_list +from example import return_void_ptr, print_void_ptr +from example import return_null_str, print_null_str +from example import return_unique_ptr + +l = StringList() +l.push_back("Element 1") +l.push_back("Element 2") +print_opaque_list(l) +print("Back element is %s" % l.back()) +l.pop_back() +print_opaque_list(l) + +print_void_ptr(return_void_ptr()) + +print(return_null_str()) +print_null_str(return_null_str()) + +print(return_unique_ptr()) diff --git a/stormpy/resources/pybind11/example/example14.ref b/stormpy/resources/pybind11/example/example14.ref new file mode 100644 index 000000000..b4768efe9 --- /dev/null +++ b/stormpy/resources/pybind11/example/example14.ref @@ -0,0 +1,10 @@ +Opaque list: + Element 1 + Element 2 +Back element is Element 2 +Opaque list: + Element 1 +Got void ptr : 1234 +None +Got null str : 0 +[u'some value'] diff --git a/stormpy/resources/pybind11/example/example15.cpp b/stormpy/resources/pybind11/example/example15.cpp new file mode 100644 index 000000000..bfc75268a --- /dev/null +++ b/stormpy/resources/pybind11/example/example15.cpp @@ -0,0 +1,51 @@ +/* + example/example15.cpp -- pickle support + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +class Pickleable { +public: + Pickleable(const std::string &value) : m_value(value) { } + const std::string &value() const { return m_value; } + + void setExtra1(int extra1) { m_extra1 = extra1; } + void setExtra2(int extra2) { m_extra2 = extra2; } + int extra1() const { return m_extra1; } + int extra2() const { return m_extra2; } +private: + std::string m_value; + int m_extra1 = 0; + int m_extra2 = 0; +}; + +void init_ex15(py::module &m) { + py::class_(m, "Pickleable") + .def(py::init()) + .def("value", &Pickleable::value) + .def("extra1", &Pickleable::extra1) + .def("extra2", &Pickleable::extra2) + .def("setExtra1", &Pickleable::setExtra1) + .def("setExtra2", &Pickleable::setExtra2) + // For details on the methods below, refer to + // http://docs.python.org/3/library/pickle.html#pickling-class-instances + .def("__getstate__", [](const Pickleable &p) { + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.value(), p.extra1(), p.extra2()); + }) + .def("__setstate__", [](Pickleable &p, py::tuple t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + /* Invoke the constructor (need to use in-place version) */ + new (&p) Pickleable(t[0].cast()); + + /* Assign any additional state */ + p.setExtra1(t[1].cast()); + p.setExtra2(t[2].cast()); + }); +} diff --git a/stormpy/resources/pybind11/example/example15.py b/stormpy/resources/pybind11/example/example15.py new file mode 100644 index 000000000..9868b62c2 --- /dev/null +++ b/stormpy/resources/pybind11/example/example15.py @@ -0,0 +1,21 @@ +from __future__ import print_function +import sys + +sys.path.append('.') + +from example import Pickleable + +try: + import cPickle as pickle # Use cPickle on Python 2.7 +except ImportError: + import pickle + +p = Pickleable("test_value") +p.setExtra1(15) +p.setExtra2(48) + +data = pickle.dumps(p, -1) # -1 is important (use highest protocol version) +print("%s %i %i" % (p.value(), p.extra1(), p.extra2())) + +p2 = pickle.loads(data) +print("%s %i %i" % (p2.value(), p2.extra1(), p2.extra2())) diff --git a/stormpy/resources/pybind11/example/example15.ref b/stormpy/resources/pybind11/example/example15.ref new file mode 100644 index 000000000..d804973a1 --- /dev/null +++ b/stormpy/resources/pybind11/example/example15.ref @@ -0,0 +1,2 @@ +test_value 15 48 +test_value 15 48 diff --git a/stormpy/resources/pybind11/example/example16.cpp b/stormpy/resources/pybind11/example/example16.cpp new file mode 100644 index 000000000..350435f57 --- /dev/null +++ b/stormpy/resources/pybind11/example/example16.cpp @@ -0,0 +1,24 @@ +/* + example/example16.cpp -- automatic upcasting for polymorphic types + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +struct BaseClass { virtual ~BaseClass() {} }; +struct DerivedClass1 : BaseClass { }; +struct DerivedClass2 : BaseClass { }; + +void init_ex16(py::module &m) { + py::class_(m, "BaseClass").def(py::init<>()); + py::class_(m, "DerivedClass1").def(py::init<>()); + py::class_(m, "DerivedClass2").def(py::init<>()); + + m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); }); + m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); }); + m.def("return_none", []() -> BaseClass* { return nullptr; }); +} diff --git a/stormpy/resources/pybind11/example/example16.py b/stormpy/resources/pybind11/example/example16.py new file mode 100644 index 000000000..b4bcb655d --- /dev/null +++ b/stormpy/resources/pybind11/example/example16.py @@ -0,0 +1,12 @@ +from __future__ import print_function +import sys + +sys.path.append('.') + +from example import return_class_1 +from example import return_class_2 +from example import return_none + +print(type(return_class_1()).__name__) +print(type(return_class_2()).__name__) +print(type(return_none()).__name__) diff --git a/stormpy/resources/pybind11/example/example16.ref b/stormpy/resources/pybind11/example/example16.ref new file mode 100644 index 000000000..96003367b --- /dev/null +++ b/stormpy/resources/pybind11/example/example16.ref @@ -0,0 +1,3 @@ +DerivedClass1 +DerivedClass2 +NoneType diff --git a/stormpy/resources/pybind11/example/example2.cpp b/stormpy/resources/pybind11/example/example2.cpp new file mode 100644 index 000000000..2d49286b1 --- /dev/null +++ b/stormpy/resources/pybind11/example/example2.cpp @@ -0,0 +1,172 @@ +/* + example/example2.cpp2 -- singleton design pattern, static functions and + variables, passing and interacting with Python types + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include + +#ifdef _WIN32 +# include +# include +#endif + +class Example2 { +public: + static Example2 *new_instance() { + return new Example2(); + } + ~Example2() { + std::cout << "Destructing Example2" << std::endl; + } + + /* Create and return a Python dictionary */ + py::dict get_dict() { + py::dict dict; + dict[py::str("key")] = py::str("value"); + return dict; + } + + /* Create and return a Python set */ + py::set get_set() { + py::set set; + set.add(py::str("key1")); + set.add(py::str("key2")); + return set; + } + + /* Create and return a C++ dictionary */ + std::map get_dict_2() { + std::map result; + result["key"] = "value"; + return result; + } + + /* Create and return a C++ set */ + std::set get_set_2() { + std::set result; + result.insert("key1"); + result.insert("key2"); + return result; + } + + /* Create, manipulate, and return a Python list */ + py::list get_list() { + py::list list; + list.append(py::str("value")); + cout << "Entry at positon 0: " << py::object(list[0]) << endl; + list[0] = py::str("overwritten"); + return list; + } + + /* C++ STL data types are automatically casted */ + std::vector get_list_2() { + std::vector list; + list.push_back(L"value"); + return list; + } + + /* C++ STL data types are automatically casted */ + std::array get_array() { + return std::array {{ "array entry 1" , "array entry 2"}}; + } + + /* Easily iterate over a dictionary using a C++11 range-based for loop */ + void print_dict(py::dict dict) { + for (auto item : dict) + std::cout << "key: " << item.first << ", value=" << item.second << std::endl; + } + + /* Easily iterate over a set using a C++11 range-based for loop */ + void print_set(py::set set) { + for (auto item : set) + std::cout << "key: " << item << std::endl; + } + + /* Easily iterate over a list using a C++11 range-based for loop */ + void print_list(py::list list) { + int index = 0; + for (auto item : list) + std::cout << "list item " << index++ << ": " << item << std::endl; + } + + /* STL data types (such as maps) are automatically casted from Python */ + void print_dict_2(const std::map &dict) { + for (auto item : dict) + std::cout << "key: " << item.first << ", value=" << item.second << std::endl; + } + + /* STL data types (such as sets) are automatically casted from Python */ + void print_set_2(const std::set &set) { + for (auto item : set) + std::cout << "key: " << item << std::endl; + } + + /* STL data types (such as vectors) are automatically casted from Python */ + void print_list_2(std::vector &list) { +#ifdef _WIN32 /* Can't easily mix cout and wcout on Windows */ + _setmode(_fileno(stdout), _O_TEXT); +#endif + int index = 0; + for (auto item : list) + std::wcout << L"list item " << index++ << L": " << item << std::endl; + } + + /* pybind automatically translates between C++11 and Python tuples */ + std::pair pair_passthrough(std::pair input) { + return std::make_pair(input.second, input.first); + } + + /* pybind automatically translates between C++11 and Python tuples */ + std::tuple tuple_passthrough(std::tuple input) { + return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input)); + } + + /* STL data types (such as arrays) are automatically casted from Python */ + void print_array(std::array &array) { + int index = 0; + for (auto item : array) + std::cout << "array item " << index++ << ": " << item << std::endl; + } + + void throw_exception() { + throw std::runtime_error("This exception was intentionally thrown."); + } + + static int value; + static const int value2; +}; + +int Example2::value = 0; +const int Example2::value2 = 5; + +void init_ex2(py::module &m) { + /* No constructor is explicitly defined below. An exception is raised when + trying to construct it directly from Python */ + py::class_(m, "Example2", "Example 2 documentation") + .def("get_dict", &Example2::get_dict, "Return a Python dictionary") + .def("get_dict_2", &Example2::get_dict_2, "Return a C++ dictionary") + .def("get_list", &Example2::get_list, "Return a Python list") + .def("get_list_2", &Example2::get_list_2, "Return a C++ list") + .def("get_set", &Example2::get_set, "Return a Python set") + .def("get_set2", &Example2::get_set, "Return a C++ set") + .def("get_array", &Example2::get_array, "Return a C++ array") + .def("print_dict", &Example2::print_dict, "Print entries of a Python dictionary") + .def("print_dict_2", &Example2::print_dict_2, "Print entries of a C++ dictionary") + .def("print_set", &Example2::print_set, "Print entries of a Python set") + .def("print_set_2", &Example2::print_set_2, "Print entries of a C++ set") + .def("print_list", &Example2::print_list, "Print entries of a Python list") + .def("print_list_2", &Example2::print_list_2, "Print entries of a C++ list") + .def("print_array", &Example2::print_array, "Print entries of a C++ array") + .def("pair_passthrough", &Example2::pair_passthrough, "Return a pair in reversed order") + .def("tuple_passthrough", &Example2::tuple_passthrough, "Return a triple in reversed order") + .def("throw_exception", &Example2::throw_exception, "Throw an exception") + .def_static("new_instance", &Example2::new_instance, "Return an instance") + .def_readwrite_static("value", &Example2::value, "Static value member") + .def_readonly_static("value2", &Example2::value2, "Static value member (readonly)"); +} diff --git a/stormpy/resources/pybind11/example/example2.py b/stormpy/resources/pybind11/example/example2.py new file mode 100755 index 000000000..d335acc3d --- /dev/null +++ b/stormpy/resources/pybind11/example/example2.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys, pydoc +sys.path.append('.') + +import example +from example import Example2 + +Example2.value = 15 +print(Example2.value) +print(Example2.value2) + +try: + Example2() +except Exception as e: + print(e) + +try: + Example2.value2 = 15 +except Exception as e: + print(e) + +instance = Example2.new_instance() + +dict_result = instance.get_dict() +dict_result['key2'] = 'value2' +instance.print_dict(dict_result) + +dict_result = instance.get_dict_2() +dict_result['key2'] = 'value2' +instance.print_dict_2(dict_result) + +set_result = instance.get_set() +set_result.add('key3') +instance.print_set(set_result) + +set_result = instance.get_set2() +set_result.add('key3') +instance.print_set_2(set_result) + +list_result = instance.get_list() +list_result.append('value2') +instance.print_list(list_result) + +list_result = instance.get_list_2() +list_result.append('value2') +instance.print_list_2(list_result) + +array_result = instance.get_array() +print(array_result) +instance.print_array(array_result) + +try: + instance.throw_exception() +except Exception as e: + print(e) + +print(instance.pair_passthrough((True, "test"))) +print(instance.tuple_passthrough((True, "test", 5))) + +print(pydoc.render_doc(Example2, "Help on %s")) + +print("__name__(example) = %s" % example.__name__) +print("__name__(example.Example2) = %s" % Example2.__name__) +print("__module__(example.Example2) = %s" % Example2.__module__) +print("__name__(example.Example2.get_set) = %s" % Example2.get_set.__name__) +print("__module__(example.Example2.get_set) = %s" % Example2.get_set.__module__) diff --git a/stormpy/resources/pybind11/example/example2.ref b/stormpy/resources/pybind11/example/example2.ref new file mode 100644 index 000000000..fd6c83dda --- /dev/null +++ b/stormpy/resources/pybind11/example/example2.ref @@ -0,0 +1,137 @@ +15 +5 +example.Example2: No constructor defined! +can't set attribute +key: key2, value=value2 +key: key, value=value +key: key, value=value +key: key2, value=value2 +key: key3 +key: key2 +key: key1 +key: key1 +key: key2 +key: key3 +Entry at positon 0: value +list item 0: overwritten +list item 1: value2 +list item 0: value +list item 1: value2 +[u'array entry 1', u'array entry 2'] +array item 0: array entry 1 +array item 1: array entry 2 +This exception was intentionally thrown. +(u'test', True) +(5L, u'test', True) +Help on class Example2 in module example + +class EExxaammppllee22(__builtin__.object) + | Example 2 documentation + | + | Methods defined here: + | + | ____iinniitt____(...) + | x.__init__(...) initializes x; see help(type(x)) for signature + | + | ggeett__aarrrraayy(...) + | Signature : (example.Example2) -> list[2] + | + | Return a C++ array + | + | ggeett__ddiicctt(...) + | Signature : (example.Example2) -> dict + | + | Return a Python dictionary + | + | ggeett__ddiicctt__22(...) + | Signature : (example.Example2) -> dict + | + | Return a C++ dictionary + | + | ggeett__lliisstt(...) + | Signature : (example.Example2) -> list + | + | Return a Python list + | + | ggeett__lliisstt__22(...) + | Signature : (example.Example2) -> list + | + | Return a C++ list + | + | ggeett__sseett(...) + | Signature : (example.Example2) -> set + | + | Return a Python set + | + | ggeett__sseett22(...) + | Signature : (example.Example2) -> set + | + | Return a C++ set + | + | ppaaiirr__ppaasssstthhrroouugghh(...) + | Signature : (example.Example2, (bool, unicode)) -> (unicode, bool) + | + | Return a pair in reversed order + | + | pprriinntt__aarrrraayy(...) + | Signature : (example.Example2, list[2]) -> NoneType + | + | Print entries of a C++ array + | + | pprriinntt__ddiicctt(...) + | Signature : (example.Example2, dict) -> NoneType + | + | Print entries of a Python dictionary + | + | pprriinntt__ddiicctt__22(...) + | Signature : (example.Example2, dict) -> NoneType + | + | Print entries of a C++ dictionary + | + | pprriinntt__lliisstt(...) + | Signature : (example.Example2, list) -> NoneType + | + | Print entries of a Python list + | + | pprriinntt__lliisstt__22(...) + | Signature : (example.Example2, list) -> NoneType + | + | Print entries of a C++ list + | + | pprriinntt__sseett(...) + | Signature : (example.Example2, set) -> NoneType + | + | Print entries of a Python set + | + | pprriinntt__sseett__22(...) + | Signature : (example.Example2, set) -> NoneType + | + | Print entries of a C++ set + | + | tthhrrooww__eexxcceeppttiioonn(...) + | Signature : (example.Example2) -> NoneType + | + | Throw an exception + | + | ttuuppllee__ppaasssstthhrroouugghh(...) + | Signature : (example.Example2, (bool, unicode, int)) -> (int, unicode, bool) + | + | Return a triple in reversed order + | + | ---------------------------------------------------------------------- + | Data and other attributes defined here: + | + | ____nneeww____ = + | T.__new__(S, ...) -> a new object with type S, a subtype of T + | + | nneeww__iinnssttaannccee = + | Signature : () -> example.Example2 + | + | Return an instance + +__name__(example) = example +__name__(example.Example2) = Example2 +__module__(example.Example2) = example +__name__(example.Example2.get_set) = get_set +__module__(example.Example2.get_set) = example +Destructing Example2 diff --git a/stormpy/resources/pybind11/example/example3.cpp b/stormpy/resources/pybind11/example/example3.cpp new file mode 100644 index 000000000..3b3a6253e --- /dev/null +++ b/stormpy/resources/pybind11/example/example3.cpp @@ -0,0 +1,75 @@ +/* + example/example3.cpp -- operator overloading + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include + +class Vector2 { +public: + Vector2(float x, float y) : x(x), y(y) { std::cout << "Value constructor" << std::endl; } + Vector2(const Vector2 &v) : x(v.x), y(v.y) { std::cout << "Copy constructor" << std::endl; } + Vector2(Vector2 &&v) : x(v.x), y(v.y) { std::cout << "Move constructor" << std::endl; v.x = v.y = 0; } + ~Vector2() { std::cout << "Destructor." << std::endl; } + + std::string toString() const { + return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; + } + + void operator=(const Vector2 &v) { + cout << "Assignment operator" << endl; + x = v.x; + y = v.y; + } + + void operator=(Vector2 &&v) { + cout << "Move assignment operator" << endl; + x = v.x; y = v.y; v.x = v.y = 0; + } + + Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } + Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); } + Vector2 operator-(float value) const { return Vector2(x - value, y - value); } + Vector2 operator+(float value) const { return Vector2(x + value, y + value); } + Vector2 operator*(float value) const { return Vector2(x * value, y * value); } + Vector2 operator/(float value) const { return Vector2(x / value, y / value); } + Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } + Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; } + Vector2& operator*=(float v) { x *= v; y *= v; return *this; } + Vector2& operator/=(float v) { x /= v; y /= v; return *this; } + + friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); } + friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); } + friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } + friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); } +private: + float x, y; +}; + + +void init_ex3(py::module &m) { + py::class_(m, "Vector2") + .def(py::init()) + .def(py::self + py::self) + .def(py::self + float()) + .def(py::self - py::self) + .def(py::self - float()) + .def(py::self * float()) + .def(py::self / float()) + .def(py::self += py::self) + .def(py::self -= py::self) + .def(py::self *= float()) + .def(py::self /= float()) + .def(float() + py::self) + .def(float() - py::self) + .def(float() * py::self) + .def(float() / py::self) + .def("__str__", &Vector2::toString); + + m.attr("Vector") = m.attr("Vector2"); +} diff --git a/stormpy/resources/pybind11/example/example3.py b/stormpy/resources/pybind11/example/example3.py new file mode 100755 index 000000000..591ae391c --- /dev/null +++ b/stormpy/resources/pybind11/example/example3.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import Vector2, Vector + +v1 = Vector2(1, 2) +v2 = Vector(3, -1) + +print("v1 = " + str(v1)) +print("v2 = " + str(v2)) +print("v1+v2 = " + str(v1+v2)) +print("v1-v2 = " + str(v1-v2)) +print("v1-8 = " + str(v1-8)) +print("v1+8 = " + str(v1+8)) +print("v1*8 = " + str(v1*8)) +print("v1/8 = " + str(v1/8)) +print("8-v1 = " + str(8-v1)) +print("8+v1 = " + str(8+v1)) +print("8*v1 = " + str(8*v1)) +print("8/v1 = " + str(8/v1)) + +v1 += v2 +v1 *= 2 + +print("(v1+v2)*2 = " + str(v1)) diff --git a/stormpy/resources/pybind11/example/example3.ref b/stormpy/resources/pybind11/example/example3.ref new file mode 100644 index 000000000..698b5ad6e --- /dev/null +++ b/stormpy/resources/pybind11/example/example3.ref @@ -0,0 +1,57 @@ +Value constructor +Value constructor +v1 = [1.000000, 2.000000] +v2 = [3.000000, -1.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +v1+v2 = [4.000000, 1.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +v1-v2 = [-2.000000, 3.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +v1-8 = [-7.000000, -6.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +v1+8 = [9.000000, 10.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +v1*8 = [8.000000, 16.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +v1/8 = [0.125000, 0.250000] +Value constructor +Copy constructor +Destructor. +Destructor. +8-v1 = [7.000000, 6.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +8+v1 = [9.000000, 10.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +8*v1 = [8.000000, 16.000000] +Value constructor +Copy constructor +Destructor. +Destructor. +8/v1 = [8.000000, 4.000000] +(v1+v2)*2 = [8.000000, 2.000000] +Destructor. +Destructor. diff --git a/stormpy/resources/pybind11/example/example4.cpp b/stormpy/resources/pybind11/example/example4.cpp new file mode 100644 index 000000000..e673c4a81 --- /dev/null +++ b/stormpy/resources/pybind11/example/example4.cpp @@ -0,0 +1,75 @@ +/* + example/example4.cpp -- global constants and functions, enumerations, raw byte strings + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +enum EMyEnumeration { + EFirstEntry = 1, + ESecondEntry +}; + +class Example4 { +public: + enum EMode { + EFirstMode = 1, + ESecondMode + }; + + static EMode test_function(EMode mode) { + std::cout << "Example4::test_function(enum=" << mode << ")" << std::endl; + return mode; + } +}; + +bool test_function1() { + std::cout << "test_function()" << std::endl; + return false; +} + +void test_function2(EMyEnumeration k) { + std::cout << "test_function(enum=" << k << ")" << std::endl; +} + +float test_function3(int i) { + std::cout << "test_function(" << i << ")" << std::endl; + return i / 2.f; +} + +py::bytes return_bytes() { + const char *data = "\x01\x00\x02\x00"; + return std::string(data, 4); +} + +void print_bytes(py::bytes bytes) { + std::string value = (std::string) bytes; + for (size_t i = 0; i < value.length(); ++i) + std::cout << "bytes[" << i << "]=" << (int) value[i] << std::endl; +} + +void init_ex4(py::module &m) { + m.def("test_function", &test_function1); + m.def("test_function", &test_function2); + m.def("test_function", &test_function3); + m.attr("some_constant") = py::int_(14); + + py::enum_(m, "EMyEnumeration") + .value("EFirstEntry", EFirstEntry) + .value("ESecondEntry", ESecondEntry) + .export_values(); + + py::class_ ex4_class(m, "Example4"); + ex4_class.def_static("test_function", &Example4::test_function); + py::enum_(ex4_class, "EMode") + .value("EFirstMode", Example4::EFirstMode) + .value("ESecondMode", Example4::ESecondMode) + .export_values(); + + m.def("return_bytes", &return_bytes); + m.def("print_bytes", &print_bytes); +} diff --git a/stormpy/resources/pybind11/example/example4.py b/stormpy/resources/pybind11/example/example4.py new file mode 100755 index 000000000..37d952f2b --- /dev/null +++ b/stormpy/resources/pybind11/example/example4.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import test_function +from example import some_constant +from example import EMyEnumeration +from example import EFirstEntry +from example import Example4 +from example import return_bytes +from example import print_bytes + +print(EMyEnumeration) +print(EMyEnumeration.EFirstEntry) +print(EMyEnumeration.ESecondEntry) +print(EFirstEntry) + +print(test_function()) +print(test_function(7)) +print(test_function(EMyEnumeration.EFirstEntry)) +print(test_function(EMyEnumeration.ESecondEntry)) +print("enum->integer = %i" % int(EMyEnumeration.ESecondEntry)) +print("integer->enum = %s" % str(EMyEnumeration(2))) + +print("A constant = " + str(some_constant)) + +print(Example4.EMode) +print(Example4.EMode.EFirstMode) +print(Example4.EFirstMode) +Example4.test_function(Example4.EFirstMode) + +print("Equality test 1: " + str( + Example4.test_function(Example4.EFirstMode) == + Example4.test_function(Example4.EFirstMode))) + +print("Inequality test 1: " + str( + Example4.test_function(Example4.EFirstMode) != + Example4.test_function(Example4.EFirstMode))) + +print("Equality test 2: " + str( + Example4.test_function(Example4.EFirstMode) == + Example4.test_function(Example4.ESecondMode))) + +print("Inequality test 2: " + str( + Example4.test_function(Example4.EFirstMode) != + Example4.test_function(Example4.ESecondMode))) + +x = { + Example4.test_function(Example4.EFirstMode): 1, + Example4.test_function(Example4.ESecondMode): 2 +} + +x[Example4.test_function(Example4.EFirstMode)] = 3 +x[Example4.test_function(Example4.ESecondMode)] = 4 +print("Hashing test = " + str(x)) + +print_bytes(return_bytes()) diff --git a/stormpy/resources/pybind11/example/example4.ref b/stormpy/resources/pybind11/example/example4.ref new file mode 100644 index 000000000..a21f62c93 --- /dev/null +++ b/stormpy/resources/pybind11/example/example4.ref @@ -0,0 +1,40 @@ + +EMyEnumeration.EFirstEntry +EMyEnumeration.ESecondEntry +EMyEnumeration.EFirstEntry +test_function() +False +test_function(7) +3.5 +test_function(enum=1) +None +test_function(enum=2) +None +enum->integer = 2 +integer->enum = EMyEnumeration.ESecondEntry +A constant = 14 + +EMode.EFirstMode +EMode.EFirstMode +Example4::test_function(enum=1) +Example4::test_function(enum=1) +Example4::test_function(enum=1) +Equality test 1: True +Example4::test_function(enum=1) +Example4::test_function(enum=1) +Inequality test 1: False +Example4::test_function(enum=1) +Example4::test_function(enum=2) +Equality test 2: False +Example4::test_function(enum=1) +Example4::test_function(enum=2) +Inequality test 2: True +Example4::test_function(enum=1) +Example4::test_function(enum=2) +Example4::test_function(enum=1) +Example4::test_function(enum=2) +Hashing test = {EMode.EFirstMode: 3, EMode.ESecondMode: 4} +bytes[0]=1 +bytes[1]=0 +bytes[2]=2 +bytes[3]=0 diff --git a/stormpy/resources/pybind11/example/example5.cpp b/stormpy/resources/pybind11/example/example5.cpp new file mode 100644 index 000000000..ad24ef069 --- /dev/null +++ b/stormpy/resources/pybind11/example/example5.cpp @@ -0,0 +1,110 @@ +/* + example/example5.cpp -- inheritance, callbacks, acquiring and releasing the + global interpreter lock + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include + + +class Pet { +public: + Pet(const std::string &name, const std::string &species) + : m_name(name), m_species(species) {} + std::string name() const { return m_name; } + std::string species() const { return m_species; } +private: + std::string m_name; + std::string m_species; +}; + +class Dog : public Pet { +public: + Dog(const std::string &name) : Pet(name, "dog") {} + void bark() const { std::cout << "Woof!" << std::endl; } +}; + +class Rabbit : public Pet { +public: + Rabbit(const std::string &name) : Pet(name, "parrot") {} +}; + +void pet_print(const Pet &pet) { + std::cout << pet.name() + " is a " + pet.species() << std::endl; +} + +void dog_bark(const Dog &dog) { + dog.bark(); +} + +bool test_callback1(py::object func) { + func.call(); + return false; +} + +int test_callback2(py::object func) { + py::object result = func.call("Hello", 'x', true, 5); + return result.cast(); +} + +void test_callback3(const std::function &func) { + cout << "func(43) = " << func(43)<< std::endl; +} + +std::function test_callback4() { + return [](int i) { return i+1; }; +} + +void init_ex5(py::module &m) { + py::class_ pet_class(m, "Pet"); + pet_class + .def(py::init()) + .def("name", &Pet::name) + .def("species", &Pet::species); + + /* One way of declaring a subclass relationship: reference parent's class_ object */ + py::class_(m, "Dog", pet_class) + .def(py::init()); + + /* Another way of declaring a subclass relationship: reference parent's C++ type */ + py::class_(m, "Rabbit", py::base()) + .def(py::init()); + + m.def("pet_print", pet_print); + m.def("dog_bark", dog_bark); + + m.def("test_callback1", &test_callback1); + m.def("test_callback2", &test_callback2); + m.def("test_callback3", &test_callback3); + m.def("test_callback4", &test_callback4); + + /* Test cleanup of lambda closure */ + + struct Payload { + Payload() { + std::cout << "Payload constructor" << std::endl; + } + ~Payload() { + std::cout << "Payload destructor" << std::endl; + } + Payload(const Payload &) { + std::cout << "Payload copy constructor" << std::endl; + } + Payload(Payload &&) { + std::cout << "Payload move constructor" << std::endl; + } + }; + + m.def("test_cleanup", []() -> std::function { + Payload p; + + return [p]() { + /* p should be cleaned up when the returned function is garbage collected */ + }; + }); +} diff --git a/stormpy/resources/pybind11/example/example5.py b/stormpy/resources/pybind11/example/example5.py new file mode 100755 index 000000000..ef90cfd07 --- /dev/null +++ b/stormpy/resources/pybind11/example/example5.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +from __future__ import print_function +from functools import partial +import sys +sys.path.append('.') + +from example import Pet +from example import Dog +from example import Rabbit +from example import dog_bark +from example import pet_print + +polly = Pet('Polly', 'parrot') +molly = Dog('Molly') +roger = Rabbit('Rabbit') +print(roger.name() + " is a " + roger.species()) +pet_print(roger) +print(polly.name() + " is a " + polly.species()) +pet_print(polly) +print(molly.name() + " is a " + molly.species()) +pet_print(molly) +dog_bark(molly) +try: + dog_bark(polly) +except Exception as e: + print('The following error is expected: ' + str(e)) + +from example import test_callback1 +from example import test_callback2 +from example import test_callback3 +from example import test_callback4 +from example import test_cleanup + +def func1(): + print('Callback function 1 called!') + +def func2(a, b, c, d): + print('Callback function 2 called : ' + str(a) + ", " + str(b) + ", " + str(c) + ", "+ str(d)) + return d + +def func3(a): + print('Callback function 3 called : ' + str(a)) + +print(test_callback1(func1)) +print(test_callback2(func2)) +print(test_callback1(partial(func2, "Hello", "from", "partial", "object"))) +print(test_callback1(partial(func3, "Partial object with one argument"))) + +test_callback3(lambda i: i + 1) +f = test_callback4() +print("func(43) = %i" % f(43)) + +test_cleanup() diff --git a/stormpy/resources/pybind11/example/example5.ref b/stormpy/resources/pybind11/example/example5.ref new file mode 100644 index 000000000..bfc3cb26e --- /dev/null +++ b/stormpy/resources/pybind11/example/example5.ref @@ -0,0 +1,26 @@ +Rabbit is a parrot +Polly is a parrot +Molly is a dog +Woof! +func(43) = 44 +Payload constructor +Payload copy constructor +Payload move constructor +Payload destructor +Payload destructor +Payload destructor +Rabbit is a parrot +Polly is a parrot +Molly is a dog +The following error is expected: Incompatible function arguments. The following argument types are supported: + 1. (example.Dog) -> NoneType + +Callback function 1 called! +False +Callback function 2 called : Hello, x, True, 5 +5 +Callback function 2 called : Hello, from, partial, object +False +Callback function 3 called : Partial object with one argument +False +func(43) = 44 diff --git a/stormpy/resources/pybind11/example/example6.cpp b/stormpy/resources/pybind11/example/example6.cpp new file mode 100644 index 000000000..89db2fbab --- /dev/null +++ b/stormpy/resources/pybind11/example/example6.cpp @@ -0,0 +1,186 @@ +/* + example/example6.cpp -- supporting Pythons' sequence protocol, iterators, + etc. + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include +#include + +class Sequence { +public: + Sequence(size_t size) : m_size(size) { + std::cout << "Value constructor: Creating a sequence with " << m_size << " entries" << std::endl; + m_data = new float[size]; + memset(m_data, 0, sizeof(float) * size); + } + + Sequence(const std::vector &value) : m_size(value.size()) { + std::cout << "Value constructor: Creating a sequence with " << m_size << " entries" << std::endl; + m_data = new float[m_size]; + memcpy(m_data, &value[0], sizeof(float) * m_size); + } + + Sequence(const Sequence &s) : m_size(s.m_size) { + std::cout << "Copy constructor: Creating a sequence with " << m_size << " entries" << std::endl; + m_data = new float[m_size]; + memcpy(m_data, s.m_data, sizeof(float)*m_size); + } + + Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) { + std::cout << "Move constructor: Creating a sequence with " << m_size << " entries" << std::endl; + s.m_size = 0; + s.m_data = nullptr; + } + + ~Sequence() { + std::cout << "Freeing a sequence with " << m_size << " entries" << std::endl; + delete[] m_data; + } + + Sequence &operator=(const Sequence &s) { + std::cout << "Assignment operator: Creating a sequence with " << s.m_size << " entries" << std::endl; + delete[] m_data; + m_size = s.m_size; + m_data = new float[m_size]; + memcpy(m_data, s.m_data, sizeof(float)*m_size); + return *this; + } + + Sequence &operator=(Sequence &&s) { + std::cout << "Move assignment operator: Creating a sequence with " << s.m_size << " entries" << std::endl; + if (&s != this) { + delete[] m_data; + m_size = s.m_size; + m_data = s.m_data; + s.m_size = 0; + s.m_data = nullptr; + } + return *this; + } + + bool operator==(const Sequence &s) const { + if (m_size != s.size()) + return false; + for (size_t i=0; i seq(m, "Sequence"); + + seq.def(py::init()) + .def(py::init&>()) + /// Bare bones interface + .def("__getitem__", [](const Sequence &s, size_t i) { + if (i >= s.size()) + throw py::index_error(); + return s[i]; + }) + .def("__setitem__", [](Sequence &s, size_t i, float v) { + if (i >= s.size()) + throw py::index_error(); + s[i] = v; + }) + .def("__len__", &Sequence::size) + /// Optional sequence protocol operations + .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, + py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) + .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) + .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) + /// Slicing protocol (optional) + .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* { + py::ssize_t start, stop, step, slicelength; + if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + Sequence *seq = new Sequence(slicelength); + for (int i=0; i(seq, "Iterator") + .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; }) + .def("__next__", &PySequenceIterator::next); + + On the actual Sequence object, the iterator would be constructed as follows: + .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast(), s); }) +#endif +} diff --git a/stormpy/resources/pybind11/example/example6.py b/stormpy/resources/pybind11/example/example6.py new file mode 100755 index 000000000..5a014dda9 --- /dev/null +++ b/stormpy/resources/pybind11/example/example6.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import Sequence + +s = Sequence(5) +print("s = " + str(s)) +print("len(s) = " + str(len(s))) +print("s[0], s[3] = %f %f" % (s[0], s[3])) +print('12.34 in s: ' + str(12.34 in s)) +s[0], s[3] = 12.34, 56.78 +print('12.34 in s: ' + str(12.34 in s)) +print("s[0], s[3] = %f %f" % (s[0], s[3])) +rev = reversed(s) +rev2 = s[::-1] +print("rev[0], rev[1], rev[2], rev[3], rev[4] = %f %f %f %f %f" % (rev[0], rev[1], rev[2], rev[3], rev[4])) + +for i in rev: + print(i, end=' ') +print('') +for i in rev2: + print(i, end=' ') +print('') +print(rev == rev2) +rev[0::2] = Sequence([2.0, 2.0, 2.0]) +for i in rev: + print(i, end=' ') +print('') diff --git a/stormpy/resources/pybind11/example/example6.ref b/stormpy/resources/pybind11/example/example6.ref new file mode 100644 index 000000000..bc369023f --- /dev/null +++ b/stormpy/resources/pybind11/example/example6.ref @@ -0,0 +1,21 @@ +Value constructor: Creating a sequence with 5 entries +s = +len(s) = 5 +s[0], s[3] = 0.000000 0.000000 +12.34 in s: False +12.34 in s: True +s[0], s[3] = 12.340000 56.779999 +Value constructor: Creating a sequence with 5 entries +Copy constructor: Creating a sequence with 5 entries +Freeing a sequence with 5 entries +Value constructor: Creating a sequence with 5 entries +rev[0], rev[1], rev[2], rev[3], rev[4] = 0.000000 56.779999 0.000000 0.000000 12.340000 +0.0 56.7799987793 0.0 0.0 12.3400001526 +0.0 56.7799987793 0.0 0.0 12.3400001526 +True +Value constructor: Creating a sequence with 3 entries +Freeing a sequence with 3 entries +2.0 56.7799987793 2.0 0.0 2.0 +Freeing a sequence with 5 entries +Freeing a sequence with 5 entries +Freeing a sequence with 5 entries diff --git a/stormpy/resources/pybind11/example/example7.cpp b/stormpy/resources/pybind11/example/example7.cpp new file mode 100644 index 000000000..b68b55396 --- /dev/null +++ b/stormpy/resources/pybind11/example/example7.cpp @@ -0,0 +1,115 @@ +/* + example/example7.cpp -- supporting Pythons' buffer protocol + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +class Matrix { +public: + Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) { + std::cout << "Value constructor: Creating a " << rows << "x" << cols << " matrix " << std::endl; + m_data = new float[rows*cols]; + memset(m_data, 0, sizeof(float) * rows * cols); + } + + Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) { + std::cout << "Copy constructor: Creating a " << m_rows << "x" << m_cols << " matrix " << std::endl; + m_data = new float[m_rows * m_cols]; + memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols); + } + + Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { + std::cout << "Move constructor: Creating a " << m_rows << "x" << m_cols << " matrix " << std::endl; + s.m_rows = 0; + s.m_cols = 0; + s.m_data = nullptr; + } + + ~Matrix() { + std::cout << "Freeing a " << m_rows << "x" << m_cols << " matrix " << std::endl; + delete[] m_data; + } + + Matrix &operator=(const Matrix &s) { + std::cout << "Assignment operator : Creating a " << s.m_rows << "x" << s.m_cols << " matrix " << std::endl; + delete[] m_data; + m_rows = s.m_rows; + m_cols = s.m_cols; + m_data = new float[m_rows * m_cols]; + memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols); + return *this; + } + + Matrix &operator=(Matrix &&s) { + std::cout << "Move assignment operator : Creating a " << s.m_rows << "x" << s.m_cols << " matrix " << std::endl; + if (&s != this) { + delete[] m_data; + m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data; + s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr; + } + return *this; + } + + float operator()(size_t i, size_t j) const { + return m_data[i*m_cols + j]; + } + + float &operator()(size_t i, size_t j) { + return m_data[i*m_cols + j]; + } + + float *data() { return m_data; } + + size_t rows() const { return m_rows; } + size_t cols() const { return m_cols; } +private: + size_t m_rows; + size_t m_cols; + float *m_data; +}; + +void init_ex7(py::module &m) { + py::class_ mtx(m, "Matrix"); + + mtx.def(py::init()) + /// Construct from a buffer + .def("__init__", [](Matrix &v, py::buffer b) { + py::buffer_info info = b.request(); + if (info.format != py::format_descriptor::value() || info.ndim != 2) + throw std::runtime_error("Incompatible buffer format!"); + new (&v) Matrix(info.shape[0], info.shape[1]); + memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols()); + }) + + .def("rows", &Matrix::rows) + .def("cols", &Matrix::cols) + + /// Bare bones interface + .def("__getitem__", [](const Matrix &m, std::pair i) { + if (i.first >= m.rows() || i.second >= m.cols()) + throw py::index_error(); + return m(i.first, i.second); + }) + .def("__setitem__", [](Matrix &m, std::pair i, float v) { + if (i.first >= m.rows() || i.second >= m.cols()) + throw py::index_error(); + m(i.first, i.second) = v; + }) + /// Provide buffer access + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor::value(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }); +} diff --git a/stormpy/resources/pybind11/example/example7.py b/stormpy/resources/pybind11/example/example7.py new file mode 100755 index 000000000..62d330174 --- /dev/null +++ b/stormpy/resources/pybind11/example/example7.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import Matrix + +try: + import numpy as np +except ImportError: + print('NumPy missing') + exit(0) + +m = Matrix(5, 5) + +print(m[2, 3]) +m[2, 3] = 4 +print(m[2, 3]) + +m2 = np.array(m, copy=False) +print(m2) +print(m2[2, 3]) +m2[2, 3] = 5 +print(m[2, 3]) + +m3 = np.array([[1,2,3],[4,5,6]]).astype(np.float32) +print(m3) +m4 = Matrix(m3) +for i in range(m4.rows()): + for j in range(m4.cols()): + print(m4[i, j], end = ' ') + print() diff --git a/stormpy/resources/pybind11/example/example7.ref b/stormpy/resources/pybind11/example/example7.ref new file mode 100644 index 000000000..75db9633b --- /dev/null +++ b/stormpy/resources/pybind11/example/example7.ref @@ -0,0 +1,17 @@ +Value constructor: Creating a 5x5 matrix +0.0 +4.0 +[[ 0. 0. 0. 0. 0.] + [ 0. 0. 0. 0. 0.] + [ 0. 0. 0. 4. 0.] + [ 0. 0. 0. 0. 0.] + [ 0. 0. 0. 0. 0.]] +4.0 +5.0 +[[ 1. 2. 3.] + [ 4. 5. 6.]] +Value constructor: Creating a 2x3 matrix +1.0 2.0 3.0 +4.0 5.0 6.0 +Freeing a 2x3 matrix +Freeing a 5x5 matrix diff --git a/stormpy/resources/pybind11/example/example8.cpp b/stormpy/resources/pybind11/example/example8.cpp new file mode 100644 index 000000000..f492588bd --- /dev/null +++ b/stormpy/resources/pybind11/example/example8.cpp @@ -0,0 +1,147 @@ +/* + example/example8.cpp -- binding classes with custom reference counting, + implicit conversions between types + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" +#include "object.h" + +/// Custom object with builtin reference counting (see 'object.h' for the implementation) +class MyObject1 : public Object { +public: + MyObject1(int value) : value(value) { + std::cout << toString() << " constructor" << std::endl; + } + + std::string toString() const { + return "MyObject1[" + std::to_string(value) + "]"; + } + +protected: + virtual ~MyObject1() { + std::cout << toString() << " destructor" << std::endl; + } + +private: + int value; +}; + +/// Object managed by a std::shared_ptr<> +class MyObject2 { +public: + MyObject2(int value) : value(value) { + std::cout << toString() << " constructor" << std::endl; + } + + std::string toString() const { + return "MyObject2[" + std::to_string(value) + "]"; + } + + virtual ~MyObject2() { + std::cout << toString() << " destructor" << std::endl; + } + +private: + int value; +}; + +/// Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<> +class MyObject3 : public std::enable_shared_from_this { +public: + MyObject3(int value) : value(value) { + std::cout << toString() << " constructor" << std::endl; + } + + std::string toString() const { + return "MyObject3[" + std::to_string(value) + "]"; + } + + virtual ~MyObject3() { + std::cout << toString() << " destructor" << std::endl; + } + +private: + int value; +}; + +/// Make pybind aware of the ref-counted wrapper type (s) +PYBIND11_DECLARE_HOLDER_TYPE(T, ref); +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); + +Object *make_object_1() { return new MyObject1(1); } +ref make_object_2() { return new MyObject1(2); } + +MyObject1 *make_myobject1_1() { return new MyObject1(4); } +ref make_myobject1_2() { return new MyObject1(5); } + +MyObject2 *make_myobject2_1() { return new MyObject2(6); } +std::shared_ptr make_myobject2_2() { return std::make_shared(7); } + +MyObject3 *make_myobject3_1() { return new MyObject3(8); } +std::shared_ptr make_myobject3_2() { return std::make_shared(9); } + +void print_object_1(const Object *obj) { std::cout << obj->toString() << std::endl; } +void print_object_2(ref obj) { std::cout << obj->toString() << std::endl; } +void print_object_3(const ref &obj) { std::cout << obj->toString() << std::endl; } +void print_object_4(const ref *obj) { std::cout << (*obj)->toString() << std::endl; } + +void print_myobject1_1(const MyObject1 *obj) { std::cout << obj->toString() << std::endl; } +void print_myobject1_2(ref obj) { std::cout << obj->toString() << std::endl; } +void print_myobject1_3(const ref &obj) { std::cout << obj->toString() << std::endl; } +void print_myobject1_4(const ref *obj) { std::cout << (*obj)->toString() << std::endl; } + +void print_myobject2_1(const MyObject2 *obj) { std::cout << obj->toString() << std::endl; } +void print_myobject2_2(std::shared_ptr obj) { std::cout << obj->toString() << std::endl; } +void print_myobject2_3(const std::shared_ptr &obj) { std::cout << obj->toString() << std::endl; } +void print_myobject2_4(const std::shared_ptr *obj) { std::cout << (*obj)->toString() << std::endl; } + +void print_myobject3_1(const MyObject3 *obj) { std::cout << obj->toString() << std::endl; } +void print_myobject3_2(std::shared_ptr obj) { std::cout << obj->toString() << std::endl; } +void print_myobject3_3(const std::shared_ptr &obj) { std::cout << obj->toString() << std::endl; } +void print_myobject3_4(const std::shared_ptr *obj) { std::cout << (*obj)->toString() << std::endl; } + +void init_ex8(py::module &m) { + py::class_> obj(m, "Object"); + obj.def("getRefCount", &Object::getRefCount); + + py::class_>(m, "MyObject1", obj) + .def(py::init()); + + m.def("make_object_1", &make_object_1); + m.def("make_object_2", &make_object_2); + m.def("make_myobject1_1", &make_myobject1_1); + m.def("make_myobject1_2", &make_myobject1_2); + m.def("print_object_1", &print_object_1); + m.def("print_object_2", &print_object_2); + m.def("print_object_3", &print_object_3); + m.def("print_object_4", &print_object_4); + m.def("print_myobject1_1", &print_myobject1_1); + m.def("print_myobject1_2", &print_myobject1_2); + m.def("print_myobject1_3", &print_myobject1_3); + m.def("print_myobject1_4", &print_myobject1_4); + + py::class_>(m, "MyObject2") + .def(py::init()); + m.def("make_myobject2_1", &make_myobject2_1); + m.def("make_myobject2_2", &make_myobject2_2); + m.def("print_myobject2_1", &print_myobject2_1); + m.def("print_myobject2_2", &print_myobject2_2); + m.def("print_myobject2_3", &print_myobject2_3); + m.def("print_myobject2_4", &print_myobject2_4); + + py::class_>(m, "MyObject3") + .def(py::init()); + m.def("make_myobject3_1", &make_myobject3_1); + m.def("make_myobject3_2", &make_myobject3_2); + m.def("print_myobject3_1", &print_myobject3_1); + m.def("print_myobject3_2", &print_myobject3_2); + m.def("print_myobject3_3", &print_myobject3_3); + m.def("print_myobject3_4", &print_myobject3_4); + + py::implicitly_convertible(); +} diff --git a/stormpy/resources/pybind11/example/example8.py b/stormpy/resources/pybind11/example/example8.py new file mode 100755 index 000000000..b12c5b999 --- /dev/null +++ b/stormpy/resources/pybind11/example/example8.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example import MyObject1 +from example import MyObject2 +from example import MyObject3 + +from example import make_object_1 +from example import make_object_2 +from example import make_myobject1_1 +from example import make_myobject1_2 +from example import make_myobject2_1 +from example import make_myobject2_2 +from example import make_myobject3_1 +from example import make_myobject3_2 + +from example import print_object_1 +from example import print_object_2 +from example import print_object_3 +from example import print_object_4 + +from example import print_myobject1_1 +from example import print_myobject1_2 +from example import print_myobject1_3 +from example import print_myobject1_4 + +from example import print_myobject2_1 +from example import print_myobject2_2 +from example import print_myobject2_3 +from example import print_myobject2_4 + +from example import print_myobject3_1 +from example import print_myobject3_2 +from example import print_myobject3_3 +from example import print_myobject3_4 + +for o in [make_object_1(), make_object_2(), MyObject1(3)]: + print("Reference count = %i" % o.getRefCount()) + print_object_1(o) + print_object_2(o) + print_object_3(o) + print_object_4(o) + +for o in [make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7]: + print(o) + if not isinstance(o, int): + print_object_1(o) + print_object_2(o) + print_object_3(o) + print_object_4(o) + print_myobject1_1(o) + print_myobject1_2(o) + print_myobject1_3(o) + print_myobject1_4(o) + +for o in [MyObject2(8), make_myobject2_1(), make_myobject2_2()]: + print(o) + print_myobject2_1(o) + print_myobject2_2(o) + print_myobject2_3(o) + print_myobject2_4(o) + +for o in [MyObject3(9), make_myobject3_1(), make_myobject3_2()]: + print(o) + print_myobject3_1(o) + print_myobject3_2(o) + print_myobject3_3(o) + print_myobject3_4(o) diff --git a/stormpy/resources/pybind11/example/example8.ref b/stormpy/resources/pybind11/example/example8.ref new file mode 100644 index 000000000..641abd0c4 --- /dev/null +++ b/stormpy/resources/pybind11/example/example8.ref @@ -0,0 +1,243 @@ +MyObject1[1] constructor +Initialized ref from pointer 0x1347ba0 +MyObject1[2] constructor +Initialized ref from pointer 0x12b9270 +Initialized ref from ref 0x12b9270 +Destructing ref 0x12b9270 +MyObject1[3] constructor +Initialized ref from pointer 0x12a2a90 +MyObject1[1] +Created empty ref +Assigning ref 0x1347ba0 +Initialized ref from ref 0x1347ba0 +MyObject1[1] +Destructing ref 0x1347ba0 +Destructing ref 0x1347ba0 +Created empty ref +Assigning ref 0x1347ba0 +MyObject1[1] +Destructing ref 0x1347ba0 +Created empty ref +Assigning ref 0x1347ba0 +MyObject1[1] +Destructing ref 0x1347ba0 +MyObject1[2] +Created empty ref +Assigning ref 0x12b9270 +Initialized ref from ref 0x12b9270 +MyObject1[2] +Destructing ref 0x12b9270 +Destructing ref 0x12b9270 +Created empty ref +Assigning ref 0x12b9270 +MyObject1[2] +Destructing ref 0x12b9270 +Created empty ref +Assigning ref 0x12b9270 +MyObject1[2] +Destructing ref 0x12b9270 +MyObject1[3] +Created empty ref +Assigning ref 0x12a2a90 +Initialized ref from ref 0x12a2a90 +MyObject1[3] +Destructing ref 0x12a2a90 +Destructing ref 0x12a2a90 +Created empty ref +Assigning ref 0x12a2a90 +MyObject1[3] +Destructing ref 0x12a2a90 +Created empty ref +Assigning ref 0x12a2a90 +MyObject1[3] +Destructing ref 0x12a2a90 +Destructing ref 0x12b9270 +MyObject1[2] destructor +Destructing ref 0x1347ba0 +MyObject1[1] destructor +MyObject1[4] constructor +Initialized ref from pointer 0x1347ba0 +MyObject1[5] constructor +Initialized ref from pointer 0x1299190 +Initialized ref from ref 0x1299190 +Destructing ref 0x1299190 +MyObject1[6] constructor +Initialized ref from pointer 0x133e2f0 +Destructing ref 0x12a2a90 +MyObject1[3] destructor +MyObject1[4] +Created empty ref +Assigning ref 0x1347ba0 +Initialized ref from ref 0x1347ba0 +MyObject1[4] +Destructing ref 0x1347ba0 +Destructing ref 0x1347ba0 +Created empty ref +Assigning ref 0x1347ba0 +MyObject1[4] +Destructing ref 0x1347ba0 +Created empty ref +Assigning ref 0x1347ba0 +MyObject1[4] +Destructing ref 0x1347ba0 +MyObject1[4] +Created empty ref +Assigning ref 0x1347ba0 +Initialized ref from ref 0x1347ba0 +MyObject1[4] +Destructing ref 0x1347ba0 +Destructing ref 0x1347ba0 +Created empty ref +Assigning ref 0x1347ba0 +MyObject1[4] +Destructing ref 0x1347ba0 +Created empty ref +Assigning ref 0x1347ba0 +MyObject1[4] +Destructing ref 0x1347ba0 +MyObject1[5] +Created empty ref +Assigning ref 0x1299190 +Initialized ref from ref 0x1299190 +MyObject1[5] +Destructing ref 0x1299190 +Destructing ref 0x1299190 +Created empty ref +Assigning ref 0x1299190 +MyObject1[5] +Destructing ref 0x1299190 +Created empty ref +Assigning ref 0x1299190 +MyObject1[5] +Destructing ref 0x1299190 +MyObject1[5] +Created empty ref +Assigning ref 0x1299190 +Initialized ref from ref 0x1299190 +MyObject1[5] +Destructing ref 0x1299190 +Destructing ref 0x1299190 +Created empty ref +Assigning ref 0x1299190 +MyObject1[5] +Destructing ref 0x1299190 +Created empty ref +Assigning ref 0x1299190 +MyObject1[5] +Destructing ref 0x1299190 +MyObject1[6] +Created empty ref +Assigning ref 0x133e2f0 +Initialized ref from ref 0x133e2f0 +MyObject1[6] +Destructing ref 0x133e2f0 +Destructing ref 0x133e2f0 +Created empty ref +Assigning ref 0x133e2f0 +MyObject1[6] +Destructing ref 0x133e2f0 +Created empty ref +Assigning ref 0x133e2f0 +MyObject1[6] +Destructing ref 0x133e2f0 +MyObject1[6] +Created empty ref +Assigning ref 0x133e2f0 +Initialized ref from ref 0x133e2f0 +MyObject1[6] +Destructing ref 0x133e2f0 +Destructing ref 0x133e2f0 +Created empty ref +Assigning ref 0x133e2f0 +MyObject1[6] +Destructing ref 0x133e2f0 +Created empty ref +Assigning ref 0x133e2f0 +MyObject1[6] +Destructing ref 0x133e2f0 +MyObject1[7] constructor +Initialized ref from pointer 0x133f3a0 +MyObject1[7] +Destructing ref 0x133f3a0 +MyObject1[7] destructor +Created empty ref +MyObject1[7] constructor +Initialized ref from pointer 0x12a2a90 +Assigning ref 0x12a2a90 +Initialized ref from ref 0x12a2a90 +MyObject1[7] +Destructing ref 0x12a2a90 +Destructing ref 0x12a2a90 +Destructing ref 0x12a2a90 +MyObject1[7] destructor +Created empty ref +MyObject1[7] constructor +Initialized ref from pointer 0x133f3a0 +Assigning ref 0x133f3a0 +MyObject1[7] +Destructing ref 0x133f3a0 +Destructing ref 0x133f3a0 +MyObject1[7] destructor +Created empty ref +MyObject1[7] constructor +Initialized ref from pointer 0x12a2a90 +Assigning ref 0x12a2a90 +MyObject1[7] +Destructing ref 0x12a2a90 +Destructing ref 0x12a2a90 +MyObject1[7] destructor +Destructing ref 0x133e2f0 +MyObject1[6] destructor +Destructing ref 0x1299190 +MyObject1[5] destructor +Destructing ref 0x1347ba0 +MyObject1[4] destructor +MyObject2[8] constructor +MyObject2[6] constructor +MyObject2[7] constructor +MyObject2[8] +MyObject2[8] +MyObject2[8] +MyObject2[8] +MyObject2[6] +MyObject2[6] +MyObject2[6] +MyObject2[6] +MyObject2[7] +MyObject2[7] +MyObject2[7] +MyObject2[7] +MyObject2[6] destructor +MyObject2[8] destructor +MyObject3[9] constructor +MyObject3[8] constructor +MyObject3[9] constructor +MyObject2[7] destructor +MyObject3[9] +MyObject3[9] +MyObject3[9] +MyObject3[9] +MyObject3[8] +MyObject3[8] +MyObject3[8] +MyObject3[8] +MyObject3[9] +MyObject3[9] +MyObject3[9] +MyObject3[9] +MyObject3[8] destructor +MyObject3[9] destructor +Reference count = 1 +Reference count = 1 +Reference count = 1 + + + +7 + + + + + + +MyObject3[9] destructor diff --git a/stormpy/resources/pybind11/example/example9.cpp b/stormpy/resources/pybind11/example/example9.cpp new file mode 100644 index 000000000..f64b539a2 --- /dev/null +++ b/stormpy/resources/pybind11/example/example9.cpp @@ -0,0 +1,55 @@ +/* + example/example9.cpp -- nested modules, importing modules, and + internal references + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +void submodule_func() { + std::cout << "submodule_func()" << std::endl; +} + +class A { +public: + A(int v) : v(v) { std::cout << "A constructor" << std::endl; } + ~A() { std::cout << "A destructor" << std::endl; } + A(const A&) { std::cout << "A copy constructor" << std::endl; } + std::string toString() { return "A[" + std::to_string(v) + "]"; } +private: + int v; +}; + +class B { +public: + B() { std::cout << "B constructor" << std::endl; } + ~B() { std::cout << "B destructor" << std::endl; } + B(const B&) { std::cout << "B copy constructor" << std::endl; } + A &get_a1() { return a1; } + A &get_a2() { return a2; } + + A a1{1}; + A a2{2}; +}; + +void init_ex9(py::module &m) { + py::module m_sub = m.def_submodule("submodule"); + m_sub.def("submodule_func", &submodule_func); + + py::class_(m_sub, "A") + .def(py::init()) + .def("__repr__", &A::toString); + + py::class_(m_sub, "B") + .def(py::init<>()) + .def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal) + .def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal) + .def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default + .def_readwrite("a2", &B::a2); + + m.attr("OD") = py::module::import("collections").attr("OrderedDict"); +} diff --git a/stormpy/resources/pybind11/example/example9.py b/stormpy/resources/pybind11/example/example9.py new file mode 100755 index 000000000..2262fcf5c --- /dev/null +++ b/stormpy/resources/pybind11/example/example9.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +import example + +print(example.__name__) +print(example.submodule.__name__) + +from example.submodule import * +from example import OD + +submodule_func() + +b = B() +print(b.get_a1()) +print(b.a1) +print(b.get_a2()) +print(b.a2) + +b.a1 = A(42) +b.a2 = A(43) + +print(b.get_a1()) +print(b.a1) +print(b.get_a2()) +print(b.a2) + +print(OD([(1, 'a'), (2, 'b')])) diff --git a/stormpy/resources/pybind11/example/example9.ref b/stormpy/resources/pybind11/example/example9.ref new file mode 100644 index 000000000..9c783135c --- /dev/null +++ b/stormpy/resources/pybind11/example/example9.ref @@ -0,0 +1,22 @@ +example +example.submodule +submodule_func() +A constructor +A constructor +B constructor +A[1] +A[1] +A[2] +A[2] +A constructor +A destructor +A constructor +A destructor +A[42] +A[42] +A[43] +A[43] +OrderedDict([(1, 'a'), (2, 'b')]) +B destructor +A destructor +A destructor diff --git a/stormpy/resources/pybind11/example/issues.cpp b/stormpy/resources/pybind11/example/issues.cpp new file mode 100644 index 000000000..c9f9e8b07 --- /dev/null +++ b/stormpy/resources/pybind11/example/issues.cpp @@ -0,0 +1,47 @@ +/* + example/issues.cpp -- collection of testcases for miscellaneous issues + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +struct Base { + virtual void dispatch(void) const = 0; +}; + +struct DispatchIssue : Base { + virtual void dispatch(void) const { + PYBIND11_OVERLOAD_PURE(void, Base, dispatch); + } +}; + +void dispatch_issue_go(const Base * b) { b->dispatch(); } + +PYBIND11_PLUGIN(mytest) +{ + pybind11::module m("mytest", "A test"); + + + return m.ptr(); +} +void init_issues(py::module &m) { + py::module m2 = m.def_submodule("issues"); + + // #137: const char* isn't handled properly + m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; }); + + // #150: char bindings broken + m2.def("print_char", [](char c) { std::cout << c << std::endl; }); + + // #159: virtual function dispatch has problems with similar-named functions + pybind11::class_ base(m2, "DispatchIssue"); + base.alias() + .def(pybind11::init<>()) + .def("dispatch", &Base::dispatch); + + m2.def("dispatch_issue_go", &dispatch_issue_go); +} diff --git a/stormpy/resources/pybind11/example/issues.py b/stormpy/resources/pybind11/example/issues.py new file mode 100644 index 000000000..84752b0d3 --- /dev/null +++ b/stormpy/resources/pybind11/example/issues.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +sys.path.append('.') + +from example.issues import print_cchar, print_char +from example.issues import DispatchIssue, dispatch_issue_go + +print_cchar("const char *") +print_char('c') + + +class PyClass1(DispatchIssue): + def dispatch(self): + print("Yay..") + + +class PyClass2(DispatchIssue): + def dispatch(self): + try: + super(PyClass2, self).dispatch() + except Exception as e: + print("Failed as expected: " + str(e)) + p = PyClass1() + dispatch_issue_go(p) + +b = PyClass2() +dispatch_issue_go(b) diff --git a/stormpy/resources/pybind11/example/issues.ref b/stormpy/resources/pybind11/example/issues.ref new file mode 100644 index 000000000..55cbdda1d --- /dev/null +++ b/stormpy/resources/pybind11/example/issues.ref @@ -0,0 +1,4 @@ +const char * +c +Failed as expected: Tried to call pure virtual function "dispatch" +Yay.. diff --git a/stormpy/resources/pybind11/example/object.h b/stormpy/resources/pybind11/example/object.h new file mode 100644 index 000000000..8097bd671 --- /dev/null +++ b/stormpy/resources/pybind11/example/object.h @@ -0,0 +1,160 @@ +#if !defined(__OBJECT_H) +#define __OBJECT_H + +#include + +/// Reference counted object base class +class Object { +public: + /// Default constructor + Object() { } + + /// Copy constructor + Object(const Object &) : m_refCount(0) {} + + /// Return the current reference count + int getRefCount() const { return m_refCount; }; + + /// Increase the object's reference count by one + void incRef() const { ++m_refCount; } + + /** \brief Decrease the reference count of + * the object and possibly deallocate it. + * + * The object will automatically be deallocated once + * the reference count reaches zero. + */ + void decRef(bool dealloc = true) const { + --m_refCount; + if (m_refCount == 0 && dealloc) + delete this; + else if (m_refCount < 0) + throw std::runtime_error("Internal error: reference count < 0!"); + } + + virtual std::string toString() const = 0; +protected: + /** \brief Virtual protected deconstructor. + * (Will only be called by \ref ref) + */ + virtual ~Object() { } +private: + mutable std::atomic m_refCount { 0 }; +}; + +/** + * \brief Reference counting helper + * + * The \a ref refeference template is a simple wrapper to store a + * pointer to an object. It takes care of increasing and decreasing + * the reference count of the object. When the last reference goes + * out of scope, the associated object will be deallocated. + * + * \ingroup libcore + */ +template class ref { +public: + /// Create a nullptr reference + ref() : m_ptr(nullptr) { std::cout << "Created empty ref" << std::endl; } + + /// Construct a reference from a pointer + ref(T *ptr) : m_ptr(ptr) { + std::cout << "Initialized ref from pointer " << ptr<< std::endl; + if (m_ptr) ((Object *) m_ptr)->incRef(); + } + + /// Copy constructor + ref(const ref &r) : m_ptr(r.m_ptr) { + std::cout << "Initialized ref from ref " << r.m_ptr << std::endl; + if (m_ptr) + ((Object *) m_ptr)->incRef(); + } + + /// Move constructor + ref(ref &&r) : m_ptr(r.m_ptr) { + std::cout << "Initialized ref with move from ref " << r.m_ptr << std::endl; + r.m_ptr = nullptr; + } + + /// Destroy this reference + ~ref() { + std::cout << "Destructing ref " << m_ptr << std::endl; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + } + + /// Move another reference into the current one + ref& operator=(ref&& r) { + std::cout << "Move-assigning ref " << r.m_ptr << std::endl; + if (*this == r) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = r.m_ptr; + r.m_ptr = nullptr; + return *this; + } + + /// Overwrite this reference with another reference + ref& operator=(const ref& r) { + std::cout << "Assigning ref " << r.m_ptr << std::endl; + if (m_ptr == r.m_ptr) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = r.m_ptr; + if (m_ptr) + ((Object *) m_ptr)->incRef(); + return *this; + } + + /// Overwrite this reference with a pointer to another object + ref& operator=(T *ptr) { + std::cout << "Assigning ptr " << ptr << " to ref" << std::endl; + if (m_ptr == ptr) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = ptr; + if (m_ptr) + ((Object *) m_ptr)->incRef(); + return *this; + } + + /// Compare this reference with another reference + bool operator==(const ref &r) const { return m_ptr == r.m_ptr; } + + /// Compare this reference with another reference + bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; } + + /// Compare this reference with a pointer + bool operator==(const T* ptr) const { return m_ptr == ptr; } + + /// Compare this reference with a pointer + bool operator!=(const T* ptr) const { return m_ptr != ptr; } + + /// Access the object referenced by this reference + T* operator->() { return m_ptr; } + + /// Access the object referenced by this reference + const T* operator->() const { return m_ptr; } + + /// Return a C++ reference to the referenced object + T& operator*() { return *m_ptr; } + + /// Return a const C++ reference to the referenced object + const T& operator*() const { return *m_ptr; } + + /// Return a pointer to the referenced object + operator T* () { return m_ptr; } + + /// Return a const pointer to the referenced object + T* get() { return m_ptr; } + + /// Return a pointer to the referenced object + const T* get() const { return m_ptr; } +private: + T *m_ptr; +}; + +#endif /* __OBJECT_H */ diff --git a/stormpy/resources/pybind11/example/run_test.py b/stormpy/resources/pybind11/example/run_test.py new file mode 100755 index 000000000..d0967c6e2 --- /dev/null +++ b/stormpy/resources/pybind11/example/run_test.py @@ -0,0 +1,72 @@ +import sys +import os +import re +import subprocess + +remove_unicode_marker = re.compile(r'u(\'[^\']*\')') +remove_long_marker = re.compile(r'([0-9])L') +remove_hex = re.compile(r'0x[0-9a-fA-F]+') +shorten_floats = re.compile(r'([1-9][0-9]*\.[0-9]{4})[0-9]*') + +relaxed = False + +def sanitize(lines): + lines = lines.split('\n') + for i in range(len(lines)): + line = lines[i] + if line.startswith(" |"): + line = "" + line = remove_unicode_marker.sub(r'\1', line) + line = remove_long_marker.sub(r'\1', line) + line = remove_hex.sub(r'0', line) + line = shorten_floats.sub(r'\1', line) + line = line.replace('__builtin__', 'builtins') + line = line.replace('example.', '') + line = line.replace('unicode', 'str') + line = line.replace('Example4.EMode', 'EMode') + line = line.replace('example.EMode', 'EMode') + line = line.replace('method of builtins.PyCapsule instance', '') + line = line.strip() + if relaxed: + lower = line.lower() + # The precise pattern of allocations and deallocations is dependent on the compiler + # and optimization level, so we unfortunately can't reliably check it in this kind of test case + if 'constructor' in lower or 'destructor' in lower \ + or 'ref' in lower or 'freeing' in lower: + line = "" + lines[i] = line + + lines = '\n'.join(sorted([l for l in lines if l != ""])) + + print('==================') + print(lines) + return lines + +path = os.path.dirname(__file__) +if path != '': + os.chdir(path) + +if len(sys.argv) < 2: + print("Syntax: %s [--relaxed] " % sys.argv[0]) + exit(0) + +if len(sys.argv) == 3 and sys.argv[1] == '--relaxed': + del sys.argv[1] + relaxed = True + +name = sys.argv[1] +output_bytes = subprocess.check_output([sys.executable, name + ".py"], + stderr=subprocess.STDOUT) + +output = sanitize(output_bytes.decode('utf-8')) +reference = sanitize(open(name + '.ref', 'r').read()) + +if 'NumPy missing' in output: + print('Test "%s" could not be run.' % name) + exit(0) +elif output == reference: + print('Test "%s" succeeded.' % name) + exit(0) +else: + print('Test "%s" FAILED!' % name) + exit(-1) diff --git a/stormpy/resources/pybind11/include/pybind11/attr.h b/stormpy/resources/pybind11/include/pybind11/attr.h new file mode 100644 index 000000000..759feed7e --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/attr.h @@ -0,0 +1,309 @@ +/* + pybind11/pybind11.h: Infrastructure for processing custom + type and function attributes + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "cast.h" + +NAMESPACE_BEGIN(pybind11) + +template struct arg_t; + +/// Annotation for keyword arguments +struct arg { + arg(const char *name) : name(name) { } + template arg_t operator=(const T &value); + template arg_t operator=(T const (&value)[N]); + const char *name; +}; + +/// Annotation for keyword arguments with default values +template struct arg_t : public arg { + arg_t(const char *name, const T &value, const char *descr = nullptr) + : arg(name), value(value), descr(descr) { } + T value; + const char *descr; +}; + +template arg_t arg::operator=(const T &value) { return arg_t(name, value); } +template arg_t arg::operator=(T const (&value)[N]) { + return operator=((const T *) value); +} + +/// Annotation for methods +struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; + +/// Annotation for parent scope +struct scope { handle value; scope(const handle &s) : value(s) { } }; + +/// Annotation for documentation +struct doc { const char *value; doc(const char *value) : value(value) { } }; + +/// Annotation for function names +struct name { const char *value; name(const char *value) : value(value) { } }; + +/// Annotation indicating that a function is an overload associated with a given "sibling" +struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } }; + +/// Annotation indicating that a class derives from another given type +template struct base { }; + +/// Keep patient alive while nurse lives +template struct keep_alive { }; + +NAMESPACE_BEGIN(detail) +/* Forward declarations */ +enum op_id : int; +enum op_type : int; +struct undefined_t; +template struct op_; +template struct init; +inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret); + +/// Internal data structure which holds metadata about a keyword argument +struct argument_record { + const char *name; ///< Argument name + const char *descr; ///< Human-readable version of the argument value + handle value; ///< Associated Python object + + argument_record(const char *name, const char *descr, handle value) + : name(name), descr(descr), value(value) { } +}; + +/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) +struct function_record { + /// Function name + char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ + + // User-specified documentation string + char *doc = nullptr; + + /// Human-readable version of the function signature + char *signature = nullptr; + + /// List of registered keyword arguments + std::vector args; + + /// Pointer to lambda function which converts arguments and performs the actual call + handle (*impl) (function_record *, handle, handle) = nullptr; + + /// Storage for the wrapped function pointer and captured data, if any + void *data = nullptr; + + /// Pointer to custom destructor for 'data' (if needed) + void (*free_data) (void *ptr) = nullptr; + + /// Return value policy associated with this function + return_value_policy policy = return_value_policy::automatic; + + /// True if name == '__init__' + bool is_constructor = false; + + /// Python method object + PyMethodDef *def = nullptr; + + /// Python handle to the associated class (if this is method) + handle class_; + + /// Python handle to the parent scope (a class or a module) + handle scope; + + /// Python handle to the sibling function representing an overload chain + handle sibling; + + /// Pointer to next overload + function_record *next = nullptr; +}; + +/// Special data structure which (temporarily) holds metadata about a bound class +struct type_record { + /// Handle to the parent scope + handle scope; + + /// Name of the class + const char *name = nullptr; + + // Pointer to RTTI type_info data structure + const std::type_info *type = nullptr; + + /// How large is the underlying C++ type? + size_t type_size = 0; + + /// How large is pybind11::instance? + size_t instance_size = 0; + + /// Function pointer to class_<..>::init_holder + void (*init_holder)(PyObject *, const void *) = nullptr; + + /// Function pointer to class_<..>::dealloc + void (*dealloc)(PyObject *) = nullptr; + + // Pointer to RTTI type_info data structure of base class + const std::type_info *base_type = nullptr; + + /// OR: Python handle to base class + handle base_handle; + + /// Optional docstring + const char *doc = nullptr; +}; + +/** + * Partial template specializations to process custom attributes provided to + * cpp_function_ and class_. These are either used to initialize the respective + * fields in the type_record and function_record data structures or executed + * at runtime to deal with custom call policies (e.g. keep_alive). + */ +template struct process_attribute; + +template struct process_attribute_default { + /// Default implementation: do nothing + static void init(const T &, function_record *) { } + static void init(const T &, type_record *) { } + static void precall(handle) { } + static void postcall(handle, handle) { } +}; + +/// Process an attribute specifying the function's name +template <> struct process_attribute : process_attribute_default { + static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring +template <> struct process_attribute : process_attribute_default { + static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring (provided as a C-style string) +template <> struct process_attribute : process_attribute_default { + static void init(const char *d, function_record *r) { r->doc = const_cast(d); } + static void init(const char *d, type_record *r) { r->doc = const_cast(d); } +}; +template <> struct process_attribute : process_attribute { }; + +/// Process an attribute indicating the function's return value policy +template <> struct process_attribute : process_attribute_default { + static void init(const return_value_policy &p, function_record *r) { r->policy = p; } +}; + +/// Process an attribute which indicates that this is an overloaded function associated with a given sibling +template <> struct process_attribute : process_attribute_default { + static void init(const sibling &s, function_record *r) { r->sibling = s.value; } +}; + +/// Process an attribute which indicates that this function is a method +template <> struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { r->class_ = s.class_; r->scope = s.class_; } +}; + +/// Process an attribute which indicates the parent scope of a method +template <> struct process_attribute : process_attribute_default { + static void init(const scope &s, function_record *r) { r->scope = s.value; } +}; + + +/// Process a keyword argument attribute (*without* a default value) +template <> struct process_attribute : process_attribute_default { + static void init(const arg &a, function_record *r) { + if (r->class_ && r->args.empty()) + r->args.emplace_back("self", nullptr, handle()); + r->args.emplace_back(a.name, nullptr, handle()); + } +}; + +/// Process a keyword argument attribute (*with* a default value) +template +struct process_attribute> : process_attribute_default> { + static void init(const arg_t &a, function_record *r) { + if (r->class_ && r->args.empty()) + r->args.emplace_back("self", nullptr, handle()); + + /* Convert keyword value into a Python object */ + object o = object(detail::type_caster::type>::cast( + a.value, return_value_policy::automatic, handle()), false); + + if (!o) { +#if !defined(NDEBUG) + std::string descr(typeid(T).name()); + detail::clean_type_id(descr); + descr = "'" + std::string(a.name) + ": " + descr + "'"; + if (r->class_) { + if (r->name) + descr += " in method '" + (std::string) r->class_.str() + "." + (std::string) r->name + "'"; + else + descr += " in method of '" + (std::string) r->class_.str() + "'"; + } else if (r->name) { + descr += " in function named '" + (std::string) r->name + "'"; + } + pybind11_fail("arg(): could not convert default keyword argument " + + descr + " into a Python object (type not registered yet?)"); +#else + pybind11_fail("arg(): could not convert default keyword argument " + "into a Python object (type not registered yet?). " + "Compile in debug mode for more information."); +#endif + } + r->args.emplace_back(a.name, a.descr, o.release()); + } +}; + +/// Process a parent class attribute +template +struct process_attribute::value>::type> : process_attribute_default { + static void init(const handle &h, type_record *r) { r->base_handle = h; } +}; + +/// Process a parent class attribute +template +struct process_attribute> : process_attribute_default> { + static void init(const base &, type_record *r) { r->base_type = &typeid(T); } +}; + +/*** + * Process a keep_alive call policy -- invokes keep_alive_impl during the + * pre-call handler if both Nurse, Patient != 0 and use the post-call handler + * otherwise + */ +template struct process_attribute> : public process_attribute_default> { + template ::type = 0> + static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); } + template ::type = 0> + static void postcall(handle, handle) { } + template ::type = 0> + static void precall(handle) { } + template ::type = 0> + static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); } +}; + +/// Ignore that a variable is unused in compiler warnings +inline void ignore_unused(const int *) { } + +/// Recursively iterate over variadic template arguments +template struct process_attributes { + static void init(const Args&... args, function_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void init(const Args&... args, type_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void precall(handle fn_args) { + int unused[] = { 0, (process_attribute::type>::precall(fn_args), 0) ... }; + ignore_unused(unused); + } + static void postcall(handle fn_args, handle fn_ret) { + int unused[] = { 0, (process_attribute::type>::postcall(fn_args, fn_ret), 0) ... }; + ignore_unused(unused); + } +}; + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/cast.h b/stormpy/resources/pybind11/include/pybind11/cast.h new file mode 100644 index 000000000..0fe35274d --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/cast.h @@ -0,0 +1,747 @@ +/* + pybind11/cast.h: Partial template specializations to cast between + C++ and Python types + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pytypes.h" +#include "typeid.h" +#include "descr.h" +#include +#include + +NAMESPACE_BEGIN(pybind11) + +/// Thin wrapper type used to treat certain data types as opaque (e.g. STL vectors, etc.) +template class opaque { +public: + template opaque(Args&&... args) : value(std::forward(args)...) { } + operator Type&() { return value; } + operator const Type&() const { return value; } + operator Type*() { return &value; } + operator const Type*() const { return &value; } + Type* operator->() { return &value; } + const Type* operator->() const { return &value; } +private: + Type value; +}; + +NAMESPACE_BEGIN(detail) + +/// Additional type information which does not fit into the PyTypeObject +struct type_info { + PyTypeObject *type; + size_t type_size; + void (*init_holder)(PyObject *, const void *); + std::vector implicit_conversions; + buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; + void *get_buffer_data = nullptr; +}; + +PYBIND11_NOINLINE inline internals &get_internals() { + static internals *internals_ptr = nullptr; + if (internals_ptr) + return *internals_ptr; + handle builtins(PyEval_GetBuiltins()); + const char *id = PYBIND11_INTERNALS_ID; + capsule caps(builtins[id]); + if (caps.check()) { + internals_ptr = caps; + } else { + internals_ptr = new internals(); + builtins[id] = capsule(internals_ptr); + } + return *internals_ptr; +} + +PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { + auto const &type_dict = get_internals().registered_types_py; + do { + auto it = type_dict.find(type); + if (it != type_dict.end()) + return (detail::type_info *) it->second; + type = type->tp_base; + if (!type) + pybind11_fail("pybind11::detail::get_type_info: unable to find type object!"); + } while (true); +} + +PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp) { + auto &types = get_internals().registered_types_cpp; + + auto it = types.find(std::type_index(tp)); + if (it != types.end()) + return (detail::type_info *) it->second; + return nullptr; +} + +PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp) { + detail::type_info *type_info = get_type_info(tp); + return handle(type_info ? ((PyObject *) type_info->type) : nullptr); +} + +PYBIND11_NOINLINE inline std::string error_string() { + std::string errorString; + PyThreadState *tstate = PyThreadState_GET(); + if (tstate == nullptr) + return ""; + + if (tstate->curexc_type) { + errorString += (std::string) handle(tstate->curexc_type).str(); + errorString += ": "; + } + if (tstate->curexc_value) + errorString += (std::string) handle(tstate->curexc_value).str(); + + return errorString; +} + +PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr) { + auto instances = get_internals().registered_instances; + auto it = instances.find(ptr); + if (it == instances.end()) + return handle(); + return handle((PyObject *) it->second); +} + +class type_caster_generic { +public: + PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) + : typeinfo(get_type_info(type_info)) { } + + PYBIND11_NOINLINE bool load(handle src, bool convert) { + if (!src || !typeinfo) + return false; + if (src.ptr() == Py_None) { + value = nullptr; + return true; + } else if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) { + value = ((instance *) src.ptr())->value; + return true; + } + if (convert) { + for (auto &converter : typeinfo->implicit_conversions) { + temp = object(converter(src.ptr(), typeinfo->type), false); + if (load(temp, false)) + return true; + } + } + return false; + } + + PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, + const std::type_info *type_info, + const std::type_info *type_info_backup, + void *(*copy_constructor)(const void *), + const void *existing_holder = nullptr) { + void *src = const_cast(_src); + if (src == nullptr) + return handle(Py_None).inc_ref(); + + // avoid an issue with internal references matching their parent's address + bool dont_cache = policy == return_value_policy::reference_internal && + parent && ((instance *) parent.ptr())->value == (void *) src; + + auto& internals = get_internals(); + auto it_instance = internals.registered_instances.find(src); + if (it_instance != internals.registered_instances.end() && !dont_cache) + return handle((PyObject *) it_instance->second).inc_ref(); + + auto it = internals.registered_types_cpp.find(std::type_index(*type_info)); + if (it == internals.registered_types_cpp.end()) { + type_info = type_info_backup; + it = internals.registered_types_cpp.find(std::type_index(*type_info)); + } + + if (it == internals.registered_types_cpp.end()) { + std::string tname = type_info->name(); + detail::clean_type_id(tname); + std::string msg = "Unregistered type : " + tname; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return handle(); + } + + auto tinfo = (const detail::type_info *) it->second; + object inst(PyType_GenericAlloc(tinfo->type, 0), false); + + auto wrapper = (instance *) inst.ptr(); + + wrapper->value = src; + wrapper->owned = true; + wrapper->parent = nullptr; + + if (policy == return_value_policy::automatic) + policy = return_value_policy::take_ownership; + else if (policy == return_value_policy::automatic_reference) + policy = return_value_policy::reference; + + if (policy == return_value_policy::copy) { + wrapper->value = copy_constructor(wrapper->value); + if (wrapper->value == nullptr) + throw cast_error("return_value_policy = copy, but the object is non-copyable!"); + } else if (policy == return_value_policy::reference) { + wrapper->owned = false; + } else if (policy == return_value_policy::reference_internal) { + wrapper->owned = false; + wrapper->parent = parent.inc_ref().ptr(); + } + + tinfo->init_holder(inst.ptr(), existing_holder); + if (!dont_cache) + internals.registered_instances[wrapper->value] = inst.ptr(); + + return inst.release(); + } + +protected: + const type_info *typeinfo = nullptr; + void *value = nullptr; + object temp; +}; + +/* Determine suitable casting operator */ +template +using cast_op_type = typename std::conditional::value, + typename std::add_pointer::type>::type, + typename std::add_lvalue_reference::type>::type>::type; + +/// Generic type caster for objects stored on the heap +template class type_caster : public type_caster_generic { +public: + static PYBIND11_DESCR name() { return type_descr(_()); } + + type_caster() : type_caster_generic(typeid(type)) { } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast(&src, policy, parent); + } + + static handle cast(const type *src, return_value_policy policy, handle parent) { + return type_caster_generic::cast(src, policy, parent, src ? &typeid(*src) : nullptr, &typeid(type), ©_constructor); + } + + template using cast_op_type = pybind11::detail::cast_op_type; + + operator type*() { return (type *) value; } + operator type&() { return *((type *) value); } +protected: + template ::value, int>::type = 0> + static void *copy_constructor(const void *arg) { + return (void *) new type(*((const type *) arg)); + } + template ::value, int>::type = 0> + static void *copy_constructor(const void *) { return nullptr; } +}; + +#define PYBIND11_TYPE_CASTER(type, py_name) \ + protected: \ + type value; \ + public: \ + static PYBIND11_DESCR name() { return type_descr(py_name); } \ + static handle cast(const type *src, return_value_policy policy, handle parent) { \ + return cast(*src, policy, parent); \ + } \ + operator type*() { return &value; } \ + operator type&() { return value; } \ + template using cast_op_type = pybind11::detail::cast_op_type<_T>; + +#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \ + namespace pybind11 { namespace detail { \ + template class type_caster \ + : public type_caster_holder { }; \ + }} + + +template +struct type_caster< + T, typename std::enable_if::value || + std::is_floating_point::value>::type> { + typedef typename std::conditional::type _py_type_0; + typedef typename std::conditional::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1; + typedef typename std::conditional::value, double, _py_type_1>::type py_type; +public: + + bool load(handle src, bool) { + py_type py_value; + + if (std::is_floating_point::value) { + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + } else if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + py_value = (py_type) PyLong_AsLong(src.ptr()); + else + py_value = (py_type) PyLong_AsUnsignedLong(src.ptr()); + } else { + if (std::is_signed::value) + py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); + else + py_value = (py_type) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(src.ptr()); + } + + if ((py_value == (py_type) -1 && PyErr_Occurred()) || + (std::is_integral::value && sizeof(py_type) != sizeof(T) && + (py_value < (py_type) std::numeric_limits::min() || + py_value > (py_type) std::numeric_limits::max()))) { + PyErr_Clear(); + return false; + } + + value = (T) py_value; + return true; + } + + static handle cast(T src, return_value_policy /* policy */, handle /* parent */) { + if (std::is_floating_point::value) { + return PyFloat_FromDouble((double) src); + } else if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + return PyLong_FromLong((long) src); + else + return PyLong_FromUnsignedLong((unsigned long) src); + } else { + if (std::is_signed::value) + return PyLong_FromLongLong((long long) src); + else + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } + } + + static handle cast(const T *src, return_value_policy policy, handle parent) { + return cast(*src, policy, parent); + } + + template ::value, int>::type = 0> + static PYBIND11_DESCR name() { return type_descr(_("int")); } + + template ::value, int>::type = 0> + static PYBIND11_DESCR name() { return type_descr(_("float")); } + + operator T*() { return &value; } + operator T&() { return value; } + + template using cast_op_type = pybind11::detail::cast_op_type; +protected: + T value; +}; + +template <> class type_caster { +public: + bool load(handle, bool) { return false; } + static handle cast(void_type, return_value_policy /* policy */, handle /* parent */) { + return handle(Py_None).inc_ref(); + } + PYBIND11_TYPE_CASTER(void_type, _("NoneType")); +}; + +template <> class type_caster : public type_caster { +public: + using type_caster::cast; + + bool load(handle h, bool) { + if (h.ptr() == Py_None) { + value = nullptr; + return true; + } + capsule c(h, true); + if (!c.check()) + return false; + value = (void *) c; + return true; + } + + static handle cast(void *ptr, return_value_policy /* policy */, handle /* parent */) { + if (ptr) + return capsule(ptr).release(); + else + return handle(Py_None).inc_ref(); + } + + template using cast_op_type = void*&; + operator void *&() { return value; } +private: + void *value = nullptr; +}; + +template <> class type_caster : public type_caster { }; + +template <> class type_caster { +public: + bool load(handle src, bool) { + if (src.ptr() == Py_True) { value = true; return true; } + else if (src.ptr() == Py_False) { value = false; return true; } + else return false; + } + static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { + return handle(src ? Py_True : Py_False).inc_ref(); + } + PYBIND11_TYPE_CASTER(bool, _("bool")); +}; + +template <> class type_caster { +public: + bool load(handle src, bool) { + object temp; + handle load_src = src; + if (PyUnicode_Check(load_src.ptr())) { + temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false); + if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError + load_src = temp; + } + char *buffer; + ssize_t length; + int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length); + if (err == -1) { PyErr_Clear(); return false; } // TypeError + value = std::string(buffer, length); + success = true; + return true; + } + + static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) { + return PyUnicode_FromStringAndSize(src.c_str(), src.length()); + } + + PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME)); +protected: + bool success = false; +}; + +template class type_caster> { +public: + static handle cast(std::unique_ptr &&src, return_value_policy policy, handle parent) { + handle result = type_caster::cast(src.get(), policy, parent); + if (result) + src.release(); + return result; + } + static PYBIND11_DESCR name() { return type_caster::name(); } +}; + +template <> class type_caster { +public: + bool load(handle src, bool) { + object temp; + handle load_src = src; + if (!PyUnicode_Check(load_src.ptr())) { + temp = object(PyUnicode_FromObject(load_src.ptr()), false); + if (!temp) { PyErr_Clear(); return false; } + load_src = temp; + } + wchar_t *buffer = nullptr; + ssize_t length = -1; +#if PY_MAJOR_VERSION >= 3 + buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length); +#else + temp = object( + sizeof(wchar_t) == sizeof(short) + ? PyUnicode_AsUTF16String(load_src.ptr()) + : PyUnicode_AsUTF32String(load_src.ptr()), false); + if (temp) { + int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length); + if (err == -1) { buffer = nullptr; } // TypeError + length = length / sizeof(wchar_t) - 1; ++buffer; // Skip BOM + } +#endif + if (!buffer) { PyErr_Clear(); return false; } + value = std::wstring(buffer, length); + success = true; + return true; + } + + static handle cast(const std::wstring &src, return_value_policy /* policy */, handle /* parent */) { + return PyUnicode_FromWideChar(src.c_str(), src.length()); + } + + PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME)); +protected: + bool success = false; +}; + +template <> class type_caster : public type_caster { +public: + bool load(handle src, bool convert) { + if (src.ptr() == Py_None) { return true; } + return type_caster::load(src, convert); + } + + static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) { + if (src == nullptr) return handle(Py_None).inc_ref(); + return PyUnicode_FromString(src); + } + + static handle cast(char src, return_value_policy /* policy */, handle /* parent */) { + char str[2] = { src, '\0' }; + return PyUnicode_DecodeLatin1(str, 1, nullptr); + } + + operator char*() { return success ? (char *) value.c_str() : nullptr; } + operator char&() { return value[0]; } + + static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } +}; + +template <> class type_caster : public type_caster { +public: + bool load(handle src, bool convert) { + if (src.ptr() == Py_None) { return true; } + return type_caster::load(src, convert); + } + + static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) { + if (src == nullptr) return handle(Py_None).inc_ref(); + return PyUnicode_FromWideChar(src, wcslen(src)); + } + + static handle cast(wchar_t src, return_value_policy /* policy */, handle /* parent */) { + wchar_t wstr[2] = { src, L'\0' }; + return PyUnicode_FromWideChar(wstr, 1); + } + + operator wchar_t*() { return success ? (wchar_t *) value.c_str() : nullptr; } + operator wchar_t&() { return value[0]; } + + static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } +}; + +template class type_caster> { + typedef std::pair type; +public: + bool load(handle src, bool convert) { + if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2) + return false; + return first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) && + second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert); + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + object o1 = object(type_caster::type>::cast(src.first, policy, parent), false); + object o2 = object(type_caster::type>::cast(src.second, policy, parent), false); + if (!o1 || !o2) + return handle(); + tuple result(2); + PyTuple_SET_ITEM(result.ptr(), 0, o1.release().ptr()); + PyTuple_SET_ITEM(result.ptr(), 1, o2.release().ptr()); + return result.release(); + } + + static PYBIND11_DESCR name() { + return type_descr( + _("(") + type_caster::type>::name() + + _(", ") + type_caster::type>::name() + _(")")); + } + + template using cast_op_type = type; + + operator type() { + return type(first .operator typename type_caster::type>::template cast_op_type(), + second.operator typename type_caster::type>::template cast_op_type()); + } +protected: + type_caster::type> first; + type_caster::type> second; +}; + +template class type_caster> { + typedef std::tuple type; +public: + enum { size = sizeof...(Tuple) }; + + bool load(handle src, bool convert) { + return load(src, convert, typename make_index_sequence::type()); + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + return cast(src, policy, parent, typename make_index_sequence::type()); + } + + static PYBIND11_DESCR name() { + return type_descr( + _("(") + + detail::concat(type_caster::type>::name()...) + + _(")")); + } + + template typename std::enable_if::value, ReturnValue>::type call(Func &&f) { + return call(std::forward(f), typename make_index_sequence::type()); + } + + template typename std::enable_if::value, void_type>::type call(Func &&f) { + call(std::forward(f), typename make_index_sequence::type()); + return void_type(); + } + + template using cast_op_type = type; + + operator type() { + return cast(typename make_index_sequence::type()); + } + +protected: + template ReturnValue call(Func &&f, index_sequence) { + return f(std::get(value) + .operator typename type_caster::type>::template cast_op_type()...); + } + + template type cast(index_sequence) { + return type(std::get(value) + .operator typename type_caster::type>::template cast_op_type()...); + } + + template bool load(handle src, bool convert, index_sequence) { + if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != size) + return false; + std::array success {{ + (PyTuple_GET_ITEM(src.ptr(), Indices) != nullptr ? std::get(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert) : false)... + }}; + (void) convert; /* avoid a warning when the tuple is empty */ + for (bool r : success) + if (!r) + return false; + return true; + } + + /* Implementation: Convert a C++ tuple into a Python tuple */ + template static handle cast(const type &src, return_value_policy policy, handle parent, index_sequence) { + std::array entries {{ + object(type_caster::type>::cast(std::get(src), policy, parent), false)... + }}; + for (const auto &entry: entries) + if (!entry) + return handle(); + tuple result(size); + int counter = 0; + for (auto & entry: entries) + PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr()); + return result.release(); + } + +protected: + std::tuple::type>...> value; +}; + +/// Type caster for holder types like std::shared_ptr, etc. +template class type_caster_holder : public type_caster { +public: + using type_caster::cast; + using type_caster::typeinfo; + using type_caster::value; + using type_caster::temp; + using type_caster::copy_constructor; + + bool load(handle src, bool convert) { + if (!src || !typeinfo) { + return false; + } else if (src.ptr() == Py_None) { + value = nullptr; + return true; + } else if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) { + auto inst = (instance *) src.ptr(); + value = (void *) inst->value; + holder = inst->holder; + return true; + } + + if (convert) { + for (auto &converter : typeinfo->implicit_conversions) { + temp = object(converter(src.ptr(), typeinfo->type), false); + if (load(temp, false)) + return true; + } + } + return false; + } + + explicit operator type*() { return this->value; } + explicit operator type&() { return *(this->value); } + explicit operator holder_type*() { return &holder; } + + // Workaround for Intel compiler bug + // see pybind11 issue 94 + #if defined(__ICC) || defined(__INTEL_COMPILER) + operator holder_type&() { return holder; } + #else + explicit operator holder_type&() { return holder; } + #endif + + static handle cast(const holder_type &src, return_value_policy policy, handle parent) { + return type_caster_generic::cast( + src.get(), policy, parent, + src.get() ? &typeid(*src.get()) : nullptr, &typeid(type), + ©_constructor, &src); + } + +protected: + holder_type holder; +}; + +template struct handle_type_name { static PYBIND11_DESCR name() { return _(); } }; +template <> struct handle_type_name { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } }; + +template +struct type_caster::value>::type> { +public: + template ::value, int>::type = 0> + bool load(handle src, bool /* convert */) { value = src; return value.check(); } + + template ::value, int>::type = 0> + bool load(handle src, bool /* convert */) { value = type(src, true); return value.check(); } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name()); +}; + +NAMESPACE_END(detail) + +template inline T cast(handle handle) { + detail::type_caster::type> conv; + if (!conv.load(handle, true)) + throw cast_error("Unable to cast Python object to C++ type"); + return (T) conv; +} + +template inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) { + if (policy == return_value_policy::automatic) + policy = std::is_pointer::value ? return_value_policy::take_ownership : return_value_policy::copy; + else if (policy == return_value_policy::automatic_reference) + policy = std::is_pointer::value ? return_value_policy::reference : return_value_policy::copy; + return object(detail::type_caster::type>::cast(value, policy, parent), false); +} + +template inline T handle::cast() const { return pybind11::cast(*this); } +template <> inline void handle::cast() const { return; } + +template inline tuple make_tuple(Args&&... args_) { + const size_t size = sizeof...(Args); + std::array args { + { object(detail::type_caster::type>::cast( + std::forward(args_), policy, nullptr), false)... } + }; + for (auto &arg_value : args) + if (!arg_value) + throw cast_error("make_tuple(): unable to convert arguments to Python objects"); + tuple result(size); + int counter = 0; + for (auto &arg_value : args) + PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr()); + return result; +} + +template inline object handle::call(Args&&... args) const { + tuple args_tuple = pybind11::make_tuple(std::forward(args)...); + object result(PyObject_CallObject(m_ptr, args_tuple.ptr()), false); + if (!result) + throw error_already_set(); + return result; +} + +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/common.h b/stormpy/resources/pybind11/include/pybind11/common.h new file mode 100644 index 000000000..15047b859 --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/common.h @@ -0,0 +1,285 @@ +/* + pybind11/common.h -- Basic macros + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if !defined(NAMESPACE_BEGIN) +# define NAMESPACE_BEGIN(name) namespace name { +#endif +#if !defined(NAMESPACE_END) +# define NAMESPACE_END(name) } +#endif + +#if !defined(PYBIND11_EXPORT) +# if defined(WIN32) || defined(_WIN32) +# define PYBIND11_EXPORT __declspec(dllexport) +# else +# define PYBIND11_EXPORT __attribute__ ((visibility("default"))) +# endif +#endif + +#if defined(_MSC_VER) +# define PYBIND11_NOINLINE __declspec(noinline) +#else +# define PYBIND11_NOINLINE __attribute__ ((noinline)) +#endif + +#define PYBIND11_VERSION_MAJOR 1 +#define PYBIND11_VERSION_MINOR 5 + +/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode +#if defined(_MSC_VER) +# define HAVE_ROUND +# pragma warning(push) +# pragma warning(disable: 4510 4610 4512 4005) +# if _DEBUG +# define _DEBUG_MARKER +# undef _DEBUG +# endif +#endif + +#include +#include + +#ifdef isalnum +# undef isalnum +# undef isalpha +# undef islower +# undef isspace +# undef isupper +# undef tolower +# undef toupper +#endif + +#if defined(_MSC_VER) +# if defined(_DEBUG_MARKER) +# define _DEBUG +# undef _DEBUG_MARKER +#endif +# pragma warning(pop) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) +#define PYBIND11_BYTES_CHECK PyBytes_Check +#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyBytes_AsString +#define PYBIND11_LONG_CHECK(o) PyLong_Check(o) +#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) +#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o) +#define PYBIND11_BYTES_NAME "bytes" +#define PYBIND11_STRING_NAME "str" +#define PYBIND11_SLICE_OBJECT PyObject +#define PYBIND11_FROM_STRING PyUnicode_FromString +#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_base.ob_base.ob_type +#define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() +#else +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_) +#define PYBIND11_BYTES_CHECK PyString_Check +#define PYBIND11_BYTES_FROM_STRING PyString_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyString_AsString +#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) +#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o)) +#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o)) +#define PYBIND11_BYTES_NAME "str" +#define PYBIND11_STRING_NAME "unicode" +#define PYBIND11_SLICE_OBJECT PySliceObject +#define PYBIND11_FROM_STRING PyString_FromString +#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_type +#define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_EXPORT PyObject *init##name() +#endif + +#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code +#define PYBIND11_STRINGIFY(x) #x +#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) +#define PYBIND11_INTERNALS_ID "__pybind11_" \ + PYBIND11_TOSTRING(PYBIND11_VERSION_MAJOR) "_" PYBIND11_TOSTRING(PYBIND11_VERSION_MINOR) "__" + +#define PYBIND11_PLUGIN(name) \ + static PyObject *pybind11_init(); \ + PYBIND11_PLUGIN_IMPL(name) { \ + try { \ + return pybind11_init(); \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + PyObject *pybind11_init() + + +NAMESPACE_BEGIN(pybind11) + +typedef Py_ssize_t ssize_t; + +/// Approach used to cast a previously unknown C++ instance into a Python object +enum class return_value_policy : int { + /** Automatic: copy objects returned as values and take ownership of objects + returned as pointers */ + automatic = 0, + /** Automatic variant 2: copy objects returned as values and reference objects + returned as pointers */ + automatic_reference, + /** Reference the object and take ownership. Python will call the + destructor and delete operator when the reference count reaches zero */ + take_ownership, + /** Reference the object, but do not take ownership (dangerous when C++ code + deletes it and Python still has a nonzero reference count) */ + reference, + /** Reference the object, but do not take ownership. The object is considered + be owned by the C++ instance whose method or property returned it. The + Python object will increase the reference count of this 'parent' by 1 */ + reference_internal, + /// Create a new copy of the returned object, which will be owned by Python + copy +}; + +/// Format strings for basic number types +template struct format_descriptor { }; +#define PYBIND11_DECL_FMT(t, n) template<> struct format_descriptor { static std::string value() { return n; }; } +PYBIND11_DECL_FMT(int8_t, "b"); PYBIND11_DECL_FMT(uint8_t, "B"); PYBIND11_DECL_FMT(int16_t, "h"); PYBIND11_DECL_FMT(uint16_t, "H"); +PYBIND11_DECL_FMT(int32_t, "i"); PYBIND11_DECL_FMT(uint32_t, "I"); PYBIND11_DECL_FMT(int64_t, "q"); PYBIND11_DECL_FMT(uint64_t, "Q"); +PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?"); + +/// Information record describing a Python buffer object +struct buffer_info { + void *ptr; // Pointer to the underlying storage + size_t itemsize; // Size of individual items in bytes + size_t size; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to format_descriptor::value + int ndim; // Number of dimensions + std::vector shape; // Shape of the tensor (1 entry per dimension) + std::vector strides; // Number of entries between adjacent entries (for each per dimension) + + buffer_info(void *ptr, size_t itemsize, const std::string &format, int ndim, + const std::vector &shape, const std::vector &strides) + : ptr(ptr), itemsize(itemsize), size(1), format(format), + ndim(ndim), shape(shape), strides(strides) { + for (int i=0; ibuf), itemsize(view->itemsize), size(1), format(view->format), + ndim(view->ndim), shape(view->ndim), strides(view->ndim), view(view) { + for (int i = 0; i < view->ndim; ++i) { + shape[i] = (size_t) view->shape[i]; + strides[i] = (size_t) view->strides[i]; + size *= shape[i]; + } + } + + ~buffer_info() { + if (view) { PyBuffer_Release(view); delete view; } + } +private: + Py_buffer *view = nullptr; +}; + +NAMESPACE_BEGIN(detail) + +inline std::string error_string(); + +/// Core part of the 'instance' type which POD (needed to be able to use 'offsetof') +template struct instance_essentials { + PyObject_HEAD + type *value; + PyObject *parent; + PyObject *weakrefs; + bool owned : 1; + bool constructed : 1; +}; + +/// PyObject wrapper around generic types, includes a special holder type that is responsible for lifetime management +template > struct instance : instance_essentials { + holder_type holder; +}; + +struct overload_hash { + inline std::size_t operator()(const std::pair& v) const { + size_t value = std::hash()(v.first); + value ^= std::hash()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2); + return value; + } +}; + +/// Internal data struture used to track registered instances and types +struct internals { + std::unordered_map registered_types_cpp; // std::type_index -> type_info + std::unordered_map registered_types_py; // PyTypeObject* -> type_info + std::unordered_map registered_instances; // void * -> PyObject* + std::unordered_set, overload_hash> inactive_overload_cache; +}; + +/// Return a reference to the current 'internals' information +inline internals &get_internals(); + +/// Index sequence for convenient template metaprogramming involving tuples +template struct index_sequence { }; +template struct make_index_sequence : make_index_sequence { }; +template struct make_index_sequence <0, S...> { typedef index_sequence type; }; + +/// Strip the class from a method type +template struct remove_class {}; +template struct remove_class { typedef R type(A...); }; +template struct remove_class { typedef R type(A...); }; + +/// Helper template to strip away type modifiers +template struct intrinsic_type { typedef T type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; + +/** \brief SFINAE helper class to check if a copy constructor is usable (in contrast to + * std::is_copy_constructible, this class also checks if the 'new' operator is accessible */ +template struct is_copy_constructible { + template static std::true_type test(decltype(new T2(std::declval::type>())) *); + template static std::false_type test(...); + static const bool value = std::is_same(nullptr))>::value; +}; + +/// Helper type to replace 'void' in some expressions +struct void_type { }; + +/// to_string variant which also accepts strings +template inline typename std::enable_if::value, std::string>::type +to_string(const T &value) { return std::to_string(value); } +template <> inline std::string to_string(const std::string &value) { return value; } +template inline typename std::enable_if::value, std::string>::type +to_string(T value) { return std::to_string((int) value); } + +NAMESPACE_END(detail) + +// C++ bindings of core Python exceptions +struct stop_iteration : public std::runtime_error { public: stop_iteration(const std::string &w="") : std::runtime_error(w) {} }; +struct index_error : public std::runtime_error { public: index_error(const std::string &w="") : std::runtime_error(w) {} }; +struct error_already_set : public std::runtime_error { public: error_already_set() : std::runtime_error(detail::error_string()) {} }; +/// Thrown when pybind11::cast or handle::call fail due to a type casting error +struct cast_error : public std::runtime_error { public: cast_error(const std::string &w = "") : std::runtime_error(w) {} }; + +PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } +PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } + +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/complex.h b/stormpy/resources/pybind11/include/pybind11/complex.h new file mode 100644 index 000000000..a140f6feb --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/complex.h @@ -0,0 +1,45 @@ +/* + pybind11/complex.h: Complex number support + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +/// glibc defines I as a macro which breaks things, e.g., boost template names +#ifdef I +# undef I +#endif + +NAMESPACE_BEGIN(pybind11) + +PYBIND11_DECL_FMT(std::complex, "Zf"); +PYBIND11_DECL_FMT(std::complex, "Zd"); + +NAMESPACE_BEGIN(detail) +template class type_caster> { +public: + bool load(handle src, bool) { + Py_complex result = PyComplex_AsCComplex(src.ptr()); + if (result.real == -1.0 && PyErr_Occurred()) { + PyErr_Clear(); + return false; + } + value = std::complex((T) result.real, (T) result.imag); + return true; + } + + static handle cast(const std::complex &src, return_value_policy /* policy */, handle /* parent */) { + return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); + } + + PYBIND11_TYPE_CASTER(std::complex, _("complex")); +}; +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/descr.h b/stormpy/resources/pybind11/include/pybind11/descr.h new file mode 100644 index 000000000..b040014dc --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/descr.h @@ -0,0 +1,175 @@ +/* + pybind11/descr.h: Helper type for concatenating type signatures + either at runtime (C++11) or compile time (C++14) + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + + +#if defined(__clang__) +# if __has_feature(cxx_return_type_deduction) && __has_feature(cxx_relaxed_constexpr) +# define PYBIND11_CPP14 +# endif +#elif defined(__GNUG__) +# if __cpp_constexpr >= 201304 && __cpp_decltype_auto >= 201304 +# define PYBIND11_CPP14 +# endif +#endif + +#if defined(PYBIND11_CPP14) /* Concatenate type signatures at compile time using C++14 */ + +template class descr { + template friend class descr; +public: + constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1]) + : descr(text, types, + typename make_index_sequence::type(), + typename make_index_sequence::type()) { } + + constexpr const char *text() const { return m_text; } + constexpr const std::type_info * const * types() const { return m_types; } + + template + constexpr descr operator+(const descr &other) const { + return concat(other, + typename make_index_sequence::type(), + typename make_index_sequence::type(), + typename make_index_sequence::type(), + typename make_index_sequence::type()); + } + +protected: + template + constexpr descr( + char const (&text) [Size1+1], + const std::type_info * const (&types) [Size2+1], + index_sequence, index_sequence) + : m_text{text[Indices1]..., '\0'}, + m_types{types[Indices2]..., nullptr } {} + + template + constexpr descr + concat(const descr &other, + index_sequence, index_sequence, + index_sequence, index_sequence) const { + return descr( + { m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' }, + { m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr } + ); + } + +protected: + char m_text[Size1 + 1]; + const std::type_info * m_types[Size2 + 1]; +}; + +template constexpr descr _(char const(&text)[Size]) { + return descr(text, { nullptr }); +} + +template struct int_to_str : int_to_str { }; +template struct int_to_str<0, Digits...> { + static constexpr auto digits = descr({ ('0' + Digits)..., '\0' }, { nullptr }); +}; + +template auto constexpr _() { + return int_to_str::digits; +} + +template constexpr descr<1, 1> _() { + return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr }); +} + +inline constexpr descr<0, 0> concat() { return _(""); } +template auto constexpr concat(descr descr) { return descr; } +template auto constexpr concat(descr descr, Args&&... args) { return descr + _(", ") + concat(args...); } +template auto constexpr type_descr(descr descr) { return _("{") + descr + _("}"); } + +#define PYBIND11_DESCR constexpr auto + +#else /* Simpler C++11 implementation based on run-time memory allocation and copying */ + +class descr { +public: + PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) { + size_t nChars = len(text), nTypes = len(types); + m_text = new char[nChars]; + m_types = new const std::type_info *[nTypes]; + memcpy(m_text, text, nChars * sizeof(char)); + memcpy(m_types, types, nTypes * sizeof(const std::type_info *)); + } + + PYBIND11_NOINLINE descr friend operator+(descr &&d1, descr &&d2) { + descr r; + + size_t nChars1 = len(d1.m_text), nTypes1 = len(d1.m_types); + size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types); + + r.m_text = new char[nChars1 + nChars2 - 1]; + r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1]; + memcpy(r.m_text, d1.m_text, (nChars1-1) * sizeof(char)); + memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char)); + memcpy(r.m_types, d1.m_types, (nTypes1-1) * sizeof(std::type_info *)); + memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *)); + + delete[] d1.m_text; delete[] d1.m_types; + delete[] d2.m_text; delete[] d2.m_types; + + return r; + } + + char *text() { return m_text; } + const std::type_info * * types() { return m_types; } + +protected: + PYBIND11_NOINLINE descr() { } + + template static size_t len(const T *ptr) { // return length including null termination + const T *it = ptr; + while (*it++ != (T) 0) + ; + return it - ptr; + } + + const std::type_info **m_types = nullptr; + char *m_text = nullptr; +}; + +/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */ + +PYBIND11_NOINLINE inline descr _(const char *text) { + const std::type_info *types[1] = { nullptr }; + return descr(text, types); +} + +template PYBIND11_NOINLINE descr _() { + const std::type_info *types[2] = { &typeid(Type), nullptr }; + return descr("%", types); +} + +template PYBIND11_NOINLINE descr _() { + const std::type_info *types[1] = { nullptr }; + return descr(std::to_string(Size).c_str(), types); +} + +PYBIND11_NOINLINE inline descr concat() { return _(""); } +PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; } +template PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward(args)...); } +PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); } + +#define PYBIND11_DESCR descr +#endif + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/functional.h b/stormpy/resources/pybind11/include/pybind11/functional.h new file mode 100644 index 000000000..f00a60379 --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/functional.h @@ -0,0 +1,46 @@ +/* + pybind11/functional.h: std::function<> support + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +template struct type_caster> { + typedef std::function type; +public: + bool load(handle src_, bool) { + src_ = detail::get_function(src_); + if (!src_ || !PyCallable_Check(src_.ptr())) + return false; + object src(src_, true); + value = [src](Args... args) -> Return { + object retval(src.call(std::move(args)...)); + /* Visual studio 2015 parser issue: need parentheses around this expression */ + return (retval.template cast()); + }; + return true; + } + + template + static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { + return cpp_function(std::forward(f_), policy).release(); + } + + PYBIND11_TYPE_CASTER(type, _("function<") + + type_caster>::name() + _(" -> ") + + type_caster::type>::name() + + _(">")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/numpy.h b/stormpy/resources/pybind11/include/pybind11/numpy.h new file mode 100644 index 000000000..3386876e5 --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/numpy.h @@ -0,0 +1,393 @@ +/* + pybind11/numpy.h: Basic NumPy support, auto-vectorization support + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include "complex.h" +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +NAMESPACE_BEGIN(pybind11) + +template struct npy_format_descriptor { }; + +class array : public buffer { +public: + struct API { + enum Entries { + API_PyArray_Type = 2, + API_PyArray_DescrFromType = 45, + API_PyArray_FromAny = 69, + API_PyArray_NewCopy = 85, + API_PyArray_NewFromDescr = 94, + + NPY_C_CONTIGUOUS_ = 0x0001, + NPY_F_CONTIGUOUS_ = 0x0002, + NPY_ARRAY_FORCECAST_ = 0x0010, + NPY_ENSURE_ARRAY_ = 0x0040, + NPY_BOOL_ = 0, + NPY_BYTE_, NPY_UBYTE_, + NPY_SHORT_, NPY_USHORT_, + NPY_INT_, NPY_UINT_, + NPY_LONG_, NPY_ULONG_, + NPY_LONGLONG_, NPY_ULONGLONG_, + NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_, + NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_ + }; + + static API lookup() { + module m = module::import("numpy.core.multiarray"); + object c = (object) m.attr("_ARRAY_API"); +#if PY_MAJOR_VERSION >= 3 + void **api_ptr = (void **) (c ? PyCapsule_GetPointer(c.ptr(), NULL) : nullptr); +#else + void **api_ptr = (void **) (c ? PyCObject_AsVoidPtr(c.ptr()) : nullptr); +#endif + API api; + api.PyArray_Type_ = (decltype(api.PyArray_Type_)) api_ptr[API_PyArray_Type]; + api.PyArray_DescrFromType_ = (decltype(api.PyArray_DescrFromType_)) api_ptr[API_PyArray_DescrFromType]; + api.PyArray_FromAny_ = (decltype(api.PyArray_FromAny_)) api_ptr[API_PyArray_FromAny]; + api.PyArray_NewCopy_ = (decltype(api.PyArray_NewCopy_)) api_ptr[API_PyArray_NewCopy]; + api.PyArray_NewFromDescr_ = (decltype(api.PyArray_NewFromDescr_)) api_ptr[API_PyArray_NewFromDescr]; + return api; + } + + bool PyArray_Check_(PyObject *obj) const { return (bool) PyObject_TypeCheck(obj, PyArray_Type_); } + + PyObject *(*PyArray_DescrFromType_)(int); + PyObject *(*PyArray_NewFromDescr_) + (PyTypeObject *, PyObject *, int, Py_intptr_t *, + Py_intptr_t *, void *, int, PyObject *); + PyObject *(*PyArray_NewCopy_)(PyObject *, int); + PyTypeObject *PyArray_Type_; + PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *); + }; + + PYBIND11_OBJECT_DEFAULT(array, buffer, lookup_api().PyArray_Check_) + + template array(size_t size, const Type *ptr) { + API& api = lookup_api(); + PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor::value); + if (descr == nullptr) + pybind11_fail("NumPy: unsupported buffer format!"); + Py_intptr_t shape = (Py_intptr_t) size; + object tmp = object(api.PyArray_NewFromDescr_( + api.PyArray_Type_, descr, 1, &shape, nullptr, (void *) ptr, 0, nullptr), false); + if (ptr && tmp) + tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false); + if (!tmp) + pybind11_fail("NumPy: unable to create array!"); + m_ptr = tmp.release().ptr(); + } + + array(const buffer_info &info) { + API& api = lookup_api(); + if ((info.format.size() < 1) || (info.format.size() > 2)) + pybind11_fail("Unsupported buffer format!"); + int fmt = (int) info.format[0]; + if (info.format == "Zd") fmt = API::NPY_CDOUBLE_; + else if (info.format == "Zf") fmt = API::NPY_CFLOAT_; + + PyObject *descr = api.PyArray_DescrFromType_(fmt); + if (descr == nullptr) + pybind11_fail("NumPy: unsupported buffer format '" + info.format + "'!"); + object tmp(api.PyArray_NewFromDescr_( + api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0], + (Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false); + if (info.ptr && tmp) + tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false); + if (!tmp) + pybind11_fail("NumPy: unable to create array!"); + m_ptr = tmp.release().ptr(); + } + +protected: + static API &lookup_api() { + static API api = API::lookup(); + return api; + } +}; + +template class array_t : public array { +public: + PYBIND11_OBJECT_CVT(array_t, array, is_non_null, m_ptr = ensure(m_ptr)); + array_t() : array() { } + static bool is_non_null(PyObject *ptr) { return ptr != nullptr; } + static PyObject *ensure(PyObject *ptr) { + if (ptr == nullptr) + return nullptr; + API &api = lookup_api(); + PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor::value); + PyObject *result = api.PyArray_FromAny_( + ptr, descr, 0, 0, API::NPY_C_CONTIGUOUS_ | API::NPY_ENSURE_ARRAY_ + | API::NPY_ARRAY_FORCECAST_, nullptr); + Py_DECREF(ptr); + return result; + } +}; + +#define DECL_FMT(t, n) template<> struct npy_format_descriptor { enum { value = array::API::n }; } +DECL_FMT(int8_t, NPY_BYTE_); DECL_FMT(uint8_t, NPY_UBYTE_); DECL_FMT(int16_t, NPY_SHORT_); +DECL_FMT(uint16_t, NPY_USHORT_); DECL_FMT(int32_t, NPY_INT_); DECL_FMT(uint32_t, NPY_UINT_); +DECL_FMT(int64_t, NPY_LONGLONG_); DECL_FMT(uint64_t, NPY_ULONGLONG_); DECL_FMT(float, NPY_FLOAT_); +DECL_FMT(double, NPY_DOUBLE_); DECL_FMT(bool, NPY_BOOL_); DECL_FMT(std::complex, NPY_CFLOAT_); +DECL_FMT(std::complex, NPY_CDOUBLE_); +#undef DECL_FMT + +NAMESPACE_BEGIN(detail) + +template +using array_iterator = typename std::add_pointer::type; + +template +array_iterator array_begin(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr)); +} + +template +array_iterator array_end(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr) + buffer.size); +} + +class common_iterator { +public: + using container_type = std::vector; + using value_type = container_type::value_type; + using size_type = container_type::size_type; + + common_iterator() : p_ptr(0), m_strides() {} + + common_iterator(void* ptr, const container_type& strides, const std::vector& shape) + : p_ptr(reinterpret_cast(ptr)), m_strides(strides.size()) { + m_strides.back() = static_cast(strides.back()); + for (size_type i = m_strides.size() - 1; i != 0; --i) { + size_type j = i - 1; + value_type s = static_cast(shape[i]); + m_strides[j] = strides[j] + m_strides[i] - strides[i] * s; + } + } + + void increment(size_type dim) { + p_ptr += m_strides[dim]; + } + + void* data() const { + return p_ptr; + } + +private: + char* p_ptr; + container_type m_strides; +}; + +template class multi_array_iterator { +public: + using container_type = std::vector; + + multi_array_iterator(const std::array &buffers, + const std::vector &shape) + : m_shape(shape.size()), m_index(shape.size(), 0), + m_common_iterator() { + + // Manual copy to avoid conversion warning if using std::copy + for (size_t i = 0; i < shape.size(); ++i) + m_shape[i] = static_cast(shape[i]); + + container_type strides(shape.size()); + for (size_t i = 0; i < N; ++i) + init_common_iterator(buffers[i], shape, m_common_iterator[i], strides); + } + + multi_array_iterator& operator++() { + for (size_t j = m_index.size(); j != 0; --j) { + size_t i = j - 1; + if (++m_index[i] != m_shape[i]) { + increment_common_iterator(i); + break; + } else { + m_index[i] = 0; + } + } + return *this; + } + + template const T& data() const { + return *reinterpret_cast(m_common_iterator[K].data()); + } + +private: + + using common_iter = common_iterator; + + void init_common_iterator(const buffer_info &buffer, + const std::vector &shape, + common_iter &iterator, container_type &strides) { + auto buffer_shape_iter = buffer.shape.rbegin(); + auto buffer_strides_iter = buffer.strides.rbegin(); + auto shape_iter = shape.rbegin(); + auto strides_iter = strides.rbegin(); + + while (buffer_shape_iter != buffer.shape.rend()) { + if (*shape_iter == *buffer_shape_iter) + *strides_iter = static_cast(*buffer_strides_iter); + else + *strides_iter = 0; + + ++buffer_shape_iter; + ++buffer_strides_iter; + ++shape_iter; + ++strides_iter; + } + + std::fill(strides_iter, strides.rend(), 0); + iterator = common_iter(buffer.ptr, strides, shape); + } + + void increment_common_iterator(size_t dim) { + for (auto &iter : m_common_iterator) + iter.increment(dim); + } + + container_type m_shape; + container_type m_index; + std::array m_common_iterator; +}; + +template +bool broadcast(const std::array& buffers, int& ndim, std::vector& shape) { + ndim = std::accumulate(buffers.begin(), buffers.end(), 0, [](int res, const buffer_info& buf) { + return std::max(res, buf.ndim); + }); + + shape = std::vector(static_cast(ndim), 1); + bool trivial_broadcast = true; + for (size_t i = 0; i < N; ++i) { + auto res_iter = shape.rbegin(); + bool i_trivial_broadcast = (buffers[i].size == 1) || (buffers[i].ndim == ndim); + for (auto shape_iter = buffers[i].shape.rbegin(); + shape_iter != buffers[i].shape.rend(); ++shape_iter, ++res_iter) { + + if (*res_iter == 1) + *res_iter = *shape_iter; + else if ((*shape_iter != 1) && (*res_iter != *shape_iter)) + pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!"); + + i_trivial_broadcast = i_trivial_broadcast && (*res_iter == *shape_iter); + } + trivial_broadcast = trivial_broadcast && i_trivial_broadcast; + } + return trivial_broadcast; +} + +template +struct vectorize_helper { + typename std::remove_reference::type f; + + template + vectorize_helper(T&&f) : f(std::forward(f)) { } + + object operator()(array_t... args) { + return run(args..., typename make_index_sequence::type()); + } + + template object run(array_t&... args, index_sequence index) { + /* Request buffers from all parameters */ + const size_t N = sizeof...(Args); + + std::array buffers {{ args.request()... }}; + + /* Determine dimensions parameters of output array */ + int ndim = 0; + std::vector shape(0); + bool trivial_broadcast = broadcast(buffers, ndim, shape); + + size_t size = 1; + std::vector strides(ndim); + if (ndim > 0) { + strides[ndim-1] = sizeof(Return); + for (int i = ndim - 1; i > 0; --i) { + strides[i - 1] = strides[i] * shape[i]; + size *= shape[i]; + } + size *= shape[0]; + } + + if (size == 1) + return cast(f(*((Args *) buffers[Index].ptr)...)); + + array result(buffer_info(nullptr, sizeof(Return), + format_descriptor::value(), + ndim, shape, strides)); + + buffer_info buf = result.request(); + Return *output = (Return *) buf.ptr; + + if(trivial_broadcast) { + /* Call the function */ + for (size_t i=0; i(buffers, buf, index); + } + + return result; + } + + template + void apply_broadcast(const std::array &buffers, + buffer_info &output, index_sequence) { + using input_iterator = multi_array_iterator; + using output_iterator = array_iterator; + + input_iterator input_iter(buffers, output.shape); + output_iterator output_end = array_end(output); + + for (output_iterator iter = array_begin(output); + iter != output_end; ++iter, ++input_iter) { + *iter = f((input_iter.template data())...); + } + } +}; + +template struct handle_type_name> { + static PYBIND11_DESCR name() { return _("array[") + type_caster::name() + _("]"); } +}; + +NAMESPACE_END(detail) + +template +detail::vectorize_helper vectorize(const Func &f, Return (*) (Args ...)) { + return detail::vectorize_helper(f); +} + +template +detail::vectorize_helper vectorize(Return (*f) (Args ...)) { + return vectorize(f, f); +} + +template auto vectorize(func &&f) -> decltype( + vectorize(std::forward(f), (typename detail::remove_class::type::operator())>::type *) nullptr)) { + return vectorize(std::forward(f), (typename detail::remove_class::type::operator())>::type *) nullptr); +} + +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/stormpy/resources/pybind11/include/pybind11/operators.h b/stormpy/resources/pybind11/include/pybind11/operators.h new file mode 100644 index 000000000..b10bfe30c --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/operators.h @@ -0,0 +1,153 @@ +/* + pybind11/operator.h: Metatemplates for operator overloading + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type())) +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +/// Enumeration with all supported operator types +enum op_id : int { + op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift, + op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert, + op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le, + op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift, + op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero, + op_repr, op_truediv +}; + +enum op_type : int { + op_l, /* base type on left */ + op_r, /* base type on right */ + op_u /* unary operator */ +}; + +struct self_t { }; +static const self_t self = self_t(); + +/// Type for an unused type slot +struct undefined_t { }; + +/// Don't warn about an unused variable +inline self_t __self() { return self; } + +/// base template of operator implementations +template struct op_impl { }; + +/// Operator implementation generator +template struct op_ { + template void execute(pybind11::class_ &class_, const Extra&... extra) const { + typedef typename std::conditional::value, Base, L>::type L_type; + typedef typename std::conditional::value, Base, R>::type R_type; + typedef op_impl op; + class_.def(op::name(), &op::execute, extra...); + } + template void execute_cast(pybind11::class_ &class_, const Extra&... extra) const { + typedef typename std::conditional::value, Base, L>::type L_type; + typedef typename std::conditional::value, Base, R>::type R_type; + typedef op_impl op; + class_.def(op::name(), &op::execute_cast, extra...); + } +}; + +#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \ + static B execute_cast(const L &l, const R &r) { return B(expr); } \ +}; \ +template struct op_impl { \ + static char const* name() { return "__" #rid "__"; } \ + static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \ + static B execute_cast(const R &r, const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &, const self_t &) { \ + return op_(); \ +} \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} \ +template op_ op(const T &, const self_t &) { \ + return op_(); \ +} + +#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \ + static B execute_cast(L &l, const R &r) { return B(expr); } \ +}; \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} + +#define PYBIND11_UNARY_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l) -> decltype(expr) { return expr; } \ + static B execute_cast(const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &) { \ + return op_(); \ +} + +PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r) +PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r) +PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r) +#if PY_MAJOR_VERSION >= 3 +PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r) +#else +PYBIND11_BINARY_OPERATOR(div, rdiv, operator/, l / r) +#endif +PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r) +PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r) +PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r) +PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r) +PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r) +PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r) +PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r) +PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r) +PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r) +PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r) +PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r) +PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r) +//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r)) +PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r) +PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r) +PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r) +PYBIND11_INPLACE_OPERATOR(idiv, operator/=, l /= r) +PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r) +PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r) +PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r) +PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r) +PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r) +PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r) +PYBIND11_UNARY_OPERATOR(neg, operator-, -l) +PYBIND11_UNARY_OPERATOR(pos, operator+, +l) +PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l)) +PYBIND11_UNARY_OPERATOR(invert, operator~, (~l)) +PYBIND11_UNARY_OPERATOR(bool, operator!, !!l) +PYBIND11_UNARY_OPERATOR(int, int_, (int) l) +PYBIND11_UNARY_OPERATOR(float, float_, (double) l) + +#undef PYBIND11_BINARY_OPERATOR +#undef PYBIND11_INPLACE_OPERATOR +#undef PYBIND11_UNARY_OPERATOR +NAMESPACE_END(detail) + +using detail::self; + +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/pybind11.h b/stormpy/resources/pybind11/include/pybind11/pybind11.h new file mode 100644 index 000000000..22044feeb --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/pybind11.h @@ -0,0 +1,1106 @@ +/* + pybind11/pybind11.h: Main header file of the C++11 python + binding generator library + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning) +# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name +# pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter +# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# pragma warning(push) +# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline" +#elif defined(__GNUG__) and !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-but-set-parameter" +# pragma GCC diagnostic ignored "-Wunused-but-set-variable" +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +#include "attr.h" + +NAMESPACE_BEGIN(pybind11) + +/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object +class cpp_function : public function { +protected: + /// Picks a suitable return value converter from cast.h + template using return_value_caster = + detail::type_caster::value, detail::void_type, typename detail::intrinsic_type::type>::type>; + + /// Picks a suitable argument value converter from cast.h + template using arg_value_caster = + detail::type_caster>; +public: + cpp_function() { } + + /// Vanilla function pointers + template + cpp_function(Return (*f)(Args...), const Extra&... extra) { + auto rec = new detail::function_record(); + rec->data = (void *) f; + + typedef arg_value_caster cast_in; + typedef return_value_caster cast_out; + + /* Dispatch code which converts function arguments and performs the actual function call */ + rec->impl = [](detail::function_record *rec, handle pyArgs, handle parent) -> handle { + cast_in args; + + /* Try to cast the function arguments into the C++ domain */ + if (!args.load(pyArgs, true)) + return PYBIND11_TRY_NEXT_OVERLOAD; + + /* Invoke call policy pre-call hook */ + detail::process_attributes::precall(pyArgs); + + /* Do the call and convert the return value back into the Python domain */ + handle result = cast_out::cast( + args.template call((Return (*) (Args...)) rec->data), + rec->policy, parent); + + /* Invoke call policy post-call hook */ + detail::process_attributes::postcall(pyArgs, result); + + return result; + }; + + /* Process any user-provided function attributes */ + detail::process_attributes::init(extra..., rec); + + /* Generate a readable signature describing the function's arguments and return value types */ + using detail::descr; + PYBIND11_DESCR signature = cast_in::name() + detail::_(" -> ") + cast_out::name(); + + /* Register the function with Python from generic (non-templated) code */ + initialize(rec, signature.text(), signature.types(), sizeof...(Args)); + } + + /// Delegating helper constructor to deal with lambda functions + template cpp_function(Func &&f, const Extra&... extra) { + initialize(std::forward(f), + (typename detail::remove_class::type::operator())>::type *) nullptr, extra...); + } + + /// Delegating helper constructor to deal with class methods (non-const) + template cpp_function( + Return (Class::*f)(Arg...), const Extra&... extra) { + initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*) (Class *, Arg...)) nullptr, extra...); + } + + /// Delegating helper constructor to deal with class methods (const) + template cpp_function( + Return (Class::*f)(Arg...) const, const Extra&... extra) { + initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*)(const Class *, Arg ...)) nullptr, extra...); + } + + /// Return the function name + object name() const { return attr("__name__"); } + +protected: + /// Special internal constructor for functors, lambda functions, etc. + template + void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) { + struct capture { typename std::remove_reference::type f; }; + + /* Store the function including any extra state it might have (e.g. a lambda capture object) */ + auto rec = new detail::function_record(); + rec->data = new capture { std::forward(f) }; + + /* Create a cleanup handler, but only if we have to (less generated code) */ + if (!std::is_trivially_destructible::value) + rec->free_data = [](void *ptr) { delete (capture *) ptr; }; + else + rec->free_data = operator delete; + + typedef arg_value_caster cast_in; + typedef return_value_caster cast_out; + + /* Dispatch code which converts function arguments and performs the actual function call */ + rec->impl = [](detail::function_record *rec, handle pyArgs, handle parent) -> handle { + cast_in args; + + /* Try to cast the function arguments into the C++ domain */ + if (!args.load(pyArgs, true)) + return PYBIND11_TRY_NEXT_OVERLOAD; + + /* Invoke call policy pre-call hook */ + detail::process_attributes::precall(pyArgs); + + /* Do the call and convert the return value back into the Python domain */ + handle result = cast_out::cast( + args.template call(((capture *) rec->data)->f), + rec->policy, parent); + + /* Invoke call policy post-call hook */ + detail::process_attributes::postcall(pyArgs, result); + + return result; + }; + + /* Process any user-provided function attributes */ + detail::process_attributes::init(extra..., rec); + + /* Generate a readable signature describing the function's arguments and return value types */ + using detail::descr; + PYBIND11_DESCR signature = cast_in::name() + detail::_(" -> ") + cast_out::name(); + + /* Register the function with Python from generic (non-templated) code */ + initialize(rec, signature.text(), signature.types(), sizeof...(Args)); + } + + /// Register a function call with Python (generic non-templated code goes here) + void initialize(detail::function_record *rec, const char *text, + const std::type_info *const *types, int args) { + + /* Create copies of all referenced C-style strings */ + rec->name = strdup(rec->name ? rec->name : ""); + if (rec->doc) rec->doc = strdup(rec->doc); + for (auto &a: rec->args) { + if (a.name) + a.name = strdup(a.name); + if (a.descr) + a.descr = strdup(a.descr); + else if (a.value) + a.descr = strdup(((std::string) ((object) handle(a.value).attr("__repr__")).call().str()).c_str()); + } + auto const ®istered_types = detail::get_internals().registered_types_cpp; + + /* Generate a proper function signature */ + std::string signature; + size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0; + while (true) { + char c = text[char_index++]; + if (c == '\0') + break; + + if (c == '{') { + if (type_depth == 1 && arg_index < rec->args.size()) { + signature += rec->args[arg_index].name; + signature += " : "; + } + ++type_depth; + } else if (c == '}') { + --type_depth; + if (type_depth == 1 && arg_index < rec->args.size()) { + if (rec->args[arg_index].descr) { + signature += " = "; + signature += rec->args[arg_index].descr; + } + arg_index++; + } + } else if (c == '%') { + const std::type_info *t = types[type_index++]; + if (!t) + pybind11_fail("Internal error while parsing type signature (1)"); + auto it = registered_types.find(std::type_index(*t)); + if (it != registered_types.end()) { + signature += ((const detail::type_info *) it->second)->type->tp_name; + } else { + std::string tname(t->name()); + detail::clean_type_id(tname); + signature += tname; + } + } else { + signature += c; + } + } + if (type_depth != 0 || types[type_index] != nullptr) + pybind11_fail("Internal error while parsing type signature (2)"); + + #if !defined(PYBIND11_CPP14) + delete[] types; + delete[] text; + #endif + +#if PY_MAJOR_VERSION < 3 + if (strcmp(rec->name, "__next__") == 0) { + std::free(rec->name); + rec->name = strdup("next"); + } +#endif + + if (!rec->args.empty() && (int) rec->args.size() != args) + pybind11_fail( + "cpp_function(): function \"" + std::string(rec->name) + "\" takes " + + std::to_string(args) + " arguments, but " + std::to_string(rec->args.size()) + + " pybind11::arg entries were specified!"); + + rec->is_constructor = !strcmp(rec->name, "__init__"); + rec->signature = strdup(signature.c_str()); + rec->args.shrink_to_fit(); + +#if PY_MAJOR_VERSION < 3 + if (rec->sibling && PyMethod_Check(rec->sibling.ptr())) + rec->sibling = PyMethod_GET_FUNCTION(rec->sibling.ptr()); +#endif + + detail::function_record *chain = nullptr, *chain_start = rec; + if (rec->sibling && PyCFunction_Check(rec->sibling.ptr())) { + capsule rec_capsule(PyCFunction_GetSelf(rec->sibling.ptr()), true); + chain = (detail::function_record *) rec_capsule; + /* Never append a method to an overload chain of a parent class; + instead, hide the parent's overloads in this case */ + if (chain->class_ != rec->class_) + chain = nullptr; + } + + if (!chain) { + /* No existing overload was found, create a new function object */ + rec->def = new PyMethodDef(); + memset(rec->def, 0, sizeof(PyMethodDef)); + rec->def->ml_name = rec->name; + rec->def->ml_meth = reinterpret_cast(*dispatcher); + rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; + + capsule rec_capsule(rec, [](PyObject *o) { + destruct((detail::function_record *) PyCapsule_GetPointer(o, nullptr)); + }); + + object scope_module; + if (rec->scope) { + scope_module = (object) rec->scope.attr("__module__"); + if (!scope_module) + scope_module = (object) rec->scope.attr("__name__"); + } + + m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate function object"); + } else { + /* Append at the end of the overload chain */ + m_ptr = rec->sibling.ptr(); + inc_ref(); + chain_start = chain; + while (chain->next) + chain = chain->next; + chain->next = rec; + } + + std::string signatures; + int index = 0; + /* Create a nice pydoc rec including all signatures and + docstrings of the functions in the overload chain */ + if (chain) { + // First a generic signature + signatures += rec->name; + signatures += "(*args, **kwargs)\n"; + signatures += "Overloaded function.\n\n"; + } + // Then specific overload signatures + for (auto it = chain_start; it != nullptr; it = it->next) { + if (chain) + signatures += std::to_string(++index) + ". "; + signatures += rec->name; + signatures += it->signature; + signatures += "\n"; + if (it->doc && strlen(it->doc) > 0) { + signatures += "\n"; + signatures += it->doc; + signatures += "\n"; + } + if (it->next) + signatures += "\n"; + } + + /* Install docstring */ + PyCFunctionObject *func = (PyCFunctionObject *) m_ptr; + if (func->m_ml->ml_doc) + std::free((char *) func->m_ml->ml_doc); + func->m_ml->ml_doc = strdup(signatures.c_str()); + + if (rec->class_) { + m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->class_.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object"); + Py_DECREF(func); + } + } + + /// When a cpp_function is GCed, release any memory allocated by pybind11 + static void destruct(detail::function_record *rec) { + while (rec) { + detail::function_record *next = rec->next; + if (rec->free_data) + rec->free_data(rec->data); + std::free((char *) rec->name); + std::free((char *) rec->doc); + std::free((char *) rec->signature); + for (auto &arg: rec->args) { + std::free((char *) arg.name); + std::free((char *) arg.descr); + arg.value.dec_ref(); + } + if (rec->def) { + std::free((char *) rec->def->ml_doc); + delete rec->def; + } + delete rec; + rec = next; + } + } + + /// Main dispatch logic for calls to functions bound using pybind11 + static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs) { + /* Iterator over the list of potentially admissible overloads */ + detail::function_record *overloads = (detail::function_record *) PyCapsule_GetPointer(self, nullptr), + *it = overloads; + + /* Need to know how many arguments + keyword arguments there are to pick the right overload */ + int nargs = (int) PyTuple_Size(args), + nkwargs = kwargs ? (int) PyDict_Size(kwargs) : 0; + + handle parent = nargs > 0 ? PyTuple_GetItem(args, 0) : nullptr, + result = PYBIND11_TRY_NEXT_OVERLOAD; + try { + for (; it != nullptr; it = it->next) { + tuple args_(args, true); + int kwargs_consumed = 0; + + /* For each overload: + 1. If the required list of arguments is longer than the + actually provided amount, create a copy of the argument + list and fill in any available keyword/default arguments. + 2. Ensure that all keyword arguments were "consumed" + 3. Call the function call dispatcher (function_record::impl) + */ + + if (nargs < (int) it->args.size()) { + args_ = tuple(it->args.size()); + for (int i = 0; i < nargs; ++i) { + handle item = PyTuple_GET_ITEM(args, i); + PyTuple_SET_ITEM(args_.ptr(), i, item.inc_ref().ptr()); + } + + int arg_ctr = 0; + for (auto const &it2 : it->args) { + int index = arg_ctr++; + if (PyTuple_GET_ITEM(args_.ptr(), index)) + continue; + + handle value; + if (kwargs) + value = PyDict_GetItemString(kwargs, it2.name); + + if (value) + kwargs_consumed++; + else if (it2.value) + value = it2.value; + + if (value) { + PyTuple_SET_ITEM(args_.ptr(), index, value.inc_ref().ptr()); + } else { + kwargs_consumed = -1; /* definite failure */ + break; + } + } + } + + if (kwargs_consumed == nkwargs) + result = it->impl(it, args_, parent); + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + break; + } + } catch (const error_already_set &) { return nullptr; + } catch (const index_error &e) { PyErr_SetString(PyExc_IndexError, e.what()); return nullptr; + } catch (const stop_iteration &e) { PyErr_SetString(PyExc_StopIteration, e.what()); return nullptr; + } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return nullptr; + } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return nullptr; + } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return nullptr; + } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return nullptr; + } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return nullptr; + } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return nullptr; + } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return nullptr; + } catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); + return nullptr; + } + + if (result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + std::string msg = "Incompatible function arguments. The " + "following argument types are supported:\n"; + int ctr = 0; + for (detail::function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { + msg += " "+ std::to_string(++ctr) + ". "; + msg += it2->signature; + msg += "\n"; + } + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else if (!result) { + std::string msg = "Unable to convert function return value to a " + "Python type! The signature was\n\t"; + msg += it->signature; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else { + if (overloads->is_constructor) { + /* When a construtor ran successfully, the corresponding + holder type (e.g. std::unique_ptr) must still be initialized. */ + PyObject *inst = PyTuple_GetItem(args, 0); + auto tinfo = detail::get_type_info(Py_TYPE(inst)); + tinfo->init_holder(inst, nullptr); + } + return result.ptr(); + } + } +}; + +/// Wrapper for Python extension modules +class module : public object { +public: + PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check) + + module(const char *name, const char *doc = nullptr) { +#if PY_MAJOR_VERSION >= 3 + PyModuleDef *def = new PyModuleDef(); + memset(def, 0, sizeof(PyModuleDef)); + def->m_name = name; + def->m_doc = doc; + def->m_size = -1; + Py_INCREF(def); + m_ptr = PyModule_Create(def); +#else + m_ptr = Py_InitModule3(name, nullptr, doc); +#endif + if (m_ptr == nullptr) + pybind11_fail("Internal error in module::module()"); + inc_ref(); + } + + template + module &def(const char *name_, Func &&f, const Extra& ... extra) { + cpp_function func(std::forward(f), name(name_), + sibling((handle) attr(name_)), scope(*this), extra...); + /* PyModule_AddObject steals a reference to 'func' */ + PyModule_AddObject(ptr(), name_, func.inc_ref().ptr()); + return *this; + } + + module def_submodule(const char *name, const char *doc = nullptr) { + std::string full_name = std::string(PyModule_GetName(m_ptr)) + + std::string(".") + std::string(name); + module result(PyImport_AddModule(full_name.c_str()), true); + if (doc) + result.attr("__doc__") = pybind11::str(doc); + attr(name) = result; + return result; + } + + static module import(const char *name) { + PyObject *obj = PyImport_ImportModule(name); + if (!obj) + pybind11_fail("Module \"" + std::string(name) + "\" not found!"); + return module(obj, false); + } +}; + +NAMESPACE_BEGIN(detail) +/// Generic support for creating new Python heap types +class generic_type : public object { + template friend class class_; +public: + PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check) +protected: + void initialize(type_record *rec) { + if (rec->base_type) { + if (rec->base_handle) + pybind11_fail("generic_type: specified base type multiple times!"); + rec->base_handle = detail::get_type_handle(*(rec->base_type)); + if (!rec->base_handle) { + std::string tname(rec->base_type->name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(rec->name) + + "\" referenced unknown base type \"" + tname + "\""); + } + } + + object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false); + object name(PYBIND11_FROM_STRING(rec->name), false); + auto type = (PyHeapTypeObject*) type_holder.ptr(); + + if (!type_holder || !name) + pybind11_fail("generic_type: unable to create type object!"); + + /* Register supplemental type information in C++ dict */ + auto &internals = get_internals(); + detail::type_info *tinfo = new detail::type_info(); + tinfo->type = (PyTypeObject *) type; + tinfo->type_size = rec->type_size; + tinfo->init_holder = rec->init_holder; + internals.registered_types_cpp[std::type_index(*(rec->type))] = tinfo; + internals.registered_types_py[type] = tinfo; + + object scope_module; + if (rec->scope) { + scope_module = (object) rec->scope.attr("__module__"); + if (!scope_module) + scope_module = (object) rec->scope.attr("__name__"); + } + + std::string full_name = (scope_module ? ((std::string) scope_module.str() + "." + rec->name) + : std::string(rec->name)); + /* Basic type attributes */ + type->ht_type.tp_name = strdup(full_name.c_str()); + type->ht_type.tp_basicsize = rec->instance_size; + type->ht_type.tp_base = (PyTypeObject *) rec->base_handle.ptr(); + rec->base_handle.inc_ref(); + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + /* Qualified names for Python >= 3.3 */ + object scope_qualname; + if (rec->scope) + scope_qualname = (object) rec->scope.attr("__qualname__"); + if (scope_qualname) { + type->ht_qualname = PyUnicode_FromFormat( + "%U.%U", scope_qualname.ptr(), name.ptr()); + } else { + type->ht_qualname = name.ptr(); + name.inc_ref(); + } +#endif + type->ht_name = name.release().ptr(); + + /* Supported protocols */ + type->ht_type.tp_as_number = &type->as_number; + type->ht_type.tp_as_sequence = &type->as_sequence; + type->ht_type.tp_as_mapping = &type->as_mapping; + + /* Supported elementary operations */ + type->ht_type.tp_init = (initproc) init; + type->ht_type.tp_new = (newfunc) new_instance; + type->ht_type.tp_dealloc = rec->dealloc; + + /* Support weak references (needed for the keep_alive feature) */ + type->ht_type.tp_weaklistoffset = offsetof(instance_essentials, weakrefs); + + /* Flags */ + type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; +#if PY_MAJOR_VERSION < 3 + type->ht_type.tp_flags |= Py_TPFLAGS_CHECKTYPES; +#endif + type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC; + + if (rec->doc) { + /* Allocate memory for docstring (using PyObject_MALLOC, since + Python will free this later on) */ + size_t size = strlen(rec->doc) + 1; + type->ht_type.tp_doc = (char *) PyObject_MALLOC(size); + memcpy((void *) type->ht_type.tp_doc, rec->doc, size); + } + + if (PyType_Ready(&type->ht_type) < 0) + pybind11_fail("generic_type: PyType_Ready failed!"); + + m_ptr = type_holder.ptr(); + + if (scope_module) // Needed by pydoc + attr("__module__") = scope_module; + + /* Register type with the parent scope */ + if (rec->scope) + rec->scope.attr(handle(type->ht_name)) = *this; + + type_holder.release(); + } + + /// Allocate a metaclass on demand (for static properties) + handle metaclass() { + auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type; + auto &ob_type = PYBIND11_OB_TYPE(ht_type); + + if (ob_type == &PyType_Type) { + std::string name_ = std::string(ht_type.tp_name) + "__Meta"; + object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false); + object name(PYBIND11_FROM_STRING(name_.c_str()), false); + if (!type_holder || !name) + pybind11_fail("generic_type::metaclass(): unable to create type object!"); + + auto type = (PyHeapTypeObject*) type_holder.ptr(); + type->ht_name = name.release().ptr(); +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + /* Qualified names for Python >= 3.3 */ + type->ht_qualname = PyUnicode_FromFormat( + "%U__Meta", ((object) attr("__qualname__")).ptr()); +#endif + type->ht_type.tp_name = strdup(name_.c_str()); + type->ht_type.tp_base = ob_type; + type->ht_type.tp_flags |= (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE) & + ~Py_TPFLAGS_HAVE_GC; + + if (PyType_Ready(&type->ht_type) < 0) + pybind11_fail("generic_type::metaclass(): PyType_Ready failed!"); + + ob_type = (PyTypeObject *) type_holder.release().ptr(); + } + return handle((PyObject *) ob_type); + } + + static int init(void *self, PyObject *, PyObject *) { + std::string msg = std::string(Py_TYPE(self)->tp_name) + ": No constructor defined!"; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return -1; + } + + static PyObject *new_instance(PyTypeObject *type, PyObject *, PyObject *) { + instance *self = (instance *) PyType_GenericAlloc((PyTypeObject *) type, 0); + auto tinfo = detail::get_type_info(type); + self->value = ::operator new(tinfo->type_size); + self->owned = true; + self->parent = nullptr; + self->constructed = false; + detail::get_internals().registered_instances[self->value] = (PyObject *) self; + return (PyObject *) self; + } + + static void dealloc(instance *self) { + if (self->value) { + bool dont_cache = self->parent && ((instance *) self->parent)->value == self->value; + if (!dont_cache) { // avoid an issue with internal references matching their parent's address + auto ®istered_instances = detail::get_internals().registered_instances; + auto it = registered_instances.find(self->value); + if (it == registered_instances.end()) + pybind11_fail("generic_type::dealloc(): Tried to deallocate unregistered instance!"); + registered_instances.erase(it); + } + Py_XDECREF(self->parent); + if (self->weakrefs) + PyObject_ClearWeakRefs((PyObject *) self); + } + Py_TYPE(self)->tp_free((PyObject*) self); + } + + void install_buffer_funcs( + buffer_info *(*get_buffer)(PyObject *, void *), + void *get_buffer_data) { + PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr; + type->ht_type.tp_as_buffer = &type->as_buffer; +#if PY_MAJOR_VERSION < 3 + type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; +#endif + type->as_buffer.bf_getbuffer = getbuffer; + type->as_buffer.bf_releasebuffer = releasebuffer; + auto tinfo = detail::get_type_info(&type->ht_type); + tinfo->get_buffer = get_buffer; + tinfo->get_buffer_data = get_buffer_data; + } + + static int getbuffer(PyObject *obj, Py_buffer *view, int flags) { + auto tinfo = detail::get_type_info(Py_TYPE(obj)); + if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) { + PyErr_SetString(PyExc_BufferError, "generic_type::getbuffer(): Internal error"); + return -1; + } + memset(view, 0, sizeof(Py_buffer)); + buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data); + view->obj = obj; + view->ndim = 1; + view->internal = info; + view->buf = info->ptr; + view->itemsize = info->itemsize; + view->len = view->itemsize; + for (auto s : info->shape) + view->len *= s; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = const_cast(info->format.c_str()); + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { + view->ndim = info->ndim; + view->strides = (ssize_t *) &info->strides[0]; + view->shape = (ssize_t *) &info->shape[0]; + } + Py_INCREF(view->obj); + return 0; + } + + static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; } +}; +NAMESPACE_END(detail) + +template > +class class_ : public detail::generic_type { +public: + typedef detail::instance instance_type; + + PYBIND11_OBJECT(class_, detail::generic_type, PyType_Check) + + template + class_(handle scope, const char *name, const Extra &... extra) { + detail::type_record record; + record.scope = scope; + record.name = name; + record.type = &typeid(type); + record.type_size = sizeof(type); + record.instance_size = sizeof(instance_type); + record.init_holder = init_holder; + record.dealloc = dealloc; + + /* Process optional arguments, if any */ + detail::process_attributes::init(extra..., &record); + + detail::generic_type::initialize(&record); + } + + template + class_ &def(const char *name_, Func&& f, const Extra&... extra) { + cpp_function cf(std::forward(f), name(name_), + sibling(attr(name_)), is_method(*this), + extra...); + attr(cf.name()) = cf; + return *this; + } + + template class_ & + def_static(const char *name_, Func f, const Extra&... extra) { + cpp_function cf(std::forward(f), name(name_), + sibling(attr(name_)), scope(*this), extra...); + attr(cf.name()) = cf; + return *this; + } + + template + class_ &def(const detail::op_ &op, const Extra&... extra) { + op.template execute(*this, extra...); + return *this; + } + + template + class_ & def_cast(const detail::op_ &op, const Extra&... extra) { + op.template execute_cast(*this, extra...); + return *this; + } + + template + class_ &def(const detail::init &init, const Extra&... extra) { + init.template execute(*this, extra...); + return *this; + } + + template class_& def_buffer(Func &&func) { + struct capture { Func func; }; + capture *ptr = new capture { std::forward(func) }; + install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* { + detail::type_caster caster; + if (!caster.load(obj, false)) + return nullptr; + return new buffer_info(((capture *) ptr)->func(caster)); + }, ptr); + return *this; + } + + template + class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) { + cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, is_method(*this)), + fset([pm](C &c, const D &value) { c.*pm = value; }, is_method(*this)); + def_property(name, fget, fset, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) { + cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, is_method(*this)); + def_property_readonly(name, fget, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)), + fset([pm](object, const D &value) { *pm = value; }, scope(*this)); + def_property_static(name, fget, fset, return_value_policy::reference, extra...); + return *this; + } + + template + class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)); + def_property_readonly_static(name, fget, return_value_policy::reference, extra...); + return *this; + } + + template + class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) { + def_property(name, fget, cpp_function(), extra...); + return *this; + } + + template + class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) { + def_property_static(name, fget, cpp_function(), extra...); + return *this; + } + + template + class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property_static(name, fget, fset, is_method(*this), extra...); + } + + template + class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset); + detail::process_attributes::init(extra..., rec_fget); + if (rec_fset) + detail::process_attributes::init(extra..., rec_fset); + pybind11::str doc_obj = pybind11::str(rec_fget->doc ? rec_fget->doc : ""); + object property( + PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type, fget.ptr() ? fget.ptr() : Py_None, + fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr), false); + if (rec_fget->class_) + attr(name) = property; + else + metaclass().attr(name) = property; + return *this; + } + + template class_ alias() { + auto &instances = pybind11::detail::get_internals().registered_types_cpp; + instances[std::type_index(typeid(target))] = instances[std::type_index(typeid(type))]; + return *this; + } +private: + /// Initialize holder object, variant 1: object derives from enable_shared_from_this + template + static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const std::enable_shared_from_this * /* dummy */) { + try { + new (&inst->holder) holder_type(std::static_pointer_cast(inst->value->shared_from_this())); + } catch (const std::bad_weak_ptr &) { + new (&inst->holder) holder_type(inst->value); + } + } + + /// Initialize holder object, variant 2: try to construct from existing holder object, if possible + template ::value, int>::type = 0> + static void init_holder_helper(instance_type *inst, const holder_type *holder_ptr, const void * /* dummy */) { + if (holder_ptr) + new (&inst->holder) holder_type(*holder_ptr); + else + new (&inst->holder) holder_type(inst->value); + } + + /// Initialize holder object, variant 3: holder is not copy constructible (e.g. unique_ptr), always initialize from raw pointer + template ::value, int>::type = 0> + static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const void * /* dummy */) { + new (&inst->holder) holder_type(inst->value); + } + + /// Initialize holder object of an instance, possibly given a pointer to an existing holder + static void init_holder(PyObject *inst_, const void *holder_ptr) { + auto inst = (instance_type *) inst_; + init_holder_helper(inst, (const holder_type *) holder_ptr, inst->value); + inst->constructed = true; + } + + static void dealloc(PyObject *inst_) { + instance_type *inst = (instance_type *) inst_; + if (inst->owned) { + if (inst->constructed) + inst->holder.~holder_type(); + else + ::operator delete(inst->value); + } + generic_type::dealloc((detail::instance *) inst); + } + + static detail::function_record *get_function_record(handle h) { + h = detail::get_function(h); + return h ? (detail::function_record *) capsule( + PyCFunction_GetSelf(h.ptr()), true) : nullptr; + } +}; + +/// Binds C++ enumerations and enumeration classes to Python +template class enum_ : public class_ { +public: + template + enum_(const handle &scope, const char *name, const Extra&... extra) + : class_(scope, name, extra...), m_parent(scope) { + auto entries = new std::unordered_map(); + this->def("__repr__", [name, entries](Type value) -> std::string { + auto it = entries->find((int) value); + return std::string(name) + "." + + ((it == entries->end()) ? std::string("???") + : std::string(it->second)); + }); + this->def("__init__", [](Type& value, int i) { value = (Type) i; }); + this->def("__int__", [](Type value) { return (int) value; }); + this->def("__eq__", [](const Type &value, Type value2) { return value == value2; }); + this->def("__ne__", [](const Type &value, Type value2) { return value != value2; }); + this->def("__hash__", [](const Type &value) { return (int) value; }); + m_entries = entries; + } + + /// Export enumeration entries into the parent scope + void export_values() { + PyObject *dict = ((PyTypeObject *) this->m_ptr)->tp_dict; + PyObject *key, *value; + ssize_t pos = 0; + while (PyDict_Next(dict, &pos, &key, &value)) + if (PyObject_IsInstance(value, this->m_ptr)) + m_parent.attr(key) = value; + } + + /// Add an enumeration entry + enum_& value(char const* name, Type value) { + this->attr(name) = pybind11::cast(value, return_value_policy::copy); + (*m_entries)[(int) value] = name; + return *this; + } +private: + std::unordered_map *m_entries; + handle m_parent; +}; + +NAMESPACE_BEGIN(detail) +template struct init { + template void execute(pybind11::class_ &class_, const Extra&... extra) const { + /// Function which calls a specific C++ in-place constructor + class_.def("__init__", [](Base *instance, Args... args) { new (instance) Base(args...); }, extra...); + } +}; + +PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret) { + /* Clever approach based on weak references taken from Boost.Python */ + handle nurse (Nurse > 0 ? PyTuple_GetItem(args.ptr(), Nurse - 1) : ret.ptr()); + handle patient(Patient > 0 ? PyTuple_GetItem(args.ptr(), Patient - 1) : ret.ptr()); + + if (!nurse || !patient) + pybind11_fail("Could not activate keep_alive!"); + + cpp_function disable_lifesupport( + [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); }); + + weakref wr(nurse, disable_lifesupport); + + patient.inc_ref(); /* reference patient and leak the weak reference */ + (void) wr.release(); +} + +template struct iterator_state { Iterator it, end; }; + +NAMESPACE_END(detail) + +template detail::init init() { return detail::init(); } + +template iterator make_iterator(Iterator first, Iterator last, Extra&&... extra) { + typedef detail::iterator_state state; + + if (!detail::get_type_info(typeid(state))) { + class_(handle(), "") + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> decltype(*std::declval()) & { + if (s.it == s.end) + throw stop_iteration(); + return *s.it++; + }, return_value_policy::reference_internal, std::forward(extra)...); + } + + return (iterator) cast(state { first, last }); +} + +template void implicitly_convertible() { + auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * { + if (!detail::type_caster().load(obj, false)) + return nullptr; + tuple args(1); + args[0] = obj; + PyObject *result = PyObject_Call((PyObject *) type, args.ptr(), nullptr); + if (result == nullptr) + PyErr_Clear(); + return result; + }; + auto ®istered_types = detail::get_internals().registered_types_cpp; + auto it = registered_types.find(std::type_index(typeid(OutputType))); + if (it == registered_types.end()) + pybind11_fail("implicitly_convertible: Unable to find type " + type_id()); + ((detail::type_info *) it->second)->implicit_conversions.push_back(implicit_caster); +} + +#if defined(WITH_THREAD) +inline void init_threading() { PyEval_InitThreads(); } + +class gil_scoped_acquire { + PyGILState_STATE state; +public: + inline gil_scoped_acquire() { state = PyGILState_Ensure(); } + inline ~gil_scoped_acquire() { PyGILState_Release(state); } +}; + +class gil_scoped_release { + PyThreadState *state; +public: + inline gil_scoped_release() { state = PyEval_SaveThread(); } + inline ~gil_scoped_release() { PyEval_RestoreThread(state); } +}; +#endif + +inline function get_overload(const void *this_ptr, const char *name) { + handle py_object = detail::get_object_handle(this_ptr); + if (!py_object) + return function(); + handle type = py_object.get_type(); + auto key = std::make_pair(type.ptr(), name); + + /* Cache functions that aren't overloaded in Python to avoid + many costly Python dictionary lookups below */ + auto &cache = detail::get_internals().inactive_overload_cache; + if (cache.find(key) != cache.end()) + return function(); + + function overload = (function) py_object.attr(name); + if (overload.is_cpp_function()) { + cache.insert(key); + return function(); + } + + /* Don't call dispatch code if invoked from overridden function */ + PyFrameObject *frame = PyThreadState_Get()->frame; + if (frame && (std::string) pybind11::handle(frame->f_code->co_name).str() == name && + frame->f_code->co_argcount > 0) { + PyFrame_FastToLocals(frame); + PyObject *self_caller = PyDict_GetItem( + frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); + if (self_caller == py_object.ptr()) + return function(); + } + return overload; +} + +#define PYBIND11_OVERLOAD_INT(ret_type, class_name, name, ...) { \ + pybind11::gil_scoped_acquire gil; \ + pybind11::function overload = pybind11::get_overload(this, #name); \ + if (overload) \ + return overload.call(__VA_ARGS__).template cast(); } + +#define PYBIND11_OVERLOAD(ret_type, class_name, name, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \ + return class_name::name(__VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE(ret_type, class_name, name, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \ + pybind11::pybind11_fail("Tried to call pure virtual function \"" #name "\""); + +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +# pragma warning(pop) +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# pragma warning(pop) +#elif defined(__GNUG__) and !defined(__clang__) +# pragma GCC diagnostic pop +#endif diff --git a/stormpy/resources/pybind11/include/pybind11/pytypes.h b/stormpy/resources/pybind11/include/pybind11/pytypes.h new file mode 100644 index 000000000..c7f109cdc --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/pytypes.h @@ -0,0 +1,476 @@ +/* + pybind11/typeid.h: Convenience wrapper classes for basic Python types + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" +#include +#include + +NAMESPACE_BEGIN(pybind11) + +/* A few forward declarations */ +class object; +class str; +class object; +class dict; +class iterator; +namespace detail { class accessor; } + +/// Holds a reference to a Python object (no reference counting) +class handle { +public: + handle() : m_ptr(nullptr) { } + handle(const handle &other) : m_ptr(other.m_ptr) { } + handle(PyObject *ptr) : m_ptr(ptr) { } + PyObject *ptr() const { return m_ptr; } + PyObject *&ptr() { return m_ptr; } + const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; } + const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; } + int ref_count() const { return (int) Py_REFCNT(m_ptr); } + handle get_type() const { return handle((PyObject *) Py_TYPE(m_ptr)); } + inline iterator begin() const; + inline iterator end() const; + inline detail::accessor operator[](handle key) const; + inline detail::accessor operator[](const char *key) const; + inline detail::accessor attr(handle key) const; + inline detail::accessor attr(const char *key) const; + inline pybind11::str str() const; + template T cast() const; + template object call(Args&&... args_) const; + operator bool() const { return m_ptr != nullptr; } + bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } + bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } + bool check() const { return m_ptr != nullptr; } +protected: + PyObject *m_ptr; +}; + +/// Holds a reference to a Python object (with reference counting) +class object : public handle { +public: + object() { } + object(const object &o) : handle(o) { inc_ref(); } + object(const handle &h, bool borrowed) : handle(h) { if (borrowed) inc_ref(); } + object(PyObject *ptr, bool borrowed) : handle(ptr) { if (borrowed) inc_ref(); } + object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; } + ~object() { dec_ref(); } + + handle release() { + PyObject *tmp = m_ptr; + m_ptr = nullptr; + return handle(tmp); + } + + object& operator=(object &other) { + other.inc_ref(); + dec_ref(); + m_ptr = other.m_ptr; + return *this; + } + + object& operator=(object &&other) { + if (this != &other) { + handle temp(m_ptr); + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + temp.dec_ref(); + } + return *this; + } +}; + +NAMESPACE_BEGIN(detail) +inline handle get_function(handle value) { + if (value) { +#if PY_MAJOR_VERSION >= 3 + if (PyInstanceMethod_Check(value.ptr())) + value = PyInstanceMethod_GET_FUNCTION(value.ptr()); +#endif + if (PyMethod_Check(value.ptr())) + value = PyMethod_GET_FUNCTION(value.ptr()); + } + return value; +} + +class accessor { +public: + accessor(handle obj, handle key, bool attr) + : obj(obj), key(key, true), attr(attr) { } + accessor(handle obj, const char *key, bool attr) + : obj(obj), key(PyUnicode_FromString(key), false), attr(attr) { } + accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr) { } + + void operator=(accessor o) { operator=(object(o)); } + + void operator=(const handle &value) { + if (attr) { + if (PyObject_SetAttr(obj.ptr(), key.ptr(), value.ptr()) == -1) + pybind11_fail("Unable to set object attribute"); + } else { + if (PyObject_SetItem(obj.ptr(), key.ptr(), value.ptr()) == -1) + pybind11_fail("Unable to set object item"); + } + } + + operator object() const { + object result(attr ? PyObject_GetAttr(obj.ptr(), key.ptr()) + : PyObject_GetItem(obj.ptr(), key.ptr()), false); + if (!result) {PyErr_Clear(); } + return result; + } + + template inline T cast() const { return operator object().cast(); } + + operator bool() const { + if (attr) { + return (bool) PyObject_HasAttr(obj.ptr(), key.ptr()); + } else { + object result(PyObject_GetItem(obj.ptr(), key.ptr()), false); + if (!result) PyErr_Clear(); + return (bool) result; + } + }; + +private: + handle obj; + object key; + bool attr; +}; + +struct list_accessor { +public: + list_accessor(handle list, size_t index) : list(list), index(index) { } + + void operator=(list_accessor o) { return operator=(object(o)); } + + void operator=(const handle &o) { + // PyList_SetItem steals a reference to 'o' + if (PyList_SetItem(list.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0) + pybind11_fail("Unable to assign value in Python list!"); + } + + operator object() const { + PyObject *result = PyList_GetItem(list.ptr(), (ssize_t) index); + if (!result) + pybind11_fail("Unable to retrieve value from Python list!"); + return object(result, true); + } + + template inline T cast() const { return operator object().cast(); } +private: + handle list; + size_t index; +}; + +struct tuple_accessor { +public: + tuple_accessor(handle tuple, size_t index) : tuple(tuple), index(index) { } + + void operator=(tuple_accessor o) { return operator=(object(o)); } + + void operator=(const handle &o) { + // PyTuple_SetItem steals a referenceto 'o' + if (PyTuple_SetItem(tuple.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0) + pybind11_fail("Unable to assign value in Python tuple!"); + } + + operator object() const { + PyObject *result = PyTuple_GetItem(tuple.ptr(), (ssize_t) index); + if (!result) + pybind11_fail("Unable to retrieve value from Python tuple!"); + return object(result, true); + } + + template inline T cast() const { return operator object().cast(); } +private: + handle tuple; + size_t index; +}; + +struct dict_iterator { +public: + dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { } + dict_iterator& operator++() { + if (!PyDict_Next(dict.ptr(), &pos, &key.ptr(), &value.ptr())) + pos = -1; + return *this; + } + std::pair operator*() const { + return std::make_pair(key, value); + } + bool operator==(const dict_iterator &it) const { return it.pos == pos; } + bool operator!=(const dict_iterator &it) const { return it.pos != pos; } +private: + handle dict, key, value; + ssize_t pos = 0; +}; + +NAMESPACE_END(detail) + + +#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, CvtStmt) \ + Name(const handle &h, bool borrowed) : Parent(h, borrowed) { CvtStmt; } \ + Name(const object& o): Parent(o) { CvtStmt; } \ + Name(object&& o): Parent(std::move(o)) { CvtStmt; } \ + Name& operator=(object&& o) { (void) static_cast(object::operator=(std::move(o))); CvtStmt; return *this; } \ + Name& operator=(object& o) { return static_cast(object::operator=(o)); CvtStmt; } \ + bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } + +#define PYBIND11_OBJECT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ) + +#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT(Name, Parent, CheckFun) \ + Name() : Parent() { } + +class iterator : public object { +public: + PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) + iterator(handle obj, bool borrowed = false) : object(obj, borrowed) { } + iterator& operator++() { + if (ptr()) + value = object(PyIter_Next(m_ptr), false); + return *this; + } + bool operator==(const iterator &it) const { return *it == **this; } + bool operator!=(const iterator &it) const { return *it != **this; } + const handle &operator*() const { + if (m_ptr && !value) + value = object(PyIter_Next(m_ptr), false); + return value; + } +private: + mutable object value; +}; + +inline detail::accessor handle::operator[](handle key) const { return detail::accessor(ptr(), key.ptr(), false); } +inline detail::accessor handle::operator[](const char *key) const { return detail::accessor(ptr(), key, false); } +inline detail::accessor handle::attr(handle key) const { return detail::accessor(ptr(), key.ptr(), true); } +inline detail::accessor handle::attr(const char *key) const { return detail::accessor(ptr(), key, true); } +inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr())); } +inline iterator handle::end() const { return iterator(nullptr); } + +class str : public object { +public: + PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check) + str(const std::string &s) + : object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) { + if (!m_ptr) pybind11_fail("Could not allocate string object!"); + } + + operator std::string() const { +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + return PyUnicode_AsUTF8(m_ptr); +#else + object temp(PyUnicode_AsUTF8String(m_ptr), false); + if (temp.ptr() == nullptr) + pybind11_fail("Unable to extract string contents!"); + return PYBIND11_BYTES_AS_STRING(temp.ptr()); +#endif + } +}; + +inline pybind11::str handle::str() const { + PyObject *strValue = PyObject_Str(m_ptr); +#if PY_MAJOR_VERSION < 3 + PyObject *unicode = PyUnicode_FromEncodedObject(strValue, "utf-8", nullptr); + Py_XDECREF(strValue); strValue = unicode; +#endif + return pybind11::str(strValue, false); +} + +class bytes : public object { +public: + PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK) + + bytes(const std::string &s) + : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), s.size()), false) { + if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); + } + + operator std::string() const { + char *buffer; + ssize_t length; + int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length); + if (err == -1) + pybind11_fail("Unable to extract bytes contents!"); + return std::string(buffer, length); + } +}; + +class bool_ : public object { +public: + PYBIND11_OBJECT_DEFAULT(bool_, object, PyBool_Check) + bool_(bool value) : object(value ? Py_True : Py_False, true) { } + operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } +}; + +class int_ : public object { +public: + PYBIND11_OBJECT_DEFAULT(int_, object, PYBIND11_LONG_CHECK) + template ::value, int>::type = 0> + int_(T value) { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + m_ptr = PyLong_FromLong((long) value); + else + m_ptr = PyLong_FromUnsignedLong((unsigned long) value); + } else { + if (std::is_signed::value) + m_ptr = PyLong_FromLongLong((long long) value); + else + m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); + } + if (!m_ptr) pybind11_fail("Could not allocate int object!"); + } + + template ::value, int>::type = 0> + operator T() const { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + return (T) PyLong_AsLong(m_ptr); + else + return (T) PyLong_AsUnsignedLong(m_ptr); + } else { + if (std::is_signed::value) + return (T) PYBIND11_LONG_AS_LONGLONG(m_ptr); + else + return (T) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(m_ptr); + } + } +}; + +class float_ : public object { +public: + PYBIND11_OBJECT_DEFAULT(float_, object, PyFloat_Check) + float_(float value) : object(PyFloat_FromDouble((double) value), false) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + float_(double value) : object(PyFloat_FromDouble((double) value), false) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + operator float() const { return (float) PyFloat_AsDouble(m_ptr); } + operator double() const { return (double) PyFloat_AsDouble(m_ptr); } +}; + +class weakref : public object { +public: + PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check) + weakref(handle obj, handle callback = handle()) : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), false) { + if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); + } +}; + +class slice : public object { +public: + PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) + slice(ssize_t start_, ssize_t stop_, ssize_t step_) { + int_ start(start_), stop(stop_), step(step_); + m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); + if (!m_ptr) pybind11_fail("Could not allocate slice object!"); + } + bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const { + return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, length, + start, stop, step, slicelength) == 0; + } +}; + +class capsule : public object { +public: + PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) + capsule(PyObject *obj, bool borrowed) : object(obj, borrowed) { } + capsule(void *value, void (*destruct)(PyObject *) = nullptr) + : object(PyCapsule_New(value, nullptr, destruct), false) { + if (!m_ptr) pybind11_fail("Could not allocate capsule object!"); + } + template operator T *() const { + T * result = static_cast(PyCapsule_GetPointer(m_ptr, nullptr)); + if (!result) pybind11_fail("Unable to extract capsule contents!"); + return result; + } +}; + +class tuple : public object { +public: + PYBIND11_OBJECT(tuple, object, PyTuple_Check) + tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), false) { + if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); + } + size_t size() const { return (size_t) PyTuple_Size(m_ptr); } + detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(ptr(), index); } +}; + +class dict : public object { +public: + PYBIND11_OBJECT(dict, object, PyDict_Check) + dict() : object(PyDict_New(), false) { + if (!m_ptr) pybind11_fail("Could not allocate dict object!"); + } + size_t size() const { return (size_t) PyDict_Size(m_ptr); } + detail::dict_iterator begin() const { return (++detail::dict_iterator(ptr(), 0)); } + detail::dict_iterator end() const { return detail::dict_iterator(); } + void clear() const { PyDict_Clear(ptr()); } +}; + +class list : public object { +public: + PYBIND11_OBJECT(list, object, PyList_Check) + list(size_t size = 0) : object(PyList_New((ssize_t) size), false) { + if (!m_ptr) pybind11_fail("Could not allocate list object!"); + } + size_t size() const { return (size_t) PyList_Size(m_ptr); } + detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); } + void append(const object &object) const { PyList_Append(m_ptr, object.ptr()); } +}; + +class set : public object { +public: + PYBIND11_OBJECT(set, object, PySet_Check) + set() : object(PySet_New(nullptr), false) { + if (!m_ptr) pybind11_fail("Could not allocate set object!"); + } + size_t size() const { return (size_t) PySet_Size(m_ptr); } + bool add(const object &object) const { return PySet_Add(m_ptr, object.ptr()) == 0; } + void clear() const { PySet_Clear(m_ptr); } +}; + +class function : public object { +public: + PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) + bool is_cpp_function() const { + handle fun = detail::get_function(m_ptr); + return fun && PyCFunction_Check(fun.ptr()); + } +}; + +class buffer : public object { +public: + PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) + + buffer_info request(bool writable = false) { + int flags = PyBUF_STRIDES | PyBUF_FORMAT; + if (writable) flags |= PyBUF_WRITABLE; + Py_buffer *view = new Py_buffer(); + if (PyObject_GetBuffer(m_ptr, view, flags) != 0) + throw error_already_set(); + return buffer_info(view); + } +}; + +inline size_t len(handle h) { + ssize_t result = PyObject_Length(h.ptr()); + if (result < 0) + pybind11_fail("Unable to compute length of object"); + return (size_t) result; +} + +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/include/pybind11/stl.h b/stormpy/resources/pybind11/include/pybind11/stl.h new file mode 100644 index 000000000..97ccdbc84 --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/stl.h @@ -0,0 +1,197 @@ +/* + pybind11/complex.h: Complex number support + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +template struct set_caster { + typedef Type type; + typedef type_caster::type> key_conv; + + bool load(handle src, bool convert) { + pybind11::set s(src, true); + if (!s.check()) + return false; + value.clear(); + key_conv conv; + for (auto entry : s) { + if (!conv.load(entry, convert)) + return false; + value.insert((Key) conv); + } + return true; + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + pybind11::set s; + for (auto const &value: src) { + object value_ = object(key_conv::cast(value, policy, parent), false); + if (!value_ || !s.add(value_)) + return handle(); + } + return s.release(); + } + + PYBIND11_TYPE_CASTER(type, _("set<") + key_conv::name() + _(">")); +}; + +template struct map_caster { + typedef Type type; + typedef type_caster::type> key_conv; + typedef type_caster::type> value_conv; + + bool load(handle src, bool convert) { + dict d(src, true); + if (!d.check()) + return false; + key_conv kconv; + value_conv vconv; + value.clear(); + for (auto it : d) { + if (!kconv.load(it.first.ptr(), convert) || + !vconv.load(it.second.ptr(), convert)) + return false; + value.emplace((Key) kconv, (Value) vconv); + } + return true; + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + dict d; + for (auto const &kv: src) { + object key = object(key_conv::cast(kv.first, policy, parent), false); + object value = object(value_conv::cast(kv.second, policy, parent), false); + if (!key || !value) + return handle(); + d[key] = value; + } + return d.release(); + } + + PYBIND11_TYPE_CASTER(type, _("dict<") + key_conv::name() + _(", ") + value_conv::name() + _(">")); +}; + +template struct list_caster { + typedef Type type; + typedef type_caster::type> value_conv; + + bool load(handle src, bool convert) { + list l(src, true); + if (!l.check()) + return false; + value_conv conv; + value.clear(); + reserve_maybe(l, &value); + for (auto it : l) { + if (!conv.load(it, convert)) + return false; + value.push_back((Value) conv); + } + return true; + } + + template ().reserve(0)), void>::value, int>::type = 0> + void reserve_maybe(list l, Type *) { value.reserve(l.size()); } + void reserve_maybe(list, void *) { } + + static handle cast(const Type &src, return_value_policy policy, handle parent) { + list l(src.size()); + size_t index = 0; + for (auto const &value: src) { + object value_ = object(value_conv::cast(value, policy, parent), false); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(Type, _("list<") + value_conv::name() + _(">")); +}; + +template struct type_caster> + : list_caster, Type> { }; + +template struct type_caster> + : list_caster, Type> { }; + +template struct type_caster> { + typedef std::array array_type; + typedef type_caster::type> value_conv; + + bool load(handle src, bool convert) { + list l(src, true); + if (!l.check()) + return false; + if (l.size() != Size) + return false; + value_conv conv; + size_t ctr = 0; + for (auto it : l) { + if (!conv.load(it, convert)) + return false; + value[ctr++] = (Type) conv; + } + return true; + } + + static handle cast(const array_type &src, return_value_policy policy, handle parent) { + list l(Size); + size_t index = 0; + for (auto const &value: src) { + object value_ = object(value_conv::cast(value, policy, parent), false); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + PYBIND11_TYPE_CASTER(array_type, _("list<") + value_conv::name() + _(">") + _("[") + _() + _("]")); +}; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +NAMESPACE_END(detail) + +inline std::ostream &operator<<(std::ostream &os, const handle &obj) { + os << (std::string) obj.str(); + return os; +} + +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/stormpy/resources/pybind11/include/pybind11/typeid.h b/stormpy/resources/pybind11/include/pybind11/typeid.h new file mode 100644 index 000000000..b395110f6 --- /dev/null +++ b/stormpy/resources/pybind11/include/pybind11/typeid.h @@ -0,0 +1,53 @@ +/* + pybind11/typeid.h: Compiler-independent access to type identifiers + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include +#include + +#if defined(__GNUG__) +#include +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) +/// Erase all occurrences of a substring +inline void erase_all(std::string &string, const std::string &search) { + for (size_t pos = 0;;) { + pos = string.find(search, pos); + if (pos == std::string::npos) break; + string.erase(pos, search.length()); + } +} + +PYBIND11_NOINLINE inline void clean_type_id(std::string &name) { +#if defined(__GNUG__) + int status = 0; + std::unique_ptr res { + abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; + if (status == 0) + name = res.get(); +#else + detail::erase_all(name, "class "); + detail::erase_all(name, "struct "); + detail::erase_all(name, "enum "); +#endif + detail::erase_all(name, "pybind11::"); +} +NAMESPACE_END(detail) + +/// Return a string representation of a C++ type +template static std::string type_id() { + std::string name(typeid(T).name()); + detail::clean_type_id(name); + return name; +} + +NAMESPACE_END(pybind11) diff --git a/stormpy/resources/pybind11/pybind11/__init__.py b/stormpy/resources/pybind11/pybind11/__init__.py new file mode 100644 index 000000000..af8f14a8e --- /dev/null +++ b/stormpy/resources/pybind11/pybind11/__init__.py @@ -0,0 +1,11 @@ +from ._version import version_info, __version__ + + +def get_include(): + import os + try: + from pip import locations + return os.path.dirname( + locations.distutils_scheme('pybind11')['headers']) + except ImportError: + return 'include' diff --git a/stormpy/resources/pybind11/pybind11/_version.py b/stormpy/resources/pybind11/pybind11/_version.py new file mode 100644 index 000000000..93cf8a709 --- /dev/null +++ b/stormpy/resources/pybind11/pybind11/_version.py @@ -0,0 +1,2 @@ +version_info = (1, 5, 'dev0') +__version__ = '.'.join(map(str, version_info)) diff --git a/stormpy/resources/pybind11/setup.cfg b/stormpy/resources/pybind11/setup.cfg new file mode 100644 index 000000000..3c6e79cf3 --- /dev/null +++ b/stormpy/resources/pybind11/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/stormpy/resources/pybind11/setup.py b/stormpy/resources/pybind11/setup.py new file mode 100644 index 000000000..362b753b0 --- /dev/null +++ b/stormpy/resources/pybind11/setup.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# Setup script for PyPI; use CMakeFile.txt to build the example application + +from setuptools import setup +from pybind11 import __version__ + +setup( + name='pybind11', + version=__version__, + description='Seamless operability between C++11 and Python', + author='Wenzel Jakob', + author_email='wenzel@inf.ethz.ch', + url='https://github.com/wjakob/pybind11', + download_url='https://github.com/wjakob/pybind11/tarball/v' + __version__, + packages=['pybind11'], + license='BSD', + headers=[ + 'include/pybind11/attr.h', + 'include/pybind11/cast.h', + 'include/pybind11/complex.h', + 'include/pybind11/descr.h', + 'include/pybind11/numpy.h', + 'include/pybind11/pybind11.h', + 'include/pybind11/stl.h', + 'include/pybind11/common.h', + 'include/pybind11/functional.h', + 'include/pybind11/operators.h', + 'include/pybind11/pytypes.h', + 'include/pybind11/typeid.h' + ], + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Utilities', + 'Programming Language :: C++', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'License :: OSI Approved :: BSD License', + ], + keywords='C++11, Python bindings', + long_description="""pybind11 is a lightweight header library that exposes +C++ types in Python and vice versa, mainly to create Python bindings of +existing C++ code. Its goals and syntax are similar to the excellent +Boost.Python library by David Abrahams: to minimize boilerplate code in +traditional extension modules by inferring type information using compile-time +introspection. + +The main issue with Boost.Python-and the reason for creating such a similar +project-is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~2.5K lines of code and depend on +Python (2.7 or 3.x) and the C++ standard library. This compact implementation +was possible thanks to some of the new C++11 language features (specifically: +tuples, lambda functions and variadic templates). Since its creation, this +library has grown beyond Boost.Python in many ways, leading to dramatically +simpler binding code in many common situations.""") diff --git a/stormpy/resources/pybind11/tools/mkdoc.py b/stormpy/resources/pybind11/tools/mkdoc.py new file mode 100644 index 000000000..09c09cfb0 --- /dev/null +++ b/stormpy/resources/pybind11/tools/mkdoc.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 +# +# Syntax: mkdoc.py [-I ..] [.. a list of header files ..] +# +# Extract documentation from C++ header files to use it in Python bindings +# + +import os, sys, platform, re, textwrap +from clang import cindex +from clang.cindex import CursorKind +from collections import OrderedDict +from threading import Thread, Semaphore +from multiprocessing import cpu_count + +if platform.system() == 'Darwin': + libclang = '/opt/llvm/lib/libclang.dylib' + if os.path.exists(libclang): + cindex.Config.set_library_path(os.path.dirname(libclang)) + +RECURSE_LIST = [ + CursorKind.TRANSLATION_UNIT, + CursorKind.NAMESPACE, + CursorKind.CLASS_DECL, + CursorKind.STRUCT_DECL, + CursorKind.CLASS_TEMPLATE +] + +PRINT_LIST = [ + CursorKind.CLASS_DECL, + CursorKind.STRUCT_DECL, + CursorKind.CLASS_TEMPLATE, + CursorKind.FUNCTION_DECL, + CursorKind.FUNCTION_TEMPLATE, + CursorKind.CXX_METHOD, + CursorKind.CONSTRUCTOR, + CursorKind.FIELD_DECL +] + +CPP_OPERATORS = { + '<=' : 'le', '>=' : 'ge', '==' : 'eq', '!=' : 'ne', '[]' : 'array', + '+=' : 'iadd', '-=' : 'isub', '*=' : 'imul', '/=' : 'idiv', '%=' : + 'imod', '&=' : 'iand', '|=' : 'ior', '^=' : 'ixor', '<<=' : 'ilshift', + '>>=' : 'irshift', '++' : 'inc', '--' : 'dec', '<<' : 'lshift', '>>' : + 'rshift', '&&' : 'land', '||' : 'lor', '!' : 'lnot', '~' : 'bnot', '&' + : 'band', '|' : 'bor', '+' : 'add', '-' : 'sub', '*' : 'mul', '/' : + 'div', '%' : 'mod', '<' : 'lt', '>' : 'gt', '=' : 'assign' +} +CPP_OPERATORS = OrderedDict(sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0]))) + +job_count = cpu_count() +job_semaphore = Semaphore(job_count) + +registered_names = dict() + +def d(s): + return s.decode('utf8') + +def sanitize_name(name): + global registered_names + for k, v in CPP_OPERATORS.items(): + name = name.replace('operator%s' % k, 'operator_%s' % v) + name = name.replace('<', '_') + name = name.replace('>', '_') + name = name.replace(' ', '_') + name = name.replace(',', '_') + if name in registered_names: + registered_names[name] += 1 + name += '_' + str(registered_names[name]) + else: + registered_names[name] = 1 + return '__doc_' + name + +def process_comment(comment): + result = '' + + # Remove C++ comment syntax + for s in comment.splitlines(): + s = s.strip() + if s.startswith('/*'): + s = s[2:].lstrip('* \t') + elif s.endswith('*/'): + s = s[:-2].rstrip('* \t') + elif s.startswith('///'): + s = s[3:] + if s.startswith('*'): + s = s[1:] + result += s.strip() + '\n' + + # Doxygen tags + cpp_group = '([\w:]+)' + param_group = '([\[\w:\]]+)' + + s = result + s = re.sub(r'\\c\s+%s' % cpp_group, r'``\1``', s) + s = re.sub(r'\\a\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\e\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\em\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\b\s+%s' % cpp_group, r'**\1**', s) + s = re.sub(r'\\param%s?\s+%s' % (param_group, cpp_group), r'\n\n$Parameter ``\2``:\n\n', s) + + for in_, out_ in { + 'return' : 'Returns', + 'author' : 'Author', + 'authors' : 'Authors', + 'copyright' : 'Copyright', + 'date' : 'Date', + 'remark' : 'Remark', + 'sa' : 'See also', + 'see' : 'See also', + 'extends' : 'Extends', + 'throw' : 'Throws', + 'throws' : 'Throws' }.items(): + s = re.sub(r'\\%s\s*' % in_, r'\n\n$%s:\n\n' % out_, s) + + s = re.sub(r'\\details\s*', r'\n\n', s) + s = re.sub(r'\\brief\s*', r'', s) + s = re.sub(r'\\short\s*', r'', s) + s = re.sub(r'\\ref\s*', r'', s) + + # HTML/TeX tags + s = re.sub(r'([^<]*)', r'``\1``', s) + s = re.sub(r'([^<]*)', r'*\1*', s) + s = re.sub(r'([^<]*)', r'**\1**', s) + s = re.sub(r'\\f\$([^\$]*)\\f\$', r'$\1$', s) + + s = s.replace('``true``', '``True``') + s = s.replace('``false``', '``False``') + + # Re-flow text + wrapper = textwrap.TextWrapper() + wrapper.expand_tabs = True + wrapper.replace_whitespace = True + wrapper.width = 75 + wrapper.initial_indent = wrapper.subsequent_indent = '' + + result = '' + for x in re.split(r'\n{2,}', s): + wrapped = wrapper.fill(x.strip()) + if len(wrapped) > 0 and wrapped[0] == '$': + result += wrapped[1:] + '\n' + wrapper.initial_indent = wrapper.subsequent_indent = ' '*4 + else: + result += wrapped + '\n\n' + wrapper.initial_indent = wrapper.subsequent_indent = '' + return result.rstrip() + + +def extract(filename, node, prefix, output): + num_extracted = 0 + if not (node.location.file is None or os.path.samefile(d(node.location.file.name), filename)): + return 0 + if node.kind in RECURSE_LIST: + sub_prefix = prefix + if node.kind != CursorKind.TRANSLATION_UNIT: + if len(sub_prefix) > 0: + sub_prefix += '_' + sub_prefix += d(node.spelling) + for i in node.get_children(): + num_extracted += extract(filename, i, sub_prefix, output) + if num_extracted == 0: + return 0 + if node.kind in PRINT_LIST: + comment = d(node.raw_comment) if node.raw_comment is not None else '' + comment = process_comment(comment) + name = sanitize_name(prefix + '_' + d(node.spelling)) + output.append('\nstatic const char *%s = %sR"doc(%s)doc";' % (name, '\n' if '\n' in comment else '', comment)) + num_extracted += 1 + return num_extracted + +class ExtractionThread(Thread): + def __init__ (self, filename, parameters, output): + Thread.__init__(self) + self.filename = filename + self.parameters = parameters + self.output = output + job_semaphore.acquire() + + def run(self): + print('Processing "%s" ..' % self.filename, file = sys.stderr) + try: + index = cindex.Index(cindex.conf.lib.clang_createIndex(False, True)) + tu = index.parse(self.filename, self.parameters) + extract(self.filename, tu.cursor, '', self.output) + finally: + job_semaphore.release() + +if __name__ == '__main__': + parameters = ['-x', 'c++', '-std=c++11'] + filenames = [] + + for item in sys.argv[1:]: + if item.startswith('-'): + parameters.append(item) + else: + filenames.append(item) + + if len(filenames) == 0: + print('Syntax: %s [.. a list of header files ..]' % sys.argv[0]) + exit(-1) + + print('''/* + This file contains docstrings for the Python bindings. + Do not edit! These were automatically extracted by mkdoc.py + */ + +#define __EXPAND(x) x +#define __COUNT(_1, _2, _3, _4, _5, COUNT, ...) COUNT +#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 5, 4, 3, 2, 1)) +#define __CAT1(a, b) a ## b +#define __CAT2(a, b) __CAT1(a, b) +#define __DOC1(n1) __doc_##n1 +#define __DOC2(n1, n2) __doc_##n1##_##n2 +#define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3 +#define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4 +#define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4_##n5 +#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) + +#if defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif +''') + + output = [] + for filename in filenames: + thr = ExtractionThread(filename, parameters, output) + thr.start() + + print('Waiting for jobs to finish ..', file = sys.stderr) + for i in range(job_count): + job_semaphore.acquire() + + output.sort() + for l in output: + print(l) + + print(''' +#if defined(__GNUG__) +#pragma GCC diagnostic pop +#endif +''') diff --git a/stormpy/setup.cfg b/stormpy/setup.cfg new file mode 100644 index 000000000..93d2dc675 --- /dev/null +++ b/stormpy/setup.cfg @@ -0,0 +1,2 @@ +[build_ext] +use-cln=0 diff --git a/stormpy/setup.py b/stormpy/setup.py new file mode 100755 index 000000000..72bb6b628 --- /dev/null +++ b/stormpy/setup.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +from setuptools import setup +from distutils.core import Extension +from distutils.command.build_ext import build_ext +import os.path +import platform +from glob import glob + +PROJECT_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + +# Glob source files for modules +core_sources = glob(os.path.join('src', 'core', '*.cpp')) +expressions_sources = glob(os.path.join('src', 'expressions', '*.cpp')) +logic_sources = glob(os.path.join('src', 'logic', '*.cpp')) + +# Configuration shared between external modules follows + +# To help along, if storm and/or pybind is not system installed, retrieve from storm distribution +include_dirs = ['.', 'src', 'resources/pybind11/include/'] +# Add more include dirs +# TODO handle by cmake +include_dirs.extend(['../build/include/', '../resources/3rdparty/sylvan/src/', '../resources/3rdparty/exprtk/', '../resources/3rdparty/gmm-5.0/include/']) +carl_dir = "/Users/mvolk/develop/carl/src/" +include_dirs.append(carl_dir) +boost_dir = '/usr/local/include/' +include_dirs.append(boost_dir) +cudd_dirs = ['../resources/3rdparty/cudd-3.0.0/cplusplus/', '../resources/3rdparty/cudd-3.0.0/mtr/', '../resources/3rdparty/cudd-3.0.0/cudd/'] +include_dirs.extend(cudd_dirs) +log4cplus_dirs = ['../resources/3rdparty/log4cplus-1.1.3-rc1/include/', '../build/resources/3rdparty/log4cplus-1.1.3-rc1/include/'] +include_dirs.extend(log4cplus_dirs) + +local_storm_path = os.path.join(PROJECT_DIR, '..') +if os.path.exists(local_storm_path): + include_dirs.append(local_storm_path) + +# Like includes, also add local path for library, assuming made in 'build' +library_dirs = [] +local_storm_lib_path = os.path.join(PROJECT_DIR, '..', 'build/src') +if os.path.exists(local_storm_lib_path): + library_dirs.append(local_storm_lib_path) + +libraries = ['storm'] +extra_compile_args = ['-std=c++11'] +define_macros = [] + +extra_link_args = [] +if platform.system() == 'Darwin': + extra_link_args.append('-Wl,-rpath,'+library_dirs[0]) + +ext_core = Extension( + name='core', + sources=['src/mod_core.cpp'] + core_sources, + include_dirs=include_dirs, + libraries=libraries, + library_dirs=library_dirs, + extra_compile_args=extra_compile_args, + define_macros=define_macros, + extra_link_args=extra_link_args +) + +ext_info = Extension( + name='info.info', + sources=['src/mod_info.cpp'], + include_dirs=include_dirs, + libraries=libraries, + library_dirs=library_dirs, + extra_compile_args=extra_compile_args, + define_macros=define_macros, + extra_link_args=extra_link_args +) + +ext_expressions = Extension( + name='expressions.expressions', + sources=['src/mod_expressions.cpp'] + expressions_sources, + include_dirs=include_dirs, + libraries=libraries, + library_dirs=library_dirs, + extra_compile_args=extra_compile_args, + define_macros=define_macros, + extra_link_args=extra_link_args +) + +ext_logic = Extension( + name='logic.logic', + sources=['src/mod_logic.cpp'] + logic_sources, + include_dirs=include_dirs, + libraries=libraries, + library_dirs=library_dirs, + extra_compile_args=extra_compile_args, + define_macros=define_macros, + extra_link_args=extra_link_args +) + +class stormpy_build_ext(build_ext): + """Extend build_ext to provide CLN toggle option + """ + user_options = build_ext.user_options + [ + ('use-cln', None, + "use cln numbers instead of gmpxx") + ] + + def __init__(self, *args, **kwargs): + build_ext.__init__(self, *args, **kwargs) + + def initialize_options (self): + build_ext.initialize_options(self) + self.use_cln = None + + def finalize_options(self): + build_ext.finalize_options(self) + + if self.use_cln: + self.libraries += ['cln'] + if not self.define: + self.define = [] + else: + self.define = list(self.define) + self.define += [('STORMPY_USE_CLN', 1)] + else: + self.libraries += ['gmp', 'gmpxx'] + if not self.undef: + self.undef = [] + self.undef += ['STORMPY_USE_CLN'] + + if library_dirs: + # Makes local storm library lookup that much easier + self.rpath += library_dirs + +setup(name="stormpy", + version="0.9", + author="M. Volk", + author_email="matthias.volk@cs.rwth-aachen.de", + maintainer="S. Junges", + maintainer_email="sebastian.junges@cs.rwth-aachen.de", + url="http://moves.rwth-aachen.de", + description="stormpy - Python Bindings for Storm", + packages=['stormpy', 'stormpy.info', 'stormpy.expressions', 'stormpy.logic'], + package_dir={'':'lib'}, + ext_package='stormpy', + ext_modules=[ext_core, ext_info, ext_expressions, ext_logic + ], + cmdclass={ + 'build_ext': stormpy_build_ext, + } +) diff --git a/stormpy/src/CMakeLists.txt b/stormpy/src/CMakeLists.txt new file mode 100644 index 000000000..3574ad93c --- /dev/null +++ b/stormpy/src/CMakeLists.txt @@ -0,0 +1,42 @@ +# This is a CMake example for Python + +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src ${stormpy_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${pybind11_incdir}) + +FILE(GLOB core_files "core/*.cpp") +FILE(GLOB info_files "info/*.cpp") +ADD_LIBRARY(stormpy_core SHARED mod_core.cpp ${core_files}) +ADD_LIBRARY(stormpy_info SHARED mod_info.cpp ${info_files}) + +SET(STORMPY_SOURCE_DIR "${PROJECT_SOURCE_DIR}") +SET(STORMPY_OUTPUT_DIR "${PROJECT_BINARY_DIR}/stormpy") + +SET_TARGET_PROPERTIES(stormpy_core PROPERTIES + OUTPUT_NAME core + PREFIX "" + SUFFIX ".so" + LIBRARY_OUTPUT_DIRECTORY ${STORMPY_OUTPUT_DIR}/ +) + +SET_TARGET_PROPERTIES(stormpy_info PROPERTIES + OUTPUT_NAME info + PREFIX "" + SUFFIX ".so" + LIBRARY_OUTPUT_DIRECTORY ${STORMPY_OUTPUT_DIR}/info +) + +add_custom_target(stormpy_files) +add_custom_command(TARGET stormpy_files POST_BUILD COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_SOURCE_DIR}/stormpy ${STORMPY_OUTPUT_DIR} + ) + +if(BUILD_STATIC) + TARGET_LINK_LIBRARIES(stormpy_core lib_storm_static ${stormpy_LIBRARIES_STATIC} ${PYTHON_LIBRARIES} ${libs_static} ) + TARGET_LINK_LIBRARIES(stormpy_info lib_storm_static ${stormpy_LIBRARIES_STATIC} ${PYTHON_LIBRARIES} ${libs_static} ) +else() + TARGET_LINK_LIBRARIES(stormpy_core lib_storm ${stormpy_LIBRARIES_DYNAMIC} ${PYTHON_LIBRARIES} ${libs_dynamic}) + TARGET_LINK_LIBRARIES(stormpy_info lib_storm ${stormpy_LIBRARIES_DYNAMIC} ${PYTHON_LIBRARIES} ${libs_dynamic}) +endif() +# +add_custom_target(stormpy DEPENDS stormpy_files stormpy_core stormpy_info) + diff --git a/stormpy/src/common.h b/stormpy/src/common.h new file mode 100644 index 000000000..de2e1c982 --- /dev/null +++ b/stormpy/src/common.h @@ -0,0 +1,127 @@ +/* + * common.h + * + * Created on: 15 Apr 2016 + * Author: hbruintjes + */ + +#pragma once + +#include +#include +#include +#include + +namespace py = pybind11; + +#if PY_MAJOR_VERSION >= 3 +#define PY_DIV "__truediv__" +#define PY_RDIV "__rtruediv__" +#else +#define PY_DIV "__div__" +#define PY_RDIV "__rdiv__" +#endif + +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); + +namespace pybind11 { +namespace detail { +/** + * Dummy type caster for handle, so functions can return pybind11 handles directly + */ +/*template <> class type_caster { +public: + bool load(handle src, bool) { + value = handle(src).inc_ref(); + return true; + } + + static handle cast(handle src, return_value_policy policy, handle parent) { + switch(policy) { + case return_value_policy::automatic: + case return_value_policy::copy: + case return_value_policy::take_ownership: + return handle(src); + case return_value_policy::reference: + return handle(src).inc_ref(); + case return_value_policy::reference_internal: + parent.inc_ref(); + return handle(src); + } + return handle(src); + } + PYBIND11_TYPE_CASTER(handle, _("handle")); +};*/ +/* +template struct tuple_caster { + typedef TupleType type; + template + using type_conv = type_caster::type>; + + bool load(handle src, bool convert) { + pybind11::tuple tup(src, true); + if (!tup.check()) + return false; + + return loadItem<0, Keys...>(tup, convert); + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + pybind11::tuple tup(sizeof...(Keys)); + if (!castItem<0, Keys...>(tup, src, policy, parent)) { + return handle(); + } + + return tup.release(); + } + +private: + template + bool loadItem(pybind11::tuple& tup, bool convert) { + type_conv conv; + if (!conv.load(tup[N], convert)) + return false; + std::get(value) = static_cast(conv); + return loadItem(tup, convert); + } + + template + bool loadItem(pybind11::tuple& tup, bool convert) { + type_conv conv; + if (!conv.load(tup[N], convert)) + return false; + std::get(value) = static_cast(conv); + return true; + } + + template + static bool castItem(pybind11::tuple& tup, const type &src, return_value_policy policy, handle parent) { + auto obj = type_conv::cast(std::get(src), policy, parent); + object value_ = object(obj, false); + if (!obj) { + return false; + } + return castItem(tup, src, policy, parent); + } + + template + static bool castItem(pybind11::tuple& tu, const type &src, return_value_policy policy, handle parent) { + auto obj = type_conv::cast(std::get(src), policy, parent); + object value_ = object(obj, false); + if (!obj) { + return false; + } + return true; + } +}; + +template struct type_caster> + : tuple_caster, Types...> { }; + +template struct type_caster> + : tuple_caster, Type1, Type2> { }; +*/ + +} +} diff --git a/stormpy/src/core/bisimulation.cpp b/stormpy/src/core/bisimulation.cpp new file mode 100644 index 000000000..3eafc80d0 --- /dev/null +++ b/stormpy/src/core/bisimulation.cpp @@ -0,0 +1,22 @@ +#include "bisimulation.h" + +// Thin wrapper for bisimulation +template +std::shared_ptr> performBisimulation(std::shared_ptr> const& model, std::shared_ptr const& formula, storm::storage::BisimulationType bisimulationType) { + return storm::performBisimulationMinimization>(model, formula, bisimulationType); +} + +// Define python bindings +void define_bisimulation(py::module& m) { + + // Bisimulation + m.def("_perform_bisimulation", &performBisimulation, "Perform bisimulation", py::arg("model"), py::arg("formula"), py::arg("bisimulation_type")); + m.def("_perform_parametric_bisimulation", &performBisimulation, "Perform bisimulation on parametric model", py::arg("model"), py::arg("formula"), py::arg("bisimulation_type")); + + // BisimulationType + py::enum_(m, "BisimulationType", "Types of bisimulation") + .value("STRONG", storm::storage::BisimulationType::Strong) + .value("WEAK", storm::storage::BisimulationType::Weak) + ; + +} diff --git a/stormpy/src/core/bisimulation.h b/stormpy/src/core/bisimulation.h new file mode 100644 index 000000000..d444f40e9 --- /dev/null +++ b/stormpy/src/core/bisimulation.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_BISIMULATION_H_ +#define PYTHON_CORE_BISIMULATION_H_ + +#include "common.h" + +void define_bisimulation(py::module& m); + +#endif /* PYTHON_CORE_BISIMULATION_H_ */ diff --git a/stormpy/src/core/common.h b/stormpy/src/core/common.h new file mode 100644 index 000000000..68aac6d6f --- /dev/null +++ b/stormpy/src/core/common.h @@ -0,0 +1,4 @@ +#include "src/common.h" +#include + +#include diff --git a/stormpy/src/core/core.cpp b/stormpy/src/core/core.cpp new file mode 100644 index 000000000..a3cf262d9 --- /dev/null +++ b/stormpy/src/core/core.cpp @@ -0,0 +1,20 @@ +#include "core.h" + +void define_core(py::module& m) { + + // Init + m.def("set_up", [] (std::string const& args) { + storm::utility::setUp(); + storm::settings::SettingsManager::manager().setFromString(args); + }, "Initialize Storm", py::arg("arguments")); + + // Parse formulas + m.def("parse_formulas", &storm::parseFormulasForExplicit, "Parse explicit formulas", py::arg("formula_string")); + m.def("parse_formulas_for_program", &storm::parseFormulasForProgram, "Parse formulas for program", py::arg("formula_string"), py::arg("program")); + + // Pair + py::class_(m, "ModelFormulasPair", "Pair of model and formulas") + .def_readwrite("model", &storm::storage::ModelFormulasPair::model, "The model") + .def_readwrite("formulas", &storm::storage::ModelFormulasPair::formulas, "The formulas") + ; +} diff --git a/stormpy/src/core/core.h b/stormpy/src/core/core.h new file mode 100644 index 000000000..f750d7c74 --- /dev/null +++ b/stormpy/src/core/core.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_CORE_H_ +#define PYTHON_CORE_CORE_H_ + +#include "common.h" + +void define_core(py::module& m); + +#endif /* PYTHON_CORE_CORE_H_ */ diff --git a/stormpy/src/core/model.cpp b/stormpy/src/core/model.cpp new file mode 100644 index 000000000..25b78a634 --- /dev/null +++ b/stormpy/src/core/model.cpp @@ -0,0 +1,75 @@ +#include "model.h" + +// Thin wrapper for model building +template +std::shared_ptr buildModel(storm::prism::Program const& program, std::shared_ptr const& formula) { + return storm::buildSymbolicModel(program, std::vector>(1,formula)).model; +} + +// Thin wrapper for getting initial states +template +std::vector getInitialStates(storm::models::sparse::Model const& model) { + std::vector initialStates; + for (auto entry : model.getInitialStates()) { + initialStates.push_back(entry); + } + return initialStates; +} + +// Define python bindings +void define_model(py::module& m) { + + // Build model + m.def("_build_model", &buildModel, "Build the model", py::arg("program"), py::arg("formula")); + m.def("_build_parametric_model", &buildModel, "Build the parametric model", py::arg("program"), py::arg("formula")); + m.def("build_model_from_prism_program", &storm::buildSymbolicModel, "Build the model", py::arg("program"), py::arg("formulas")); + m.def("build_parametric_model_from_prism_program", &storm::buildSymbolicModel, "Build the parametric model", py::arg("program"), py::arg("formulas")); + + // ModelType + py::enum_(m, "ModelType", "Type of the model") + .value("DTMC", storm::models::ModelType::Dtmc) + .value("MDP", storm::models::ModelType::Mdp) + .value("CTMC", storm::models::ModelType::Ctmc) + .value("MA", storm::models::ModelType::MarkovAutomaton) + ; + + // ModelBase + py::class_>(m, "ModelBase", "Base class for all models") + .def("nr_states", &storm::models::ModelBase::getNumberOfStates, "Get number of states") + .def("nr_transitions", &storm::models::ModelBase::getNumberOfTransitions, "Get number of transitions") + .def("model_type", &storm::models::ModelBase::getType, "Get model type") + .def("supports_parameters", &storm::models::ModelBase::supportsParameters, "Check if model supports parameters") + .def("has_parameters", &storm::models::ModelBase::hasParameters, "Check if model has parameters") + .def("is_exact", &storm::models::ModelBase::isExact, "Check if model is exact") + .def("as_dtmc", &storm::models::ModelBase::as>, "Get model as DTMC") + .def("as_pdtmc", &storm::models::ModelBase::as>, "Get model as pDTMC") + .def("as_mdp", &storm::models::ModelBase::as>, "Get model as MDP") + .def("as_pmdp", &storm::models::ModelBase::as>, "Get model as pMDP") + ; + + // Models + py::class_, std::shared_ptr>>(m, "SparseModel", "A probabilistic model where transitions are represented by doubles and saved in a sparse matrix", py::base()) + .def("labels", [](storm::models::sparse::Model const& model) { + return model.getStateLabeling().getLabels(); + }, "Get labels") + .def("labels_state", &storm::models::sparse::Model::getLabelsOfState, "Get labels") + .def("initial_states", &getInitialStates, "Get initial states") + ; + py::class_, std::shared_ptr>>(m, "SparseDtmc", "DTMC in sparse representation", py::base>()) + ; + py::class_, std::shared_ptr>>(m, "SparseMdp", "MDP in sparse representation", py::base>()) + ; + py::class_, std::shared_ptr>>(m, "SparseParametricModel", "A probabilistic model where transitions are represented by rational functions and saved in a sparse matrix", py::base()) + .def("collect_probability_parameters", &storm::models::sparse::getProbabilityParameters, "Collect parameters") + .def("labels", [](storm::models::sparse::Model const& model) { + return model.getStateLabeling().getLabels(); + }, "Get labels") + .def("labels_state", &storm::models::sparse::Model::getLabelsOfState, "Get labels") + .def("initial_states", &getInitialStates, "Get initial states") + ; + py::class_, std::shared_ptr>>(m, "SparseParametricDtmc", "pDTMC in sparse representation", py::base>()) + ; + py::class_, std::shared_ptr>>(m, "SparseParametricMdp", "pMDP in sparse representation", py::base>()) + ; + +} diff --git a/stormpy/src/core/model.h b/stormpy/src/core/model.h new file mode 100644 index 000000000..9f5c279e6 --- /dev/null +++ b/stormpy/src/core/model.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_MODEL_H_ +#define PYTHON_CORE_MODEL_H_ + +#include "common.h" + +void define_model(py::module& m); + +#endif /* PYTHON_CORE_MODEL_H_ */ diff --git a/stormpy/src/core/modelchecking.cpp b/stormpy/src/core/modelchecking.cpp new file mode 100644 index 000000000..3e9b7756b --- /dev/null +++ b/stormpy/src/core/modelchecking.cpp @@ -0,0 +1,57 @@ +#include "modelchecking.h" + +// Class holding the model checking result +class PmcResult { + public: + storm::RationalFunction resultFunction; + std::unordered_set> constraintsWellFormed; + std::unordered_set> constraintsGraphPreserving; + + std::string toString() { + std::stringstream stream; + stream << resultFunction << std::endl; + stream << "Well formed constraints:" << std::endl; + for (auto constraint : constraintsWellFormed) { + stream << constraint << std::endl; + } + stream << "Graph preserving constraints:" << std::endl; + for (auto constraint : constraintsGraphPreserving) { + stream << constraint << std::endl; + } + return stream.str(); + } +}; + +// Thin wrapper for model checking +double modelChecking(std::shared_ptr> model, std::shared_ptr const& formula) { + std::unique_ptr checkResult = storm::verifySparseModel(model, formula); + return checkResult->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; +} + +// Thin wrapper for parametric model checking +std::shared_ptr parametricModelChecking(std::shared_ptr> model, std::shared_ptr const& formula) { + std::unique_ptr checkResult = storm::verifySparseModel(model, formula); + std::shared_ptr result = std::make_shared(); + result->resultFunction = checkResult->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; + storm::models::sparse::Dtmc::ConstraintCollector constraintCollector(*(model->template as>())); + result->constraintsWellFormed = constraintCollector.getWellformedConstraints(); + result->constraintsGraphPreserving = constraintCollector.getGraphPreservingConstraints(); + return result; +} + +// Define python bindings +void define_modelchecking(py::module& m) { + + // Model checking + m.def("_model_checking", &modelChecking, "Perform model checking", py::arg("model"), py::arg("formula")); + m.def("_parametric_model_checking", ¶metricModelChecking, "Perform parametric model checking", py::arg("model"), py::arg("formula")); + + // PmcResult + py::class_>(m, "PmcResult", "Holds the results after parametric model checking") + .def("__str__", &PmcResult::toString) + .def_readonly("result_function", &PmcResult::resultFunction, "Result as rational function") + .def_readonly("constraints_well_formed", &PmcResult::constraintsWellFormed, "Constraints ensuring well-formed probabilities") + .def_readonly("constraints_graph_preserving", &PmcResult::constraintsGraphPreserving, "Constraints ensuring graph preservation") + ; + +} diff --git a/stormpy/src/core/modelchecking.h b/stormpy/src/core/modelchecking.h new file mode 100644 index 000000000..06b1aad3c --- /dev/null +++ b/stormpy/src/core/modelchecking.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_MODELCHECKING_H_ +#define PYTHON_CORE_MODELCHECKING_H_ + +#include "common.h" + +void define_modelchecking(py::module& m); + +#endif /* PYTHON_CORE_MODELCHECKING_H_ */ diff --git a/stormpy/src/core/prism.cpp b/stormpy/src/core/prism.cpp new file mode 100644 index 000000000..2cc88f370 --- /dev/null +++ b/stormpy/src/core/prism.cpp @@ -0,0 +1,26 @@ +#include "prism.h" + +// Define python bindings +void define_prism(py::module& m) { + + // Parse prism program + m.def("parse_program", &storm::parseProgram, "Parse program", py::arg("path")); + + // PrismType + py::enum_(m, "PrismModelType", "Type of the prism model") + .value("DTMC", storm::prism::Program::ModelType::DTMC) + .value("CTMC", storm::prism::Program::ModelType::CTMC) + .value("MDP", storm::prism::Program::ModelType::MDP) + .value("CTMDP", storm::prism::Program::ModelType::CTMDP) + .value("MA", storm::prism::Program::ModelType::MA) + .value("UNDEFINED", storm::prism::Program::ModelType::UNDEFINED) + ; + + // PrismProgram + py::class_(m, "Program", "Prism program") + .def("nr_modules", &storm::prism::Program::getNumberOfModules, "Get number of modules") + .def("model_type", &storm::prism::Program::getModelType, "Get model type") + .def("has_undefined_constants", &storm::prism::Program::hasUndefinedConstants, "Check if program has undefined constants") + ; + +} diff --git a/stormpy/src/core/prism.h b/stormpy/src/core/prism.h new file mode 100644 index 000000000..6a4d43307 --- /dev/null +++ b/stormpy/src/core/prism.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_PRISM_H_ +#define PYTHON_CORE_PRISM_H_ + +#include "common.h" + +void define_prism(py::module& m); + +#endif /* PYTHON_CORE_PRISM_H_ */ diff --git a/stormpy/src/helpers.h b/stormpy/src/helpers.h new file mode 100644 index 000000000..ffda72c19 --- /dev/null +++ b/stormpy/src/helpers.h @@ -0,0 +1,29 @@ +/* + * helpers.h + * + * Created on: 16 Apr 2016 + * Author: harold + */ + +#ifndef PYTHON_HELPERS_H_ +#define PYTHON_HELPERS_H_ + +#include +#include + +/** + * Helper function to get a string out of the stream operator. + * Used for __str__ functions. + */ +template +std::string streamToString(T const & t) { + std::stringstream ss; + ss << t; + return ss.str(); +} + +// Be warned: Enabling something like this will break everything about Monomial, +// as to Python the shared_ptr (Arg) IS the Monomial +// //PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); + +#endif /* PYTHON_HELPERS_H_ */ diff --git a/stormpy/src/logic/formulae.cpp b/stormpy/src/logic/formulae.cpp new file mode 100644 index 000000000..ad4bb52b1 --- /dev/null +++ b/stormpy/src/logic/formulae.cpp @@ -0,0 +1,59 @@ +#include "formulae.h" + +#include "src/common.h" +#include "src/logic/Formulas.h" + +void define_formulae(py::module& m) { + + py::enum_(m, "ComparisonType") + .value("LESS", storm::logic::ComparisonType::Less) + .value("LEQ", storm::logic::ComparisonType::LessEqual) + .value("GREATER", storm::logic::ComparisonType::Greater) + .value("GEQ", storm::logic::ComparisonType::GreaterEqual) + ; + + /*py::class_>, void, void>("FormulaVec", "Vector of formulas") + .def(vector_indexing_suite>, true>()) + ;*/ + + py::class_>(m, "Formula", "Generic Storm Formula") + .def("__str__", &storm::logic::Formula::toString) + ; + + // Path Formulae + py::class_>(m, "PathFormula", "Formula about the probability of a set of paths in an automaton", py::base()); + py::class_>(m, "UnaryPathFormula", "Path formula with one operand", py::base()); + py::class_>(m, "EventuallyFormula", "Formula for eventually", py::base()); + py::class_>(m, "GloballyFormula", "Formula for globally", py::base()); + py::class_>(m, "BinaryPathFormula", "Path formula with two operands", py::base()); + py::class_>(m, "BoundedUntilFormula", "Until Formula with either a step or a time bound.", py::base()); + py::class_>(m, "ConditionalFormula", "Formula with the right hand side being a condition.", py::base()); + py::class_>(m, "UntilFormula", "Path Formula for unbounded until", py::base()); + + // Reward Path Formulae + //py::class_(m, "RewardPathFormula", "Formula about the rewards of a set of paths in an automaton", py::base()); + py::class_>(m, "CumulativeRewardFormula", "Summed rewards over a the paths", py::base()); + py::class_>(m ,"InstantaneousRewardFormula", "Instantaneous reward", py::base()); + py::class_>(m, "LongRunAverageRewardFormula", "Long run average reward", py::base()); + //py::class_>(m, "ReachabilityRewardFormula", "Reachability reward", py::base()); + + + // State Formulae + py::class_>(m, "StateFormula", "Formula about a state of an automaton", py::base()); + py::class_>(m, "AtomicExpressionFormula", "Formula with an atomic expression", py::base()); + py::class_>(m, "AtomicLabelFormula", "Formula with an atomic label", py::base()); + py::class_>(m, "BooleanLiteralFormula", "Formula with a boolean literal", py::base()); + py::class_>(m, "UnaryStateFormula", "State formula with one operand", py::base()); + py::class_>(m, "UnaryBooleanStateFormula", "Unary boolean state formula", py::base()); + py::class_>(m, "OperatorFormula", "Operator formula", py::base()) + .def("has_bound", &storm::logic::OperatorFormula::hasBound, "Check if formula is bounded") + .def_property("threshold", &storm::logic::OperatorFormula::getThreshold, &storm::logic::OperatorFormula::setThreshold, "Threshold of bound") + .def_property("comparison_type", &storm::logic::OperatorFormula::getComparisonType, &storm::logic::OperatorFormula::setComparisonType, "Comparison type of bound") + ; + py::class_>(m, "TimeOperator", "The time operator", py::base()); + py::class_>(m, "LongRunAvarageOperator", "Long run average operator", py::base()); + py::class_>(m, "ProbabilityOperator", "Probability operator", py::base()); + py::class_>(m, "RewardOperator", "Reward operator", py::base()); + py::class_>(m, "BinaryStateFormula", "State formula with two operands", py::base()); + py::class_>(m, "BooleanBinaryStateFormula", "Boolean binary state formula", py::base()); +} diff --git a/stormpy/src/logic/formulae.h b/stormpy/src/logic/formulae.h new file mode 100644 index 000000000..d499685e7 --- /dev/null +++ b/stormpy/src/logic/formulae.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_LOGIC_FORMULAE_H_ +#define PYTHON_LOGIC_FORMULAE_H_ + +#include "src/common.h" + +void define_formulae(py::module& m); + +#endif /* PYTHON_LOGIC_FORMULAE_H_ */ diff --git a/stormpy/src/mod_core.cpp b/stormpy/src/mod_core.cpp new file mode 100644 index 000000000..c86da7fba --- /dev/null +++ b/stormpy/src/mod_core.cpp @@ -0,0 +1,17 @@ +#include "common.h" + +#include "core/core.h" +#include "core/model.h" +#include "core/modelchecking.h" +#include "core/bisimulation.h" +#include "core/prism.h" + +PYBIND11_PLUGIN(core) { + py::module m("core"); + define_core(m); + define_model(m); + define_modelchecking(m); + define_bisimulation(m); + define_prism(m); + return m.ptr(); +} diff --git a/stormpy/src/mod_expressions.cpp b/stormpy/src/mod_expressions.cpp new file mode 100644 index 000000000..ffe9a223c --- /dev/null +++ b/stormpy/src/mod_expressions.cpp @@ -0,0 +1,16 @@ +#include "common.h" +#include "helpers.h" + +#include + +PYBIND11_PLUGIN(expressions) { + py::module m("stormpy.expressions", "Storm expressions"); + + py::class_>(m, "ExpressionManager", "Manages variables for expressions") + ; + + py::class_(m, "Expression", "Holds an expression") + ; + + return m.ptr(); +} diff --git a/stormpy/src/mod_info.cpp b/stormpy/src/mod_info.cpp new file mode 100644 index 000000000..c40253c75 --- /dev/null +++ b/stormpy/src/mod_info.cpp @@ -0,0 +1,14 @@ +#include "common.h" +#include "helpers.h" + +#include + +PYBIND11_PLUGIN(info) { + py::module m("stormpy.info", "Storm information"); + py::class_(m, "Version", "Version information for Storm") + .def("short", &storm::utility::StormVersion::shortVersionString, "Storm version in short representation") + .def("long", &storm::utility::StormVersion::longVersionString, "Storm version in long representation") + .def("build_info", &storm::utility::StormVersion::buildInfo, "Build info for Storm") + ; + return m.ptr(); +} diff --git a/stormpy/src/mod_logic.cpp b/stormpy/src/mod_logic.cpp new file mode 100644 index 000000000..49f16d7aa --- /dev/null +++ b/stormpy/src/mod_logic.cpp @@ -0,0 +1,9 @@ +#include "common.h" + +#include "logic/formulae.h" + +PYBIND11_PLUGIN(logic) { + py::module m("stormpy.logic", "Logic module for Storm"); + define_formulae(m); + return m.ptr(); +} diff --git a/stormpy/tests/.gitignore b/stormpy/tests/.gitignore new file mode 100644 index 000000000..bee8a64b7 --- /dev/null +++ b/stormpy/tests/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/stormpy/tests/core/test_bisimulation.py b/stormpy/tests/core/test_bisimulation.py new file mode 100644 index 000000000..5d74a2953 --- /dev/null +++ b/stormpy/tests/core/test_bisimulation.py @@ -0,0 +1,40 @@ +import stormpy +import stormpy.logic + +class TestBisimulation: + def test_bisimulation(self): + program = stormpy.parse_program("../examples/dtmc/crowds/crowds5_5.pm") + assert program.nr_modules() == 1 + assert program.model_type() == stormpy.PrismModelType.DTMC + prop = "P=? [F \"observe0Greater1\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 7403 + assert model.nr_transitions() == 13041 + assert model.model_type() == stormpy.ModelType.DTMC + assert not model.supports_parameters() + model_bisim = stormpy.perform_bisimulation(model, formulas[0], stormpy.BisimulationType.STRONG) + assert model_bisim.nr_states() == 64 + assert model_bisim.nr_transitions() == 104 + assert model_bisim.model_type() == stormpy.ModelType.DTMC + assert not model_bisim.supports_parameters() + + def test_parametric_bisimulation(self): + program = stormpy.parse_program("../examples/pdtmc/crowds/crowds_3-5.pm") + assert program.nr_modules() == 1 + assert program.model_type() == stormpy.PrismModelType.DTMC + assert program.has_undefined_constants() + prop = "P=? [F \"observe0Greater1\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_parametric_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 1367 + assert model.nr_transitions() == 2027 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.has_parameters() + model_bisim = stormpy.perform_bisimulation(model, formulas[0], stormpy.BisimulationType.STRONG) + assert model_bisim.nr_states() == 80 + assert model_bisim.nr_transitions() == 120 + assert model_bisim.model_type() == stormpy.ModelType.DTMC + assert model_bisim.has_parameters() diff --git a/stormpy/tests/core/test_core.py b/stormpy/tests/core/test_core.py new file mode 100644 index 000000000..d711e12be --- /dev/null +++ b/stormpy/tests/core/test_core.py @@ -0,0 +1,10 @@ +import stormpy + +class TestCore: + def test_init(self): + stormpy.set_up("") + + def test_pycarl(self): + import pycarl + import pycarl.formula + import pycarl.parse diff --git a/stormpy/tests/core/test_model.py b/stormpy/tests/core/test_model.py new file mode 100644 index 000000000..8958080b7 --- /dev/null +++ b/stormpy/tests/core/test_model.py @@ -0,0 +1,98 @@ +import stormpy +import stormpy.logic + +class TestModel: + def test_build_dtmc_from_prism_program(self): + stormpy.set_up("") + program = stormpy.parse_program("../examples/dtmc/die/die.pm") + prop = "P=? [F \"one\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 13 + assert model.nr_transitions() == 20 + assert model.model_type() == stormpy.ModelType.DTMC + assert not model.supports_parameters() + assert type(model) is stormpy.SparseDtmc + + def test_build_parametric_dtmc_from_prism_program(self): + program = stormpy.parse_program("../examples/pdtmc/brp/brp_16_2.pm") + assert program.nr_modules() == 5 + assert program.model_type() == stormpy.PrismModelType.DTMC + assert program.has_undefined_constants() + prop = "P=? [F \"target\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_parametric_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 613 + assert model.nr_transitions() == 803 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.supports_parameters() + assert model.has_parameters() + assert type(model) is stormpy.SparseParametricDtmc + + def test_build_dtmc(self): + program = stormpy.parse_program("../examples/dtmc/die/die.pm") + formulas = stormpy.parse_formulas_for_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + assert model.nr_states() == 13 + assert model.nr_transitions() == 20 + assert model.model_type() == stormpy.ModelType.DTMC + assert not model.supports_parameters() + assert type(model) is stormpy.SparseDtmc + + def test_build_parametric_dtmc(self): + program = stormpy.parse_program("../examples/pdtmc/brp/brp_16_2.pm") + formulas = stormpy.parse_formulas_for_program("P=? [ F \"target\" ]", program) + model = stormpy.build_parametric_model(program, formulas[0]) + assert model.nr_states() == 613 + assert model.nr_transitions() == 803 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.supports_parameters() + assert model.has_parameters() + assert type(model) is stormpy.SparseParametricDtmc + + def test_build_dtmc_supporting_parameters(self): + program = stormpy.parse_program("../examples/dtmc/die/die.pm") + formulas = stormpy.parse_formulas_for_program("P=? [ F \"one\" ]", program) + model = stormpy.build_parametric_model(program, formulas[0]) + assert model.nr_states() == 13 + assert model.nr_transitions() == 20 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.supports_parameters() + assert not model.has_parameters() + assert type(model) is stormpy.SparseParametricDtmc + + def test_label(self): + program = stormpy.parse_program("../examples/dtmc/die/die.pm") + formulas = stormpy.parse_formulas_for_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + labels = model.labels() + assert len(labels) == 2 + assert "init" in labels + assert "one" in labels + assert "init" in model.labels_state(0) + assert "one" in model.labels_state(7) + + def test_initial_states(self): + program = stormpy.parse_program("../examples/dtmc/die/die.pm") + formulas = stormpy.parse_formulas_for_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + initial_states = model.initial_states() + assert len(initial_states) == 1 + assert 0 in initial_states + + def test_label_parametric(self): + program = stormpy.parse_program("../examples/pdtmc/brp/brp_16_2.pm") + formulas = stormpy.parse_formulas_for_program("P=? [ F \"target\" ]", program) + model = stormpy.build_parametric_model(program, formulas[0]) + labels = model.labels() + assert len(labels) == 2 + assert "init" in labels + assert "target" in labels + assert "init" in model.labels_state(0) + assert "target" in model.labels_state(28) + assert "target" in model.labels_state(611) + initial_states = model.initial_states() + assert len(initial_states) == 1 + assert 0 in initial_states diff --git a/stormpy/tests/core/test_modelchecking.py b/stormpy/tests/core/test_modelchecking.py new file mode 100644 index 000000000..334d049cf --- /dev/null +++ b/stormpy/tests/core/test_modelchecking.py @@ -0,0 +1,35 @@ +import stormpy +import stormpy.logic + +class TestModelChecking: + def test_state_elimination(self): + program = stormpy.parse_program("../examples/dtmc/die/die.pm") + formulas = stormpy.parse_formulas_for_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + assert model.nr_states() == 13 + assert model.nr_transitions() == 20 + result = stormpy.model_checking(model, formulas[0]) + assert result == 0.16666666666666663 + + def test_parametric_state_elimination(self): + import pycarl + import pycarl.formula + program = stormpy.parse_program("../examples/pdtmc/brp/brp_16_2.pm") + prop = "P=? [F \"target\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_parametric_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 613 + assert model.nr_transitions() == 803 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.has_parameters() + result = stormpy.model_checking(model, formulas[0]) + func = result.result_function + one = pycarl.FactorizedPolynomial(pycarl.Rational(1)) + assert func.denominator == one + constraints_well_formed = result.constraints_well_formed + for constraint in constraints_well_formed: + assert constraint.rel() == pycarl.formula.Relation.GEQ or constraint.rel() == pycarl.formula.Relation.LEQ + constraints_graph_preserving = result.constraints_graph_preserving + for constraint in constraints_graph_preserving: + assert constraint.rel() == pycarl.formula.Relation.GREATER diff --git a/stormpy/tests/core/test_parse.py b/stormpy/tests/core/test_parse.py new file mode 100644 index 000000000..6335eb6c5 --- /dev/null +++ b/stormpy/tests/core/test_parse.py @@ -0,0 +1,15 @@ +import stormpy +import stormpy.logic + +class TestParse: + def test_parse_program(self): + program = stormpy.parse_program("../examples/dtmc/die/die.pm") + assert program.nr_modules() == 1 + assert program.model_type() == stormpy.PrismModelType.DTMC + assert not program.has_undefined_constants() + + def test_parse_formula(self): + prop = "P=? [F \"one\"]" + formulas = stormpy.parse_formulas(prop) + assert len(formulas) == 1 + assert str(formulas[0]) == prop diff --git a/stormpy/tests/expressions/test_expressions.py b/stormpy/tests/expressions/test_expressions.py new file mode 100644 index 000000000..823186d62 --- /dev/null +++ b/stormpy/tests/expressions/test_expressions.py @@ -0,0 +1,9 @@ +import stormpy +from stormpy.expressions import expressions + +class TestExpressions: + def test_expression_manager(self): + manager = expressions.ExpressionManager + + def test_expression(self): + expression = expressions.Expression diff --git a/stormpy/tests/info/test_info.py b/stormpy/tests/info/test_info.py new file mode 100644 index 000000000..133ae36d2 --- /dev/null +++ b/stormpy/tests/info/test_info.py @@ -0,0 +1,8 @@ +import stormpy +from stormpy.info import info + +class TestInfo: + def test_version(self): + s = info.Version.short() + s = info.Version.long() + s = info.Version.build_info() diff --git a/stormpy/tests/logic/test_formulas.py b/stormpy/tests/logic/test_formulas.py new file mode 100644 index 000000000..7600f5a6f --- /dev/null +++ b/stormpy/tests/logic/test_formulas.py @@ -0,0 +1,50 @@ +import stormpy +from stormpy.logic import logic + +class TestFormulas: + + def test_probability_formula(self): + prop = "P=? [F \"one\"]" + formulas = stormpy.parse_formulas(prop) + formula = formulas[0] + assert type(formula) == logic.ProbabilityOperator + assert len(formulas) == 1 + assert str(formula) == prop + + def test_reward_formula(self): + prop = "R=? [F \"one\"]" + formulas = stormpy.parse_formulas(prop) + formula = formulas[0] + assert type(formula) == logic.RewardOperator + assert len(formulas) == 1 + assert str(formula) == "R[exp]=? [F \"one\"]" + + def test_formula_list(self): + formulas = [] + prop = "=? [F \"one\"]" + forms = stormpy.parse_formulas("P" + prop) + formulas.append(forms[0]) + forms = stormpy.parse_formulas("R" + prop) + formulas.append(forms[0]) + assert len(formulas) == 2 + assert str(formulas[0]) == "P" + prop + assert str(formulas[1]) == "R[exp]" + prop + + def test_bounds(self): + prop = "P=? [F \"one\"]" + formula = stormpy.parse_formulas(prop)[0] + assert not formula.has_bound() + prop = "P<0.4 [F \"one\"]" + formula = stormpy.parse_formulas(prop)[0] + assert formula.has_bound() + assert formula.threshold == 0.4 + assert formula.comparison_type == logic.ComparisonType.LESS + + def test_set_bounds(self): + prop = "P<0.4 [F \"one\"]" + formula = stormpy.parse_formulas(prop)[0] + formula.threshold = 0.2 + formula.comparison_type = logic.ComparisonType.GEQ + assert formula.threshold == 0.2 + assert formula.comparison_type == logic.ComparisonType.GEQ + assert str(formula) == "P>=0.2 [F \"one\"]" diff --git a/test/functional/logic/FragmentCheckerTest.cpp b/test/functional/logic/FragmentCheckerTest.cpp index bb5d358c9..0280844d3 100644 --- a/test/functional/logic/FragmentCheckerTest.cpp +++ b/test/functional/logic/FragmentCheckerTest.cpp @@ -9,7 +9,7 @@ TEST(FragmentCheckerTest, Propositional) { storm::logic::FragmentSpecification prop = storm::logic::propositional(); storm::parser::FormulaParser formulaParser; - std::shared_ptr formula; + std::shared_ptr formula; ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString("\"label\"")); EXPECT_TRUE(checker.conformsToSpecification(*formula, prop)); @@ -41,7 +41,7 @@ TEST(FragmentCheckerTest, Pctl) { storm::logic::FragmentSpecification pctl = storm::logic::pctl(); storm::parser::FormulaParser formulaParser; - std::shared_ptr formula; + std::shared_ptr formula; ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString("\"label\"")); EXPECT_TRUE(checker.conformsToSpecification(*formula, pctl)); @@ -61,7 +61,7 @@ TEST(FragmentCheckerTest, Prctl) { storm::logic::FragmentSpecification prctl = storm::logic::prctl(); storm::parser::FormulaParser formulaParser; - std::shared_ptr formula; + std::shared_ptr formula; ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString("\"label\"")); EXPECT_TRUE(checker.conformsToSpecification(*formula, prctl)); @@ -87,7 +87,7 @@ TEST(FragmentCheckerTest, Csl) { storm::logic::FragmentSpecification csl = storm::logic::csl(); storm::parser::FormulaParser formulaParser; - std::shared_ptr formula; + std::shared_ptr formula; ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString("\"label\"")); EXPECT_TRUE(checker.conformsToSpecification(*formula, csl)); @@ -110,7 +110,7 @@ TEST(FragmentCheckerTest, Csrl) { storm::logic::FragmentSpecification csrl = storm::logic::csrl(); storm::parser::FormulaParser formulaParser; - std::shared_ptr formula; + std::shared_ptr formula; ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString("\"label\"")); EXPECT_TRUE(checker.conformsToSpecification(*formula, csrl)); diff --git a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp index dc9512a38..39c10b59f 100644 --- a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp @@ -24,7 +24,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Cluster) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -107,7 +107,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Embedded) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -176,7 +176,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Polling) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. std::shared_ptr> model = storm::builder::ExplicitPrismModelBuilder(program).translate(); @@ -217,7 +217,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Tandem) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS diff --git a/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp index 715489715..8b9550fa3 100644 --- a/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp @@ -31,7 +31,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Die) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -75,7 +75,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Crowds) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -112,7 +112,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, SynchronousLeader) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -155,7 +155,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, LRASingleBscc) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -179,7 +179,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, LRASingleBscc) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -203,7 +203,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, LRASingleBscc) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -266,7 +266,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, LRA) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -295,7 +295,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Conditional) { // A parser that we use for conveniently constructing the formulas. storm::parser::FormulaParser formulaParser; - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"target\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"target\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); diff --git a/test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp index d5bd19fe2..fd32f5f20 100644 --- a/test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp @@ -27,7 +27,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Cluster_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -124,7 +124,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Cluster_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -221,7 +221,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Embedded_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -300,7 +300,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Embedded_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -379,7 +379,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Polling_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. std::shared_ptr> model = storm::builder::DdPrismModelBuilder().translateProgram(program); @@ -415,7 +415,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Polling_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. std::shared_ptr> model = storm::builder::DdPrismModelBuilder().translateProgram(program); @@ -458,7 +458,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Tandem_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model with the customers reward structure. #ifdef WINDOWS @@ -546,7 +546,7 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Tandem_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model with the customers reward structure. #ifdef WINDOWS @@ -625,4 +625,4 @@ TEST(GmmxxHybridCtmcCslModelCheckerTest, Tandem_Sylvan) { storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult7 = checkResult->asHybridQuantitativeCheckResult(); EXPECT_NEAR(0.9100373532, quantitativeCheckResult7.getMin(), storm::settings::generalSettings().getPrecision()); EXPECT_NEAR(0.9100373532, quantitativeCheckResult7.getMax(), storm::settings::generalSettings().getPrecision()); -} \ No newline at end of file +} diff --git a/test/functional/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp index 6d0eac386..3f3254bdd 100644 --- a/test/functional/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp @@ -42,7 +42,7 @@ TEST(GmmxxHybridDtmcPrctlModelCheckerTest, Die_Cudd) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -103,7 +103,7 @@ TEST(GmmxxHybridDtmcPrctlModelCheckerTest, Die_Sylvan) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -156,7 +156,7 @@ TEST(GmmxxHybridDtmcPrctlModelCheckerTest, Crowds_Cudd) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -200,7 +200,7 @@ TEST(GmmxxHybridDtmcPrctlModelCheckerTest, Crowds_Sylvan) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -252,7 +252,7 @@ TEST(GmmxxHybridDtmcPrctlModelCheckerTest, SynchronousLeader_Cudd) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -304,7 +304,7 @@ TEST(GmmxxHybridDtmcPrctlModelCheckerTest, SynchronousLeader_Sylvan) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); diff --git a/test/functional/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp index 06a236b4d..06d09f758 100644 --- a/test/functional/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp @@ -44,7 +44,7 @@ TEST(GmmxxHybridMdpPrctlModelCheckerTest, Dice_Cudd) { storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -141,7 +141,7 @@ TEST(GmmxxHybridMdpPrctlModelCheckerTest, Dice_Sylvan) { storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -238,7 +238,7 @@ TEST(GmmxxHybridMdpPrctlModelCheckerTest, AsynchronousLeader_Cudd) { storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -317,7 +317,7 @@ TEST(GmmxxHybridMdpPrctlModelCheckerTest, AsynchronousLeader_Sylvan) { storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); diff --git a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp index 22e7d8464..bcae93e2d 100644 --- a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp @@ -32,7 +32,7 @@ TEST(GmmxxMdpPrctlModelCheckerTest, Dice) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -148,7 +148,7 @@ TEST(GmmxxMdpPrctlModelCheckerTest, AsynchronousLeader) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -211,7 +211,7 @@ TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) { solverFactory->setPreferredTechnique(storm::solver::MinMaxTechniqueSelection::PolicyIteration); storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::move(solverFactory)); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"target\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"target\"]"); storm::modelchecker::CheckTask checkTask(*formula); checkTask.setProduceSchedulers(true); @@ -261,7 +261,7 @@ TEST(GmmxxMdpPrctlModelCheckerTest, tiny_rewards) { solverFactory->setPreferredTechnique(storm::solver::MinMaxTechniqueSelection::ValueIteration); storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::move(solverFactory)); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Rmin=? [F \"target\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Rmin=? [F \"target\"]"); storm::modelchecker::CheckTask checkTask(*formula); diff --git a/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp index 0a1d8ee4c..f166dc34f 100644 --- a/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp +++ b/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp @@ -22,7 +22,7 @@ TEST(NativeCtmcCslModelCheckerTest, Cluster) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -98,7 +98,7 @@ TEST(NativeCtmcCslModelCheckerTest, Embedded) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -160,7 +160,7 @@ TEST(NativeCtmcCslModelCheckerTest, Polling) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. std::shared_ptr> model = storm::builder::ExplicitPrismModelBuilder(program).translate(); @@ -194,7 +194,7 @@ TEST(NativeCtmcCslModelCheckerTest, Tandem) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model with the customers reward structure. #ifdef WINDOWS diff --git a/test/functional/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp b/test/functional/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp index 253417bad..7cb0fa66d 100644 --- a/test/functional/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp @@ -31,7 +31,7 @@ TEST(SparseDtmcPrctlModelCheckerTest, Die) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -75,7 +75,7 @@ TEST(SparseDtmcPrctlModelCheckerTest, Crowds) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -112,7 +112,7 @@ TEST(SparseDtmcPrctlModelCheckerTest, SynchronousLeader) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -155,7 +155,7 @@ TEST(SparseDtmcPrctlModelCheckerTest, LRASingleBscc) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory(storm::solver::NativeLinearEquationSolverSolutionMethod::SOR, 0.9))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -179,7 +179,7 @@ TEST(SparseDtmcPrctlModelCheckerTest, LRASingleBscc) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory(storm::solver::NativeLinearEquationSolverSolutionMethod::SOR, 0.9))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -203,7 +203,7 @@ TEST(SparseDtmcPrctlModelCheckerTest, LRASingleBscc) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory(storm::solver::NativeLinearEquationSolverSolutionMethod::SOR, 0.9))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -266,7 +266,7 @@ TEST(SparseDtmcPrctlModelCheckerTest, LRA) { storm::modelchecker::SparseDtmcPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory(storm::solver::NativeLinearEquationSolverSolutionMethod::SOR, 0.9))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRA=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -279,4 +279,4 @@ TEST(SparseDtmcPrctlModelCheckerTest, LRA) { EXPECT_NEAR(.79 / 3., quantitativeResult1[13], storm::settings::nativeEquationSolverSettings().getPrecision()); EXPECT_NEAR(0.3 / 3., quantitativeResult1[14], storm::settings::nativeEquationSolverSettings().getPrecision()); } -} \ No newline at end of file +} diff --git a/test/functional/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp index 6b660acf8..8d098145a 100644 --- a/test/functional/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp +++ b/test/functional/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp @@ -26,7 +26,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Cluster_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -123,7 +123,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Cluster_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -220,7 +220,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Embedded_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -299,7 +299,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Embedded_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. #ifdef WINDOWS @@ -378,7 +378,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Polling_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. std::shared_ptr> model = storm::builder::DdPrismModelBuilder().translateProgram(program); @@ -414,7 +414,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Polling_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model. std::shared_ptr> model = storm::builder::DdPrismModelBuilder().translateProgram(program); @@ -457,7 +457,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Tandem_Cudd) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model with the customers reward structure. #ifdef WINDOWS @@ -547,7 +547,7 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Tandem_Sylvan) { // Parse the model description. storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); // Build the model with the customers reward structure. #ifdef WINDOWS @@ -628,4 +628,4 @@ TEST(NativeHybridCtmcCslModelCheckerTest, Tandem_Sylvan) { // FIXME: because of divergence, these results are not correct. // EXPECT_NEAR(0.9100373532, quantitativeCheckResult7.getMin(), storm::settings::generalSettings().getPrecision()); // EXPECT_NEAR(0.9100373532, quantitativeCheckResult7.getMax(), storm::settings::generalSettings().getPrecision()); -} \ No newline at end of file +} diff --git a/test/functional/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp b/test/functional/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp index 13c4f4f85..488cc5b0c 100644 --- a/test/functional/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp @@ -43,7 +43,7 @@ TEST(NativeHybridDtmcPrctlModelCheckerTest, Die_Cudd) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -104,7 +104,7 @@ TEST(NativeHybridDtmcPrctlModelCheckerTest, Die_Sylvan) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -157,7 +157,7 @@ TEST(NativeHybridDtmcPrctlModelCheckerTest, Crowds_Cudd) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -201,7 +201,7 @@ TEST(NativeHybridDtmcPrctlModelCheckerTest, Crowds_Sylvan) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -253,7 +253,7 @@ TEST(NativeHybridDtmcPrctlModelCheckerTest, SynchronousLeader_Cudd) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -305,7 +305,7 @@ TEST(NativeHybridDtmcPrctlModelCheckerTest, SynchronousLeader_Sylvan) { storm::modelchecker::HybridDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::NativeLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -331,4 +331,4 @@ TEST(NativeHybridDtmcPrctlModelCheckerTest, SynchronousLeader_Sylvan) { EXPECT_NEAR(1.0416666666666643, quantitativeResult3.getMin(), storm::settings::gmmxxEquationSolverSettings().getPrecision()); EXPECT_NEAR(1.0416666666666643, quantitativeResult3.getMax(), storm::settings::gmmxxEquationSolverSettings().getPrecision()); -} \ No newline at end of file +} diff --git a/test/functional/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp index 40ce383c5..e01cf5a26 100644 --- a/test/functional/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp @@ -41,7 +41,7 @@ TEST(NativeHybridMdpPrctlModelCheckerTest, Dice_Cudd) { std::shared_ptr> mdp = model->as>(); storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -137,7 +137,7 @@ TEST(NativeHybridMdpPrctlModelCheckerTest, Dice_Sylvan) { std::shared_ptr> mdp = model->as>(); storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -234,7 +234,7 @@ TEST(NativeHybridMdpPrctlModelCheckerTest, AsynchronousLeader_Cudd) { storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -313,7 +313,7 @@ TEST(NativeHybridMdpPrctlModelCheckerTest, AsynchronousLeader_Sylvan) { storm::modelchecker::HybridMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); diff --git a/test/functional/modelchecker/NativeMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/NativeMdpPrctlModelCheckerTest.cpp index 85c38e505..e16c93e14 100644 --- a/test/functional/modelchecker/NativeMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/NativeMdpPrctlModelCheckerTest.cpp @@ -29,7 +29,7 @@ TEST(SparseMdpPrctlModelCheckerTest, Dice) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -145,7 +145,7 @@ TEST(SparseMdpPrctlModelCheckerTest, AsynchronousLeader) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -209,7 +209,7 @@ TEST(SparseMdpPrctlModelCheckerTest, LRA_SingleMec) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -241,7 +241,7 @@ TEST(SparseMdpPrctlModelCheckerTest, LRA_SingleMec) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -282,7 +282,7 @@ TEST(SparseMdpPrctlModelCheckerTest, LRA_SingleMec) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -368,7 +368,7 @@ TEST(SparseMdpPrctlModelCheckerTest, LRA) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -490,7 +490,7 @@ TEST(SparseMdpPrctlModelCheckerTest, LRA) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("LRAmax=? [\"a\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -516,4 +516,4 @@ TEST(SparseMdpPrctlModelCheckerTest, LRA) { EXPECT_NEAR(.79 / 3., quantitativeResult2[13], storm::settings::nativeEquationSolverSettings().getPrecision()); EXPECT_NEAR(0.3 / 3., quantitativeResult2[14], storm::settings::nativeEquationSolverSettings().getPrecision()); } -} \ No newline at end of file +} diff --git a/test/functional/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp b/test/functional/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp index ad4d9ab3d..ff5e9da06 100644 --- a/test/functional/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp +++ b/test/functional/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp @@ -27,7 +27,7 @@ TEST(SparseDtmcEliminationModelCheckerTest, Die) { storm::modelchecker::SparseDtmcEliminationModelChecker> checker(*dtmc); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -71,7 +71,7 @@ TEST(SparseDtmcEliminationModelCheckerTest, Crowds) { storm::modelchecker::SparseDtmcEliminationModelChecker> checker(*dtmc); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -121,7 +121,7 @@ TEST(SparseDtmcEliminationModelCheckerTest, SynchronousLeader) { storm::modelchecker::SparseDtmcEliminationModelChecker> checker(*dtmc); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); diff --git a/test/functional/modelchecker/SparseExplorationModelCheckerTest.cpp b/test/functional/modelchecker/SparseExplorationModelCheckerTest.cpp index 0e7304f81..a9cf4c910 100644 --- a/test/functional/modelchecker/SparseExplorationModelCheckerTest.cpp +++ b/test/functional/modelchecker/SparseExplorationModelCheckerTest.cpp @@ -18,7 +18,7 @@ TEST(SparseExplorationModelCheckerTest, Dice) { storm::modelchecker::SparseExplorationModelChecker checker(program); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(storm::modelchecker::CheckTask<>(*formula, true)); storm::modelchecker::ExplicitQuantitativeCheckResult const& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -70,7 +70,7 @@ TEST(SparseExplorationModelCheckerTest, AsynchronousLeader) { storm::modelchecker::SparseExplorationModelChecker checker(program); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(storm::modelchecker::CheckTask<>(*formula, true)); storm::modelchecker::ExplicitQuantitativeCheckResult const& quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); diff --git a/test/functional/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp b/test/functional/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp index 8f6c9c9e5..29d6ef4e9 100644 --- a/test/functional/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp @@ -41,7 +41,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Die_Cudd) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -102,7 +102,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Die_Sylvan) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -156,7 +156,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Crowds_Cudd) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -200,7 +200,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Crowds_Sylvan) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -255,7 +255,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, SynchronousLeader_Cudd) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -307,7 +307,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, SynchronousLeader_Sylvan) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -333,4 +333,4 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, SynchronousLeader_Sylvan) { EXPECT_NEAR(1.0416666666666643, quantitativeResult3.getMin(), storm::settings::nativeEquationSolverSettings().getPrecision()); EXPECT_NEAR(1.0416666666666643, quantitativeResult3.getMax(), storm::settings::nativeEquationSolverSettings().getPrecision()); -} \ No newline at end of file +} diff --git a/test/functional/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp index a2486280d..ad26ef072 100644 --- a/test/functional/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp @@ -41,7 +41,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, Dice_Cudd) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -138,7 +138,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, Dice_Sylvan) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -235,7 +235,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, AsynchronousLeader_Cudd) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -314,7 +314,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, AsynchronousLeader_Sylvan) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -369,4 +369,4 @@ TEST(SymbolicMdpPrctlModelCheckerTest, AsynchronousLeader_Sylvan) { // FIXME: this precision bound is not really good. EXPECT_NEAR(4.2857, quantitativeResult6.getMin(), 100 * storm::settings::nativeEquationSolverSettings().getPrecision()); EXPECT_NEAR(4.2857, quantitativeResult6.getMax(), 100 * storm::settings::nativeEquationSolverSettings().getPrecision()); -} \ No newline at end of file +} diff --git a/test/functional/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp index 17b1a871a..d2a4420b7 100644 --- a/test/functional/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp @@ -28,7 +28,7 @@ TEST(TopologicalValueIterationMdpPrctlModelCheckerTest, Dice) { storm::modelchecker::SparseMdpPrctlModelChecker> mc(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Topological))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); std::unique_ptr result = mc.check(*formula); @@ -145,7 +145,7 @@ TEST(TopologicalValueIterationMdpPrctlModelCheckerTest, AsynchronousLeader) { storm::modelchecker::SparseMdpPrctlModelChecker> mc(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Topological))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = mc.check(*formula); diff --git a/test/functional/parser/FormulaParserTest.cpp b/test/functional/parser/FormulaParserTest.cpp index a3d78632b..1435806eb 100644 --- a/test/functional/parser/FormulaParserTest.cpp +++ b/test/functional/parser/FormulaParserTest.cpp @@ -8,7 +8,7 @@ TEST(FormulaParserTest, LabelTest) { storm::parser::FormulaParser formulaParser; std::string input = "\"label\""; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isAtomicLabelFormula()); @@ -18,7 +18,7 @@ TEST(FormulaParserTest, ComplexLabelTest) { storm::parser::FormulaParser formulaParser; std::string input = "!(\"a\" & \"b\") | \"a\" & !\"c\""; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isInFragment(storm::logic::propositional())); @@ -33,7 +33,7 @@ TEST(FormulaParserTest, ExpressionTest) { storm::parser::FormulaParser formulaParser(manager); std::string input = "!(x | y > 3)"; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isInFragment(storm::logic::propositional())); @@ -48,7 +48,7 @@ TEST(FormulaParserTest, LabelAndExpressionTest) { storm::parser::FormulaParser formulaParser(manager); std::string input = "!\"a\" | x | y > 3"; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isInFragment(storm::logic::propositional())); @@ -62,7 +62,7 @@ TEST(FormulaParserTest, ProbabilityOperatorTest) { storm::parser::FormulaParser formulaParser; std::string input = "P<0.9 [\"a\" U \"b\"]"; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isProbabilityOperatorFormula()); @@ -74,7 +74,7 @@ TEST(FormulaParserTest, RewardOperatorTest) { storm::parser::FormulaParser formulaParser; std::string input = "Rmin<0.9 [F \"a\"]"; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isRewardOperatorFormula()); @@ -94,7 +94,7 @@ TEST(FormulaParserTest, ConditionalProbabilityTest) { storm::parser::FormulaParser formulaParser; std::string input = "P<0.9 [F \"a\" || F \"b\"]"; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isProbabilityOperatorFormula()); @@ -106,7 +106,7 @@ TEST(FormulaParserTest, NestedPathFormulaTest) { storm::parser::FormulaParser formulaParser; std::string input = "P<0.9 [F X \"a\"]"; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isProbabilityOperatorFormula()); @@ -118,7 +118,7 @@ TEST(FormulaParserTest, CommentTest) { storm::parser::FormulaParser formulaParser; std::string input = "// This is a comment. And this is a commented out formula: P<=0.5 [ F \"a\" ] The next line contains the actual formula. \n P<=0.5 [ X \"b\" ] // Another comment \n // And again: another comment."; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); ASSERT_NO_THROW(formula = formulaParser.parseSingleFormulaFromString(input)); EXPECT_TRUE(formula->isProbabilityOperatorFormula()); ASSERT_TRUE(formula->asProbabilityOperatorFormula().getSubformula().isNextFormula()); @@ -133,7 +133,7 @@ TEST(FormulaParserTest, WrongFormatTest) { storm::parser::FormulaParser formulaParser(manager); std::string input = "P>0.5 [ a ]"; - std::shared_ptr formula(nullptr); + std::shared_ptr formula(nullptr); EXPECT_THROW(formula = formulaParser.parseSingleFormulaFromString(input), storm::exceptions::WrongFormatException); input = "P=0.5 [F \"a\"]"; diff --git a/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp b/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp index fe0a199b7..65c5ef132 100644 --- a/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp +++ b/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp @@ -43,7 +43,7 @@ TEST(NondeterministicModelBisimulationDecomposition, TwoDice) { // A parser that we use for conveniently constructing the formulas. storm::parser::FormulaParser formulaParser; - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"two\"]"); typename storm::storage::NondeterministicModelBisimulationDecomposition>::Options options2(*mdp, *formula); @@ -55,4 +55,4 @@ TEST(NondeterministicModelBisimulationDecomposition, TwoDice) { EXPECT_EQ(11ul, result->getNumberOfStates()); EXPECT_EQ(26ul, result->getNumberOfTransitions()); EXPECT_EQ(14ul, result->as>()->getNumberOfChoices()); -} \ No newline at end of file +} diff --git a/test/functional/utility/ModelInstantiatorTest.cpp b/test/functional/utility/ModelInstantiatorTest.cpp index 24512d886..e0b9765d1 100644 --- a/test/functional/utility/ModelInstantiatorTest.cpp +++ b/test/functional/utility/ModelInstantiatorTest.cpp @@ -27,7 +27,7 @@ TEST(ModelInstantiatorTest, BrpProb) { // Program and formula storm::prism::Program program = storm::parseProgram(programFile); program.checkValidity(); - std::vector> formulas = storm::parseFormulasForProgram(formulaAsString, program); + std::vector> formulas = storm::parseFormulasForProgram(formulaAsString, program); ASSERT_TRUE(formulas.size()==1); // Parametric model typename storm::builder::ExplicitPrismModelBuilder::Options options = storm::builder::ExplicitPrismModelBuilder::Options(*formulas[0]); @@ -148,7 +148,7 @@ TEST(ModelInstantiatorTest, Brp_Rew) { // Program and formula storm::prism::Program program = storm::parseProgram(programFile); program.checkValidity(); - std::vector> formulas = storm::parseFormulasForProgram(formulaAsString, program); + std::vector> formulas = storm::parseFormulasForProgram(formulaAsString, program); ASSERT_TRUE(formulas.size()==1); // Parametric model typename storm::builder::ExplicitPrismModelBuilder::Options options = storm::builder::ExplicitPrismModelBuilder::Options(*formulas[0]); @@ -221,7 +221,7 @@ TEST(ModelInstantiatorTest, Consensus) { // Program and formula storm::prism::Program program = storm::parseProgram(programFile); program.checkValidity(); - std::vector> formulas = storm::parseFormulasForProgram(formulaAsString, program); + std::vector> formulas = storm::parseFormulasForProgram(formulaAsString, program); ASSERT_TRUE(formulas.size()==1); // Parametric model typename storm::builder::ExplicitPrismModelBuilder::Options options = storm::builder::ExplicitPrismModelBuilder::Options(*formulas[0]); @@ -262,4 +262,4 @@ TEST(ModelInstantiatorTest, Consensus) { EXPECT_NEAR(0.3526577219, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision()); } -#endif \ No newline at end of file +#endif diff --git a/test/performance/modelchecker/GmmxxDtmcPrctModelCheckerTest.cpp b/test/performance/modelchecker/GmmxxDtmcPrctModelCheckerTest.cpp index 4284ab85c..21b2ac15e 100644 --- a/test/performance/modelchecker/GmmxxDtmcPrctModelCheckerTest.cpp +++ b/test/performance/modelchecker/GmmxxDtmcPrctModelCheckerTest.cpp @@ -26,7 +26,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Crowds) { // A parser that we use for conveniently constructing the formulas. storm::parser::FormulaParser formulaParser; - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -64,7 +64,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, SynchronousLeader) { // A parser that we use for conveniently constructing the formulas. storm::parser::FormulaParser formulaParser; - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); diff --git a/test/performance/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/test/performance/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp index daf041ec7..63832e20a 100644 --- a/test/performance/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp +++ b/test/performance/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp @@ -26,7 +26,7 @@ TEST(GmxxMdpPrctlModelCheckerTest, AsynchronousLeader) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -84,7 +84,7 @@ TEST(GmxxMdpPrctlModelCheckerTest, Consensus) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Gmmxx))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"finished\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"finished\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); diff --git a/test/performance/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp b/test/performance/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp index 85d6399c9..74b244f5b 100644 --- a/test/performance/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp +++ b/test/performance/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp @@ -26,7 +26,7 @@ TEST(NativeDtmcPrctlModelCheckerTest, Crowds) { // A parser that we use for conveniently constructing the formulas. storm::parser::FormulaParser formulaParser; - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -64,7 +64,7 @@ TEST(NativeDtmcPrctlModelCheckerTest, SynchronousLeader) { // A parser that we use for conveniently constructing the formulas. storm::parser::FormulaParser formulaParser; - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); diff --git a/test/performance/modelchecker/NativeMdpPrctlModelCheckerTest.cpp b/test/performance/modelchecker/NativeMdpPrctlModelCheckerTest.cpp index f55a45d07..5c3886631 100644 --- a/test/performance/modelchecker/NativeMdpPrctlModelCheckerTest.cpp +++ b/test/performance/modelchecker/NativeMdpPrctlModelCheckerTest.cpp @@ -27,7 +27,7 @@ TEST(SparseMdpPrctlModelCheckerTest, AsynchronousLeader) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); @@ -85,7 +85,7 @@ TEST(SparseMdpPrctlModelCheckerTest, Consensus) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Native))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"finished\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"finished\"]"); std::unique_ptr result = checker.check(*formula); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeResult1 = result->asExplicitQuantitativeCheckResult(); diff --git a/test/performance/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp b/test/performance/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp index b9f90f3b8..fc96aeaf3 100644 --- a/test/performance/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp +++ b/test/performance/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp @@ -41,7 +41,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, SynchronousLeader_Cudd) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -93,7 +93,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, SynchronousLeader_Sylvan) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -137,7 +137,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Crowds_Cudd) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -181,7 +181,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Crowds_Sylvan) { storm::modelchecker::SymbolicDtmcPrctlModelChecker checker(*dtmc, std::unique_ptr>(new storm::utility::solver::SymbolicLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"observe0Greater1\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -207,4 +207,4 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Crowds_Sylvan) { EXPECT_NEAR(0.23773283919051694, quantitativeResult3.getMin(), storm::settings::nativeEquationSolverSettings().getPrecision()); EXPECT_NEAR(0.23773283919051694, quantitativeResult3.getMax(), storm::settings::nativeEquationSolverSettings().getPrecision()); -} \ No newline at end of file +} diff --git a/test/performance/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp b/test/performance/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp index fec7389c9..ad424a8f9 100644 --- a/test/performance/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp +++ b/test/performance/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp @@ -41,7 +41,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, AsynchronousLeader_Cudd) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -93,7 +93,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, AsynchronousLeader_Sylvan) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -149,7 +149,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, CSMA_Cudd) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [ !\"collision_max_backoff\" U \"all_delivered\" ]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [ !\"collision_max_backoff\" U \"all_delivered\" ]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -206,7 +206,7 @@ TEST(SymbolicMdpPrctlModelCheckerTest, CSMA_Sylvan) { storm::modelchecker::SymbolicMdpPrctlModelChecker checker(*mdp, std::unique_ptr>(new storm::utility::solver::SymbolicMinMaxLinearEquationSolverFactory())); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [ !\"collision_max_backoff\" U \"all_delivered\" ]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [ !\"collision_max_backoff\" U \"all_delivered\" ]"); std::unique_ptr result = checker.check(*formula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(model->getReachableStates(), model->getInitialStates())); @@ -234,4 +234,4 @@ TEST(SymbolicMdpPrctlModelCheckerTest, CSMA_Sylvan) { // FIXME: not optimal precision. EXPECT_NEAR(93.624117712294478, quantitativeResult5.getMin(), 100 * storm::settings::nativeEquationSolverSettings().getPrecision()); EXPECT_NEAR(93.624117712294478, quantitativeResult5.getMax(), 100 * storm::settings::nativeEquationSolverSettings().getPrecision()); -} \ No newline at end of file +} diff --git a/test/performance/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp b/test/performance/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp index 578e04f42..fa921b479 100644 --- a/test/performance/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp +++ b/test/performance/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp @@ -22,7 +22,7 @@ TEST(DISABLED_TopologicalValueIterationMdpPrctlModelCheckerTest, AsynchronousLea storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Topological))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"elected\"]"); std::unique_ptr result = checker.check(*formula); @@ -69,7 +69,7 @@ TEST(DISABLED_TopologicalValueIterationMdpPrctlModelCheckerTest, Consensus) { storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::unique_ptr>(new storm::utility::solver::MinMaxLinearEquationSolverFactory(storm::solver::EquationSolverTypeSelection::Topological))); - std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"finished\"]"); + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"finished\"]"); std::unique_ptr result = checker.check(*formula); @@ -109,4 +109,4 @@ TEST(DISABLED_TopologicalValueIterationMdpPrctlModelCheckerTest, Consensus) { result = checker.check(*formula); ASSERT_NEAR(2183.142422, result->asExplicitQuantitativeCheckResult()[31168], storm::settings::topologicalValueIterationEquationSolverSettings().getPrecision()); -} \ No newline at end of file +}