Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #4
0
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(); }
        }
    }
}
Beispiel #5
0
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();
}
Beispiel #6
0
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;
}