void example2() { // Aggregates configuration options. // Using config, you can control many parts of the search, e.g. // - the amount and kind of preprocessing // - the enumerator to use and the number of models to compute // - the heuristic used for decision making // - the restart strategy // - ... Clasp::ClaspConfig config; // We want to compute all models but // otherwise we use the default configuration. config.enumerate.numModels = 0; // The "interface" to the clasp library. Clasp::ClaspFacade libclasp; // LogicProgram provides the interface for defining logic programs. // The returned object is already setup and ready to use. // See logic_program.h for details. Clasp::Asp::LogicProgram& asp = libclasp.startAsp(config); asp.setAtomName(1, "a"); asp.setAtomName(2, "b"); asp.startRule(Clasp::Asp::BASICRULE).addHead(1).addToBody(2, false).endRule(); asp.startRule(Clasp::Asp::BASICRULE).addHead(2).addToBody(1, false).endRule(); // We are done with problem setup. // Prepare the problem for solving. libclasp.prepare(); // Start the actual solving process. ModelPrinter printer; libclasp.solve(&printer); std::cout << "No more models!" << std::endl; }
void Solver::aspCallsOnNewRowFromChild(ItemTree::Children::const_iterator newRow, const DecompositionPtr& originatingChild, Clasp::ClaspFacade& clasp) { std::vector<std::pair<Decomposition*, ItemTree::Children::const_iterator>> rowIterators; // Key: Child node; Value: Row in the item tree at this child rowIterators.reserve(decomposition.getChildren().size()); // At index 0 we will store newRow. This iterator will not be incremented. rowIterators.emplace_back(originatingChild.get(), newRow); for(const auto& child : decomposition.getChildren()) { if(child != originatingChild) { rowIterators.emplace_back(child.get(), dynamic_cast<Solver&>(child->getSolver()).getItemTreeSoFar()->getChildren().begin()); assert(rowIterators.back().second != dynamic_cast<Solver&>(child->getSolver()).getItemTreeSoFar()->getChildren().end()); } } do { ItemTreeNode::ExtensionPointerTuple extendedRows; for(const auto& nodeAndRow : rowIterators) extendedRows.emplace(nodeAndRow.first->getNode().getGlobalId(), (*nodeAndRow.second)->getNode()); claspCallback->setExtendedRows(std::move(extendedRows)); { Clasp::Asp::LogicProgram& prg = static_cast<Clasp::Asp::LogicProgram&>(clasp.update()); for(const auto& nodeAndRow : rowIterators) { for(const auto& item : (*nodeAndRow.second)->getNode()->getItems()) { // std::cout << "W " << std::this_thread::get_id() << " [" << decomposition.getNode().getGlobalId() << "]: Setting " << item << " to true\n"; prg.freeze(itemsToVars.at(item), Clasp::value_true); } } } clasp.prepare(); claspCallback->prepare(clasp.ctx.symbolTable()); clasp.solve(claspCallback.get()); { // XXX Necessary to update so often? Is the overhead bad? Clasp::Asp::LogicProgram& prg = static_cast<Clasp::Asp::LogicProgram&>(clasp.update()); for(const auto& nodeAndRow : rowIterators) { for(const auto& item : (*nodeAndRow.second)->getNode()->getItems()) { // std::cout << "W " << std::this_thread::get_id() << " [" << decomposition.getNode().getGlobalId() << "]: Setting " << item << " to false\n"; prg.freeze(itemsToVars.at(item), Clasp::value_false); } } } } while(nextRowCombination(rowIterators)); }
void example4() { Clasp::ClaspConfig config; config.solve.enumMode = Clasp::EnumOptions::enum_user; config.solve.numModels = 0; // The "interface" to the clasp library. Clasp::ClaspFacade libclasp; Clasp::Asp::LogicProgram& asp = libclasp.startAsp(config); asp.setAtomName(1, "a"); asp.setAtomName(2, "b"); asp.startRule(Clasp::Asp::BASICRULE).addHead(1).addToBody(2, false).endRule(); asp.startRule(Clasp::Asp::BASICRULE).addHead(2).addToBody(1, false).endRule(); libclasp.prepare(); // Start the actual solving process. ModelHandler handler; libclasp.solve(&handler); std::cout << "No more models!" << std::endl; }
void ClaspConApp::run(Clasp::ClaspFacade& clasp) { clasp.start(claspConfig_, getStream()); if (!clasp.incremental()) { claspConfig_.releaseOptions(); } if (claspAppOpts_.compute && clasp.program()->type() == Clasp::Problem_t::Asp) { bool val = claspAppOpts_.compute < 0; Clasp::Var var = static_cast<Clasp::Var>(!val ? claspAppOpts_.compute : -claspAppOpts_.compute); static_cast<Clasp::Asp::LogicProgram*>(clasp.program())->startRule().addToBody(var, val).endRule(); } auto* lp = static_cast<Clasp::Asp::LogicProgram*>(clasp.program()); auto& td = lp->theoryData(); MySharedContext s(clasp.ctx); order::Normalizer n(s,conf_); clingcon::TheoryParser tp(n,td,lp,s.trueLit()); TheoryOutput to; /// only valid for this method, but i do have pointer to it in Configurator, is this ok ? Configurator conf(conf_,n,to); claspConfig_.addConfigurator(&conf); while (clasp.read()) { if (handlePostGroundOptions(*clasp.program())) { if (lp->end() && clasp.ctx.master()->propagate()) { bool conflict = false; for (auto i = td.currBegin(); i != td.end(); ++i) { if (!tp.readConstraint(i)) throw std::runtime_error("Unknown theory atom detected, cowardly refusing to continue"); } to.names_ = std::move(tp.postProcess()); clasp.ctx.output.theory = &to; for (unsigned int level = 0; level < tp.minimize().size(); ++level) for (auto i : tp.minimize()[level]) n.addMinimize(i.second,level); if (!n.prepare()) conflict = true; else { n.checkDomains(); // may throw! if domain was not restricted s.createNewLiterals(n.estimateVariables()); if (!n.createClauses()) conflict = true; } if (conflict && !clasp.ctx.master()->hasConflict()) clasp.ctx.master()->force(Clasp::Literal(0,true)); }/// else, program is conflicting clasp.prepare(); // // // i can not update the program if it is not incremental // do i have to make my program incremental for this ? // while estimating the number of variables i have to create // a stack of new variables all the time, probably updating clasp over and over ... //clasp.update(); // //Maybe call prepare before, then update, then normalizer stuff, then prepare again // theory atoms already seem to be frozen // clasp.prepare(); if (handlePreSolveOptions(clasp)) { clasp.solve(); } } } }
void Solver::workerThreadMain() { std::unique_lock<std::mutex> lock(workerMutex); // Set up ASP solver Clasp::ClaspFacade clasp; Clasp::ClaspConfig config; config.solve.numModels = 0; Clasp::Asp::LogicProgram& claspProgramBuilder = dynamic_cast<Clasp::Asp::LogicProgram&>(clasp.startAsp(config, true)); std::unique_ptr<Gringo::Output::LparseOutputter> lpOut(new GringoOutputProcessor(claspProgramBuilder)); claspCallback.reset(new ClaspCallback(dynamic_cast<GringoOutputProcessor&>(*lpOut), app, *this, lock)); std::unique_ptr<Gringo::Output::OutputBase> out(new Gringo::Output::OutputBase({}, *lpOut)); Gringo::Input::Program program; Gringo::Scripts scripts; Gringo::Defines defs; Gringo::Input::NongroundProgramBuilder gringoProgramBuilder(scripts, program, *out, defs); Gringo::Input::NonGroundParser parser(gringoProgramBuilder); // Input: Original problem instance std::unique_ptr<std::stringstream> instanceInput(new std::stringstream); *instanceInput << app.getInputString(); // Input: Decomposition std::unique_ptr<std::stringstream> decompositionInput(new std::stringstream); solver::asp::Solver::declareDecomposition(decomposition, *decompositionInput); app.getPrinter().solverInvocationInput(decomposition, decompositionInput->str()); // Pass input to ASP solver for(const auto& file : encodingFiles) parser.pushFile(std::string(file)); parser.pushStream("<instance>", std::move(instanceInput)); parser.pushStream("<decomposition>", std::move(decompositionInput)); parser.parse(); // Ground program.rewrite(defs); program.check(); if(Gringo::message_printer()->hasError()) throw std::runtime_error("Grounding stopped because of errors"); auto gPrg = program.toGround(out->domains); Gringo::Ground::Parameters params; params.add("base", {}); gPrg.ground(params, scripts, *out); params.clear(); // Prepare for solving. (This makes clasp's symbol table available.) clasp.prepare(); claspCallback->prepare(clasp.ctx.symbolTable()); // We need to know which clasp variable corresponds to each childItem(_) atom. for(const auto& pair : clasp.ctx.symbolTable()) { if(!pair.second.name.empty()) { const std::string name = pair.second.name.c_str(); if(name.compare(0, 10, "childItem(") == 0) { const std::string argument = name.substr(10, name.length()-11); itemsToVars.emplace(argument, pair.first); } } } // Let main thread finish the constructor wakeMainThreadRequested = true; wakeMainThread.notify_one(); // Wait until we should do work wakeWorkerThread.wait(lock, [&]() { return wakeWorkerThreadRequested; }); wakeWorkerThreadRequested = false; if(decomposition.getChildren().empty()) { // This is a leaf solver. clasp.solve(claspCallback.get()); } else { // Get the first row from each child node std::unordered_map<unsigned int, ItemTree::Children::const_iterator> childRows; childRows.reserve(decomposition.getChildren().size()); for(const auto& child : decomposition.getChildren()) { const ItemTree::Children::const_iterator newRow = dynamic_cast<Solver&>(child->getSolver()).nextRow(); if(newRow == dynamic_cast<Solver&>(child->getSolver()).getItemTreeSoFar()->getChildren().end()) { // Notify main thread that solving is complete noMoreModels = true; wakeMainThreadRequested = true; wakeMainThread.notify_one(); return; } childRows.emplace(child->getNode().getGlobalId(), newRow); } // Let the combination of these rows be the input for our ASP call ItemTreeNode::ExtensionPointerTuple rootExtensionPointers; for(const auto& child : decomposition.getChildren()) rootExtensionPointers.emplace(child->getNode().getGlobalId(), dynamic_cast<Solver&>(child->getSolver()).getItemTreeSoFar()->getNode()); claspCallback->setRootExtensionPointers(std::move(rootExtensionPointers)); ItemTreeNode::ExtensionPointerTuple extendedRows; for(const auto& nodeIdAndRow : childRows) extendedRows.emplace(nodeIdAndRow.first, (*nodeIdAndRow.second)->getNode()); claspCallback->setExtendedRows(std::move(extendedRows)); { Clasp::Asp::LogicProgram& prg = static_cast<Clasp::Asp::LogicProgram&>(clasp.update()); for(const auto& nodeIdAndRow : childRows) { for(const auto& item : (*nodeIdAndRow.second)->getNode()->getItems()) { prg.freeze(itemsToVars.at(item), Clasp::value_true); } } } clasp.prepare(); claspCallback->prepare(clasp.ctx.symbolTable()); clasp.solve(claspCallback.get()); { // XXX Necessary to update so often? Is the overhead bad? Clasp::Asp::LogicProgram& prg = static_cast<Clasp::Asp::LogicProgram&>(clasp.update()); for(const auto& nodeIdAndRow : childRows) { for(const auto& item : (*nodeIdAndRow.second)->getNode()->getItems()) { prg.freeze(itemsToVars.at(item), Clasp::value_false); } } } // Now there are no models anymore for this row combination // Until there are no new rows anymore, generate one new row at some child node and combine it with all rows from other child nodes bool foundNewRow; do { foundNewRow = false; for(const auto& child : decomposition.getChildren()) { ItemTree::Children::const_iterator newRow = dynamic_cast<Solver&>(child->getSolver()).nextRow(); if(newRow != dynamic_cast<Solver&>(child->getSolver()).getItemTreeSoFar()->getChildren().end()) { foundNewRow = true; aspCallsOnNewRowFromChild(newRow, child, clasp); } } } while(foundNewRow); } // Notify main thread that solving is complete noMoreModels = true; wakeMainThreadRequested = true; wakeMainThread.notify_one(); }
ItemTreePtr Solver::compute() { const auto nodeStackElement = app.getPrinter().visitNode(decomposition); // Compute item trees of child nodes ChildItemTrees childItemTrees; for(const auto& child : decomposition.getChildren()) { ItemTreePtr itree = child->getSolver().compute(); if(!itree) return itree; childItemTrees.emplace(child->getNode().getGlobalId(), std::move(itree)); } // Input: Child item trees std::unique_ptr<std::stringstream> childItemTreesInput(new std::stringstream); *childItemTreesInput << "% Child item tree facts" << std::endl; for(const auto& childItemTree : childItemTrees) { std::ostringstream rootItemSetName; rootItemSetName << 'n' << childItemTree.first; asp_utils::declareItemTree(*childItemTreesInput, childItemTree.second.get(), tableMode, childItemTree.first, rootItemSetName.str()); } app.getPrinter().solverInvocationInput(decomposition, childItemTreesInput->str()); // Input: Induced subinstance std::unique_ptr<std::stringstream> instanceInput(new std::stringstream); asp_utils::induceSubinstance(*instanceInput, app.getInstance(), decomposition.getNode().getBag()); app.getPrinter().solverInvocationInput(decomposition, instanceInput->str()); // Input: Decomposition std::unique_ptr<std::stringstream> decompositionInput(new std::stringstream); asp_utils::declareDecomposition(decomposition, *decompositionInput); app.getPrinter().solverInvocationInput(decomposition, decompositionInput->str()); // Set up ASP solver Clasp::ClaspConfig config; config.solve.numModels = 0; Clasp::ClaspFacade clasp; // TODO The last parameter of clasp.startAsp in the next line is "allowUpdate". Does setting it to false have benefits? Clasp::Asp::LogicProgram& claspProgramBuilder = dynamic_cast<Clasp::Asp::LogicProgram&>(clasp.startAsp(config)); std::unique_ptr<Gringo::Output::LparseOutputter> lpOut(newGringoOutputProcessor(claspProgramBuilder, childItemTrees, tableMode)); std::unique_ptr<Gringo::Output::OutputBase> out(new Gringo::Output::OutputBase({}, *lpOut)); Gringo::Input::Program program; asp_utils::DummyGringoModule module; Gringo::Scripts scripts(module); Gringo::Defines defs; Gringo::Input::NongroundProgramBuilder gringoProgramBuilder(scripts, program, *out, defs); Gringo::Input::NonGroundParser parser(gringoProgramBuilder); // Pass input to ASP solver for(const auto& file : encodingFiles) parser.pushFile(std::string(file)); parser.pushStream("<instance>", std::move(instanceInput)); parser.pushStream("<decomposition>", std::move(decompositionInput)); parser.pushStream("<child_itrees>", std::move(childItemTreesInput)); parser.parse(); // Ground and solve program.rewrite(defs); program.check(); if(Gringo::message_printer()->hasError()) throw std::runtime_error("Grounding stopped because of errors"); auto gPrg = program.toGround(out->domains); Gringo::Ground::Parameters params; params.add("base", {}); gPrg.ground(params, scripts, *out); params.clear(); // Finalize ground program and create solver variables claspProgramBuilder.endProgram(); std::unique_ptr<asp_utils::ClaspCallback> cb(newClaspCallback(tableMode, *lpOut, childItemTrees, app, decomposition.isRoot(), decomposition, cardinalityCost)); cb->prepare(claspProgramBuilder); clasp.prepare(); clasp.solve(cb.get()); if(printStatistics) { std::cout << "Solver statistics for decomposition node " << decomposition.getNode().getGlobalId() << ':' << std::endl; Clasp::Cli::TextOutput{true, Clasp::Cli::TextOutput::format_asp}.printStatistics(clasp.summary(), true); } ItemTreePtr result = cb->finalize(decomposition.isRoot(), app.isPruningDisabled() == false || decomposition.isRoot()); app.getPrinter().solverInvocationResult(decomposition, result.get()); return result; }