Exemple #1
0
void declareDecomposition(const Decomposition& decomposition, std::ostream& out)
{
	out << "% Decomposition facts" << std::endl;
	out << "currentNode(" << decomposition.getNode().getGlobalId() << ")." << std::endl;
	for(const auto& v : decomposition.getNode().getBag()) {
		out << "bag(" << decomposition.getNode().getGlobalId() << ',' << v << "). ";
		out << "current(" << v << ")." << std::endl;
	}

	out << "#const numChildNodes=" << decomposition.getChildren().size() << '.' << std::endl;
	if(decomposition.getChildren().empty())
		out << "initial." << std::endl;
	else {
		for(const auto& child : decomposition.getChildren()) {
			out << "childNode(" << child->getNode().getGlobalId() << ")." << std::endl;
			for(const auto& v : child->getNode().getBag()) {
				out << "bag(" << child->getNode().getGlobalId() << ',' << v << "). ";
				out << "-introduced(" << v << ")." << std::endl; // Redundant
			}
		}
	}

	if(decomposition.isRoot())
		out << "final." << std::endl;

	if(decomposition.isPostJoinNode())
		out << "postJoin." << std::endl;

	// Redundant predicates for convenience...
	out << "introduced(X) :- current(X), not -introduced(X)." << std::endl;
	out << "removed(X) :- childNode(N), bag(N,X), not current(X)." << std::endl;
}
void DebugMachineReadable::solverInvocationResult(const Decomposition& decompositionNode, const ItemTree* result)
{
	const auto id = decompositionNode.getNode().getGlobalId();
	if(result) {
		std::cout << "% Facts describing the resulting item tree at node " << id << std::endl;
		std::ostringstream rootItemSetName;
		rootItemSetName << 'n' << id;
		solver::asp::Solver::declareItemTree(std::cout, result, false, id, rootItemSetName.str());
		std::cout << std::endl;

		std::cout << "% Memory locations of the item tree nodes at decomposition node " << id << " (not passed to ASP)" << std::endl;
		declareItemTreeNodeMemoryAddresses(std::cout, result, rootItemSetName.str());
		std::cout << std::endl;

		std::cout << "% Extension pointers at decomposition node " << id << " (not passed to ASP)" << std::endl;
		declareExtensionPointers(std::cout, result, rootItemSetName.str());
		std::cout << std::endl;

		std::cout << "% (Derived) costs of non-leaf nodes of the item tree at decomposition node " << id << " (not passed to ASP)" << std::endl;
		declareDerivedCosts(std::cout, result, rootItemSetName.str());
		std::cout << std::endl;
	}
	else
		std::cout << "% Item tree of node " << id << " is empty." << std::endl;
}
Exemple #3
0
LeafSolver::LeafSolver(const Decomposition& decomposition, const Application& app)
	: ::Solver(decomposition, app)
{
	if(decomposition.getNode().getBag().empty() == false)
		throw std::runtime_error("ASP solver requires empty leaves");
}
Exemple #4
0
Solver::Solver(const Decomposition& decomposition, const Application& app, const std::vector<std::string>& encodingFiles, bool reground, BranchAndBoundLevel bbLevel)
	: ::LazySolver(decomposition, app, bbLevel)
	, reground(reground)
	, encodingFiles(encodingFiles)
{
	Gringo::message_printer()->disable(Gringo::W_ATOM_UNDEFINED);

	if(!reground) {
		// Set up ASP solver
		config.solve.numModels = 0;
		Clasp::Asp::LogicProgram& claspProgramBuilder = static_cast<Clasp::Asp::LogicProgram&>(clasp.startAsp(config, true)); // TODO In leaves updates might not be necessary.

		struct LazyGringoOutputProcessor : GringoOutputProcessor
		{
			LazyGringoOutputProcessor(Solver* s, Clasp::Asp::LogicProgram& prg)
				: GringoOutputProcessor(prg), self(s)
			{
			}

			void storeAtom(unsigned int atomUid, Gringo::Value v) override
			{
				const std::string& n = *v.name();
				if(n == "childItem") {
					ASP_CHECK(v.args().size() == 1, "'childItem' predicate does not have arity 1");
					std::ostringstream argument;
					v.args().front().print(argument);
					self->itemsToLitIndices.emplace(String(argument.str()), self->literals.size());
					self->literals.push_back(Clasp::posLit(atomUid));
				}
				else if(n == "childAuxItem") {
					ASP_CHECK(v.args().size() == 1, "'childAuxItem' predicate does not have arity 1");
					std::ostringstream argument;
					v.args().front().print(argument);
					self->auxItemsToLitIndices.emplace(String(argument.str()), self->literals.size());
					self->literals.push_back(Clasp::posLit(atomUid));
				}
				GringoOutputProcessor::storeAtom(atomUid, v);
			}

			Solver* self;
		} gringoOutput(this, claspProgramBuilder);

		std::unique_ptr<Gringo::Output::OutputBase> out(new Gringo::Output::OutputBase({}, gringoOutput));
		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);

		// 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());

		// 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();

		// Set value of external atoms to free
		for(const auto& p : literals)
			claspProgramBuilder.freeze(p.var(), Clasp::value_free);

		// Finalize ground program and create solver literals
		claspProgramBuilder.endProgram();

		// Map externals to their solver literals
		for(auto& p : literals) {
			p = claspProgramBuilder.getLiteral(p.var());
			assert(!p.watched()); // Literal must not be watched
		}

		for(const auto& atom : gringoOutput.getItemAtomInfos())
			itemAtomInfos.emplace_back(ItemAtomInfo(atom, claspProgramBuilder));
		for(const auto& atom : gringoOutput.getAuxItemAtomInfos())
			auxItemAtomInfos.emplace_back(AuxItemAtomInfo(atom, claspProgramBuilder));
//		for(const auto& atom : gringoOutput->getCurrentCostAtomInfos())
//			currentCostAtomInfos.emplace_back(CurrentCostAtomInfo(atom, claspProgramBuilder));
//		for(const auto& atom : gringoOutput->getCostAtomInfos())
//			costAtomInfos.emplace_back(CostAtomInfo(atom, claspProgramBuilder)));

		// Prepare for solving.
		clasp.prepare();
	}
}
Exemple #5
0
void Solver::startSolvingForCurrentRowCombination()
{
//	++solverSetups;
	asyncResult.reset();

	if(reground) {
		// Set up ASP solver
		config.solve.numModels = 0;
		// TODO The last parameter of clasp.startAsp in the next line is "allowUpdate". Does setting it to false have benefits?
		// WORKAROUND for BUG in ClaspFacade::startAsp()
		// TODO remove on update to new version
		if(clasp.ctx.numVars() == 0 && clasp.ctx.frozen())
			clasp.ctx.reset();

		Clasp::Asp::LogicProgram& claspProgramBuilder = static_cast<Clasp::Asp::LogicProgram&>(clasp.startAsp(config));
		GringoOutputProcessor gringoOutput(claspProgramBuilder);
		std::unique_ptr<Gringo::Output::OutputBase> out(new Gringo::Output::OutputBase({}, gringoOutput));
		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);

		// 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());

		// Input: Child rows
		std::unique_ptr<std::stringstream> childRowsInput(new std::stringstream);
		*childRowsInput << "% Child row facts" << std::endl;
		for(const auto& row : getCurrentRowCombination()) {
			for(const auto& item : row->getItems())
				*childRowsInput << "childItem(" << item << ")." << std::endl;
			for(const auto& item : row->getAuxItems())
				*childRowsInput << "childAuxItem(" << item << ")." << std::endl;
			// TODO costs, etc.
		}
		app.getPrinter().solverInvocationInput(decomposition, childRowsInput->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.pushStream("<child_rows>", std::move(childRowsInput));
		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();

		claspProgramBuilder.endProgram();

		itemAtomInfos.clear();
		for(const auto& atom : gringoOutput.getItemAtomInfos())
			itemAtomInfos.emplace_back(ItemAtomInfo(atom, claspProgramBuilder));
		auxItemAtomInfos.clear();
		for(const auto& atom : gringoOutput.getAuxItemAtomInfos())
			auxItemAtomInfos.emplace_back(AuxItemAtomInfo(atom, claspProgramBuilder));
		// TODO costs etc.

		clasp.prepare();
	}

	else {
		// Set external variables to the values of the current child row combination
		clasp.update(false, false);

		clasp.prepare();

		// Mark atoms corresponding to items from the currently extended rows
		for(const auto& row : getCurrentRowCombination()) {
			for(const auto& item : row->getItems()) {
				assert(itemsToLitIndices.find(item) != itemsToLitIndices.end());
				assert(itemsToLitIndices.at(item) < literals.size());
#ifdef DISABLE_CHECKS
				literals[itemsToLitIndices.at(item)].watch();
#else
				try {
					literals[itemsToLitIndices.at(item)].watch();
				}
				catch(const std::out_of_range&) {
					std::ostringstream msg;
					msg << "Unknown variable; atom childItem(" << *item << ") not shown or not declared as external?";
					throw std::runtime_error(msg.str());
				}
#endif
			}
			for(const auto& item : row->getAuxItems()) {
				assert(auxItemsToLitIndices.find(item) != auxItemsToLitIndices.end());
				assert(auxItemsToLitIndices.at(item) < literals.size());
#ifdef DISABLE_CHECKS
				literals[auxItemsToLitIndices.at(item)].watch();
#else
				try {
					literals[auxItemsToLitIndices.at(item)].watch();
				}
				catch(const std::out_of_range&) {
					std::ostringstream msg;
					msg << "Unknown variable; atom childAuxItem(" << *item << ") not shown or not declared as external?";
					throw std::runtime_error(msg.str());
				}
#endif
			}
		}
		// Set marked literals to true and all others to false
		for(auto& lit : literals) {
			if(lit.watched()) {
				lit.clearWatch();
				clasp.assume(lit);
			}
			else
				clasp.assume(~lit);
		}
	}

	asyncResult.reset(new BasicSolveIter(clasp));
}
void DebugMachineReadable::solverInvocationInput(const Decomposition& decompositionNode, const std::string& input)
{
	std::cout << "% Input for solver at decomposition node " << decompositionNode.getNode().getGlobalId() << std::endl << input << std::endl;
}