<commit_before>#include <plasp/pddl/TranslatorASP.h>

#include <boost/assert.hpp>

#include <plasp/pddl/expressions/And.h>
#include <plasp/pddl/expressions/Not.h>
#include <plasp/pddl/expressions/Predicate.h>
#include <plasp/utils/Formatting.h>
#include <plasp/utils/IO.h>
#include <plasp/utils/TranslatorException.h>

namespace plasp
{
namespace pddl
{

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TranslatorASP
//
////////////////////////////////////////////////////////////////////////////////////////////////////

TranslatorASP::TranslatorASP(const Description &description, utils::LogStream &outputStream)
:	m_description(description),
	m_outputStream(outputStream)
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translate() const
{
	translateDomain();

	if (m_description.containsProblem())
	{
		m_outputStream << std::endl;
		translateProblem();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateDomain() const
{
	m_outputStream << utils::Heading1("domain");

	const auto &domain = m_description.domain();

	// Types
	m_outputStream << std::endl;
	translateTypes();

	// Constants
	if (!domain.constants().empty())
	{
		m_outputStream << std::endl;
		translateConstants("constants", domain.constants());
	}

	// Predicates
	if (!domain.predicates().empty())
	{
		m_outputStream << std::endl;
		translatePredicates();
	}

	// Actions
	if (!domain.actions().empty())
	{
		m_outputStream << std::endl;
		translateActions();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateTypes() const
{
	m_outputStream << utils::Heading2("types");

	m_outputStream << std::endl;

	const auto &types = m_description.domain().types();

	if (types.empty())
	{
		m_outputStream
			<< utils::Keyword("type") << "("
			<< utils::Keyword("type") << "(object))." << std::endl;

		return;
	}

	std::for_each(types.cbegin(), types.cend(),
		[&](const auto &type)
		{
			const auto typeName = utils::escapeASP(type->name());

			m_outputStream
				<< utils::Keyword("type") << "("
				<< utils::Keyword("type") << "("
				<< typeName << "))." << std::endl;

			const auto &parentTypes = type->parentTypes();

			std::for_each(parentTypes.cbegin(), parentTypes.cend(),
				[&](const auto &parentType)
				{
					const auto parentTypeName = utils::escapeASP(parentType->name());

					m_outputStream
						<< utils::Keyword("inherits") << "(" << utils::Keyword("type")
						<< "(" << typeName << "), " << utils::Keyword("type")
						<< "(" << parentTypeName << "))." << std::endl

						<< utils::Keyword("has") << "(" << utils::Variable("X") << ", "
						<< utils::Keyword("type") << "(" << parentTypeName << ")) :- "
						<< utils::Keyword("has") << "(" << utils::Variable("X") << ", "
						<< utils::Keyword("type") << "(" << typeName << "))." << std::endl;
				});
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translatePredicates() const
{
	m_outputStream << utils::Heading2("predicates");

	const auto &predicates = m_description.domain().predicates();

	std::for_each(predicates.cbegin(), predicates.cend(),
		[&](const auto &predicate)
		{
			m_outputStream << std::endl;

			m_outputStream << utils::Keyword("predicate") << "(" << utils::escapeASP(predicate->name());

			this->translateVariablesHead(predicate->arguments());

			m_outputStream << ")";

			this->translateVariablesBody(predicate->arguments());

			m_outputStream << ".";
		});

	m_outputStream << std::endl;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateActions() const
{
	m_outputStream << utils::Heading2("actions");

	const auto &actions = m_description.domain().actions();

	const auto printActionName =
		[&](const auto &action)
		{
			m_outputStream << utils::Keyword("action") << "(" << utils::escapeASP(action.name());

			this->translateVariablesHead(action.parameters());

			m_outputStream << ")";
		};

	std::for_each(actions.cbegin(), actions.cend(),
		[&](const auto &action)
		{
			const auto translateLiteral =
				[&](const auto &ruleHead, const auto &literal)
				{
					m_outputStream << std::endl << utils::Keyword(ruleHead) << "(";

					printActionName(*action);

					m_outputStream << ", ";

					this->translateLiteral(literal);

					m_outputStream << ") :- ";

					printActionName(*action);

					m_outputStream << ".";
				};

			m_outputStream << std::endl;

			// Name
			printActionName(*action);

			this->translateVariablesBody(action->parameters());

			m_outputStream << ".";

			// Precondition
			if (action->precondition())
			{
				const auto &precondition = *action->precondition();

				if (precondition.expressionType() == Expression::Type::Predicate
					|| precondition.expressionType() == Expression::Type::Not)
				{
					translateLiteral("precondition", precondition);
				}
				// Assuming a conjunction
				else
				{
					if (precondition.expressionType() != Expression::Type::And)
						throw utils::TranslatorException("only “and” expressions and (negated) predicates supported as action preconditions currently");

					const auto &andExpression = dynamic_cast<const expressions::And &>(precondition);

					std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
						[&](const auto *argument)
						{
							translateLiteral("precondition", *argument);
						});
				}
			}

			// Effect
			if (action->effect())
			{
				const auto &effect = *action->effect();

				if (effect.expressionType() == Expression::Type::Predicate
					|| effect.expressionType() == Expression::Type::Not)
				{
					translateLiteral("postcondition", effect);
				}
				// Assuming a conjunction
				else
				{
					if (effect.expressionType() != Expression::Type::And)
						throw utils::TranslatorException("only “and” expressions and (negated) predicates supported as action effects currently");

					const auto &andExpression = dynamic_cast<const expressions::And &>(effect);

					std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
						[&](const auto *argument)
						{
							translateLiteral("postcondition", *argument);
						});
				}
			}

			m_outputStream << std::endl;
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateConstants(const std::string &heading, const expressions::Constants &constants) const
{
	m_outputStream << utils::Heading2(heading);

	std::for_each(constants.cbegin(), constants.cend(),
		[&](const auto &constant)
		{
			const auto constantName = utils::escapeASP(constant->name());

			m_outputStream << std::endl << utils::Keyword("constant")
				<< "(" << constantName << ")." << std::endl;

			const auto *type = constant->type();

			if (type != nullptr)
			{
				m_outputStream << utils::Keyword("has") << "("
					<< utils::Keyword("constant") << "(" << constantName << "), "
					<< utils::Keyword("type") << "(" << utils::escapeASP(type->name()) << "))." << std::endl;
			}
			else
			{
				m_outputStream << utils::Keyword("has") << "("
					<< utils::Keyword("constant") << "(" << constantName << "), "
					<< utils::Keyword("type") << "(object))." << std::endl;
			}
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateVariablesHead(const expressions::Variables &variables) const
{
	if (variables.empty())
		return;

	m_outputStream << "(";

	for (auto i = variables.cbegin(); i != variables.cend(); i++)
	{
		if (i != variables.cbegin())
			m_outputStream << ", ";

		const auto &variable = **i;

		m_outputStream << utils::Variable(utils::escapeASPVariable(variable.name()));
	}

	m_outputStream << ")";
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateVariablesBody(const expressions::Variables &variables) const
{
	if (variables.empty())
		return;

	m_outputStream << " :- ";

	for (auto i = variables.cbegin(); i != variables.cend(); i++)
	{
		const auto &variable = **i;

		if (i != variables.cbegin())
			m_outputStream << ", ";

		if (variable.type() != nullptr)
		{
			if (variable.type()->expressionType() != Expression::Type::PrimitiveType)
				throw utils::TranslatorException("only primitive types supported currently");

			const auto &type = *dynamic_cast<const expressions::PrimitiveType *>(variable.type());

			m_outputStream << utils::Keyword("has") << "("
				<< utils::Variable(utils::escapeASPVariable(variable.name())) << ", "
				<< utils::Keyword("type") << "(" << utils::escapeASP(type.name()) << "))";
		}
		else
		{
			m_outputStream << utils::Keyword("has") << "("
				<< utils::Variable(utils::escapeASPVariable(variable.name())) << ", "
				<< utils::Keyword("type") << "(object))";
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateLiteral(const Expression &literal) const
{
	// Translate single predicate
	if (literal.expressionType() == Expression::Type::Predicate)
	{
		this->translatePredicate(dynamic_cast<const expressions::Predicate &>(literal));
		m_outputStream << ", " << utils::Keyword("true");
	}
	// Assuming that "not" expression may only contain a predicate
	else if (literal.expressionType() == Expression::Type::Not)
	{
		const auto &notExpression = dynamic_cast<const expressions::Not &>(literal);
		const auto &predicate = dynamic_cast<const expressions::Predicate &>(*notExpression.argument());

		this->translatePredicate(predicate);
		m_outputStream << ", " << utils::Keyword("false");
	}
	else
		throw utils::TranslatorException("only primitive predicates and their negations supported as literals currently");
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translatePredicate(const expressions::Predicate &predicate) const
{
	m_outputStream << utils::Keyword("predicate") << "(" << utils::escapeASP(predicate.name());

	const auto &arguments = predicate.arguments();

	if (arguments.empty())
	{
		m_outputStream << ")";
		return;
	}

	m_outputStream << "(";

	for (auto i = arguments.cbegin(); i != arguments.cend(); i++)
	{
		if (i != arguments.cbegin())
			m_outputStream << ", ";

		if ((*i)->expressionType() == Expression::Type::Constant)
		{
			const auto &constant = dynamic_cast<const expressions::Constant &>(**i);

			m_outputStream << utils::Keyword("constant") << "(" << utils::escapeASP(constant.name()) << ")";
		}
		else if ((*i)->expressionType() == Expression::Type::Variable)
		{
			const auto &variable = dynamic_cast<const expressions::Variable &>(**i);

			m_outputStream << utils::Variable(utils::escapeASPVariable(variable.name()));
		}
		else
			throw utils::TranslatorException("only variables and constants supported in predicates currently");
	}

	m_outputStream << "))";
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateProblem() const
{
	BOOST_ASSERT(m_description.containsProblem());

	m_outputStream << utils::Heading1("problem");

	const auto &problem = m_description.problem();

	// Objects
	if (!problem.objects().empty())
	{
		m_outputStream << std::endl;
		translateConstants("objects", problem.objects());
	}

	// Initial State
	m_outputStream << std::endl;
	translateInitialState();

	// Goal
	m_outputStream << std::endl;
	translateGoal();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateInitialState() const
{
	BOOST_ASSERT(m_description.containsProblem());

	m_outputStream << utils::Heading2("initial state");

	const auto &initialStateFacts = m_description.problem().initialState().facts();

	std::for_each(initialStateFacts.cbegin(), initialStateFacts.cend(),
		[&](const auto &fact)
		{
			m_outputStream << std::endl << utils::Keyword("initialState") << "(";

			// Translate single predicate
			if (fact->expressionType() == Expression::Type::Predicate)
				this->translatePredicate(dynamic_cast<const expressions::Predicate &>(*fact));
			// Assuming that "not" expression may only contain a predicate
			else if (fact->expressionType() == Expression::Type::Not)
			{
				const auto &notExpression = dynamic_cast<const expressions::Not &>(*fact);

				if (notExpression.argument()->expressionType() != Expression::Type::Predicate)
					throw utils::TranslatorException("only negations of simple predicates supported in initial state currently");
			}
			else
				throw utils::TranslatorException("only predicates and their negations supported in initial state currently");

			m_outputStream << ").";
		});

	m_outputStream << std::endl;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateGoal() const
{
	BOOST_ASSERT(m_description.containsProblem());

	m_outputStream << utils::Heading2("goal");

	const auto &goal = m_description.problem().goal();

	if (goal.expressionType() == Expression::Type::Predicate
		|| goal.expressionType() == Expression::Type::Not)
	{
		m_outputStream << std::endl << utils::Keyword("goal") << "(";

		translateLiteral(goal);

		m_outputStream << ").";
	}
	else if (goal.expressionType() == Expression::Type::And)
	{
		const auto &andExpression = dynamic_cast<const expressions::And &>(goal);

		std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
			[&](const auto *argument)
			{
				m_outputStream << std::endl << utils::Keyword("goal") << "(";

				this->translateLiteral(*argument);

				m_outputStream << ").";
			});
	}
	else
		throw utils::TranslatorException("only single predicates, their negations, and conjunctions are currently supported in the goal");

	m_outputStream << std::endl;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

}
}
<commit_msg>Started turning translated PDDL predicates into unified variable format.<commit_after>#include <plasp/pddl/TranslatorASP.h>

#include <boost/assert.hpp>

#include <plasp/pddl/expressions/And.h>
#include <plasp/pddl/expressions/Not.h>
#include <plasp/pddl/expressions/Predicate.h>
#include <plasp/utils/Formatting.h>
#include <plasp/utils/IO.h>
#include <plasp/utils/TranslatorException.h>

namespace plasp
{
namespace pddl
{

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TranslatorASP
//
////////////////////////////////////////////////////////////////////////////////////////////////////

TranslatorASP::TranslatorASP(const Description &description, utils::LogStream &outputStream)
:	m_description(description),
	m_outputStream(outputStream)
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translate() const
{
	translateDomain();

	if (m_description.containsProblem())
	{
		m_outputStream << std::endl;
		translateProblem();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateDomain() const
{
	m_outputStream << utils::Heading1("domain");

	const auto &domain = m_description.domain();

	// Types
	m_outputStream << std::endl;
	translateTypes();

	// Constants
	if (!domain.constants().empty())
	{
		m_outputStream << std::endl;
		translateConstants("constants", domain.constants());
	}

	// Predicates
	if (!domain.predicates().empty())
	{
		m_outputStream << std::endl;
		translatePredicates();
	}

	// Actions
	if (!domain.actions().empty())
	{
		m_outputStream << std::endl;
		translateActions();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateTypes() const
{
	m_outputStream << utils::Heading2("types");

	m_outputStream << std::endl;

	const auto &types = m_description.domain().types();

	if (types.empty())
	{
		m_outputStream
			<< utils::Keyword("type") << "("
			<< utils::Keyword("type") << "(object))." << std::endl;

		return;
	}

	std::for_each(types.cbegin(), types.cend(),
		[&](const auto &type)
		{
			const auto typeName = utils::escapeASP(type->name());

			m_outputStream
				<< utils::Keyword("type") << "("
				<< utils::Keyword("type") << "("
				<< typeName << "))." << std::endl;

			const auto &parentTypes = type->parentTypes();

			std::for_each(parentTypes.cbegin(), parentTypes.cend(),
				[&](const auto &parentType)
				{
					const auto parentTypeName = utils::escapeASP(parentType->name());

					m_outputStream
						<< utils::Keyword("inherits") << "(" << utils::Keyword("type")
						<< "(" << typeName << "), " << utils::Keyword("type")
						<< "(" << parentTypeName << "))." << std::endl

						<< utils::Keyword("has") << "(" << utils::Variable("X") << ", "
						<< utils::Keyword("type") << "(" << parentTypeName << ")) :- "
						<< utils::Keyword("has") << "(" << utils::Variable("X") << ", "
						<< utils::Keyword("type") << "(" << typeName << "))." << std::endl;
				});
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translatePredicates() const
{
	m_outputStream << utils::Heading2("predicates");

	const auto &predicates = m_description.domain().predicates();

	const auto printPredicateName =
		[&](const auto &predicate)
		{
			m_outputStream
				<< utils::escapeASP(predicate->name());

			this->translateVariablesHead(predicate->arguments());
		};

	const auto printValueRule =
		[&](const auto &predicate, const auto &value)
		{
			m_outputStream
				<< utils::Keyword("contains") << "("
				<< utils::Keyword("variable") << "(";

			printPredicateName(predicate);

			m_outputStream
				<< "), " << utils::Keyword("value") << "(";

			printPredicateName(predicate);

			m_outputStream << ", " << utils::Keyword(value) << ")";

			this->translateVariablesBody(predicate->arguments());

			m_outputStream << "." << std::endl;
		};

	std::for_each(predicates.cbegin(), predicates.cend(),
		[&](const auto &predicate)
		{
			m_outputStream
				<< std::endl
				<< utils::Keyword("variable") << "("
				<< utils::Keyword("variable") << "(";

			printPredicateName(predicate);

			m_outputStream << "))";

			this->translateVariablesBody(predicate->arguments());

			m_outputStream << "." << std::endl;

			printValueRule(predicate, "true");
			printValueRule(predicate, "false");
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateActions() const
{
	m_outputStream << utils::Heading2("actions");

	const auto &actions = m_description.domain().actions();

	const auto printActionName =
		[&](const auto &action)
		{
			m_outputStream << utils::Keyword("action") << "(" << utils::escapeASP(action.name());

			this->translateVariablesHead(action.parameters());

			m_outputStream << ")";
		};

	std::for_each(actions.cbegin(), actions.cend(),
		[&](const auto &action)
		{
			const auto translateLiteral =
				[&](const auto &ruleHead, const auto &literal)
				{
					m_outputStream << std::endl << utils::Keyword(ruleHead) << "(";

					printActionName(*action);

					m_outputStream << ", ";

					this->translateLiteral(literal);

					m_outputStream << ") :- ";

					printActionName(*action);

					m_outputStream << ".";
				};

			m_outputStream << std::endl;

			// Name
			printActionName(*action);

			this->translateVariablesBody(action->parameters());

			m_outputStream << ".";

			// Precondition
			if (action->precondition())
			{
				const auto &precondition = *action->precondition();

				if (precondition.expressionType() == Expression::Type::Predicate
					|| precondition.expressionType() == Expression::Type::Not)
				{
					translateLiteral("precondition", precondition);
				}
				// Assuming a conjunction
				else
				{
					if (precondition.expressionType() != Expression::Type::And)
						throw utils::TranslatorException("only “and” expressions and (negated) predicates supported as action preconditions currently");

					const auto &andExpression = dynamic_cast<const expressions::And &>(precondition);

					std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
						[&](const auto *argument)
						{
							translateLiteral("precondition", *argument);
						});
				}
			}

			// Effect
			if (action->effect())
			{
				const auto &effect = *action->effect();

				if (effect.expressionType() == Expression::Type::Predicate
					|| effect.expressionType() == Expression::Type::Not)
				{
					translateLiteral("postcondition", effect);
				}
				// Assuming a conjunction
				else
				{
					if (effect.expressionType() != Expression::Type::And)
						throw utils::TranslatorException("only “and” expressions and (negated) predicates supported as action effects currently");

					const auto &andExpression = dynamic_cast<const expressions::And &>(effect);

					std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
						[&](const auto *argument)
						{
							translateLiteral("postcondition", *argument);
						});
				}
			}

			m_outputStream << std::endl;
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateConstants(const std::string &heading, const expressions::Constants &constants) const
{
	m_outputStream << utils::Heading2(heading);

	std::for_each(constants.cbegin(), constants.cend(),
		[&](const auto &constant)
		{
			const auto constantName = utils::escapeASP(constant->name());

			m_outputStream << std::endl << utils::Keyword("constant")
				<< "(" << constantName << ")." << std::endl;

			const auto *type = constant->type();

			if (type != nullptr)
			{
				m_outputStream << utils::Keyword("has") << "("
					<< utils::Keyword("constant") << "(" << constantName << "), "
					<< utils::Keyword("type") << "(" << utils::escapeASP(type->name()) << "))." << std::endl;
			}
			else
			{
				m_outputStream << utils::Keyword("has") << "("
					<< utils::Keyword("constant") << "(" << constantName << "), "
					<< utils::Keyword("type") << "(object))." << std::endl;
			}
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateVariablesHead(const expressions::Variables &variables) const
{
	if (variables.empty())
		return;

	m_outputStream << "(";

	for (auto i = variables.cbegin(); i != variables.cend(); i++)
	{
		if (i != variables.cbegin())
			m_outputStream << ", ";

		const auto &variable = **i;

		m_outputStream << utils::Variable(utils::escapeASPVariable(variable.name()));
	}

	m_outputStream << ")";
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateVariablesBody(const expressions::Variables &variables) const
{
	if (variables.empty())
		return;

	m_outputStream << " :- ";

	for (auto i = variables.cbegin(); i != variables.cend(); i++)
	{
		const auto &variable = **i;

		if (i != variables.cbegin())
			m_outputStream << ", ";

		if (variable.type() != nullptr)
		{
			if (variable.type()->expressionType() != Expression::Type::PrimitiveType)
				throw utils::TranslatorException("only primitive types supported currently");

			const auto &type = *dynamic_cast<const expressions::PrimitiveType *>(variable.type());

			m_outputStream << utils::Keyword("has") << "("
				<< utils::Variable(utils::escapeASPVariable(variable.name())) << ", "
				<< utils::Keyword("type") << "(" << utils::escapeASP(type.name()) << "))";
		}
		else
		{
			m_outputStream << utils::Keyword("has") << "("
				<< utils::Variable(utils::escapeASPVariable(variable.name())) << ", "
				<< utils::Keyword("type") << "(object))";
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateLiteral(const Expression &literal) const
{
	// Translate single predicate
	if (literal.expressionType() == Expression::Type::Predicate)
	{
		this->translatePredicate(dynamic_cast<const expressions::Predicate &>(literal));
		m_outputStream << ", " << utils::Keyword("true");
	}
	// Assuming that "not" expression may only contain a predicate
	else if (literal.expressionType() == Expression::Type::Not)
	{
		const auto &notExpression = dynamic_cast<const expressions::Not &>(literal);
		const auto &predicate = dynamic_cast<const expressions::Predicate &>(*notExpression.argument());

		this->translatePredicate(predicate);
		m_outputStream << ", " << utils::Keyword("false");
	}
	else
		throw utils::TranslatorException("only primitive predicates and their negations supported as literals currently");
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translatePredicate(const expressions::Predicate &predicate) const
{
	m_outputStream << utils::Keyword("predicate") << "(" << utils::escapeASP(predicate.name());

	const auto &arguments = predicate.arguments();

	if (arguments.empty())
	{
		m_outputStream << ")";
		return;
	}

	m_outputStream << "(";

	for (auto i = arguments.cbegin(); i != arguments.cend(); i++)
	{
		if (i != arguments.cbegin())
			m_outputStream << ", ";

		if ((*i)->expressionType() == Expression::Type::Constant)
		{
			const auto &constant = dynamic_cast<const expressions::Constant &>(**i);

			m_outputStream << utils::Keyword("constant") << "(" << utils::escapeASP(constant.name()) << ")";
		}
		else if ((*i)->expressionType() == Expression::Type::Variable)
		{
			const auto &variable = dynamic_cast<const expressions::Variable &>(**i);

			m_outputStream << utils::Variable(utils::escapeASPVariable(variable.name()));
		}
		else
			throw utils::TranslatorException("only variables and constants supported in predicates currently");
	}

	m_outputStream << "))";
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateProblem() const
{
	BOOST_ASSERT(m_description.containsProblem());

	m_outputStream << utils::Heading1("problem");

	const auto &problem = m_description.problem();

	// Objects
	if (!problem.objects().empty())
	{
		m_outputStream << std::endl;
		translateConstants("objects", problem.objects());
	}

	// Initial State
	m_outputStream << std::endl;
	translateInitialState();

	// Goal
	m_outputStream << std::endl;
	translateGoal();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateInitialState() const
{
	BOOST_ASSERT(m_description.containsProblem());

	m_outputStream << utils::Heading2("initial state");

	const auto &initialStateFacts = m_description.problem().initialState().facts();

	std::for_each(initialStateFacts.cbegin(), initialStateFacts.cend(),
		[&](const auto &fact)
		{
			m_outputStream << std::endl << utils::Keyword("initialState") << "(";

			// Translate single predicate
			if (fact->expressionType() == Expression::Type::Predicate)
				this->translatePredicate(dynamic_cast<const expressions::Predicate &>(*fact));
			// Assuming that "not" expression may only contain a predicate
			else if (fact->expressionType() == Expression::Type::Not)
			{
				const auto &notExpression = dynamic_cast<const expressions::Not &>(*fact);

				if (notExpression.argument()->expressionType() != Expression::Type::Predicate)
					throw utils::TranslatorException("only negations of simple predicates supported in initial state currently");
			}
			else
				throw utils::TranslatorException("only predicates and their negations supported in initial state currently");

			m_outputStream << ").";
		});

	m_outputStream << std::endl;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TranslatorASP::translateGoal() const
{
	BOOST_ASSERT(m_description.containsProblem());

	m_outputStream << utils::Heading2("goal");

	const auto &goal = m_description.problem().goal();

	if (goal.expressionType() == Expression::Type::Predicate
		|| goal.expressionType() == Expression::Type::Not)
	{
		m_outputStream << std::endl << utils::Keyword("goal") << "(";

		translateLiteral(goal);

		m_outputStream << ").";
	}
	else if (goal.expressionType() == Expression::Type::And)
	{
		const auto &andExpression = dynamic_cast<const expressions::And &>(goal);

		std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
			[&](const auto *argument)
			{
				m_outputStream << std::endl << utils::Keyword("goal") << "(";

				this->translateLiteral(*argument);

				m_outputStream << ").";
			});
	}
	else
		throw utils::TranslatorException("only single predicates, their negations, and conjunctions are currently supported in the goal");

	m_outputStream << std::endl;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

}
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <map>
#include <stdarg.h> // for va_start/va_end
#include <thread>
#include <mutex>
#include <functional>
#include <iostream>
#include <ostream>
#include <sstream>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <zmq.hpp>
#include "chlog.hpp"

using namespace std;
using namespace ch_frb_io;

namespace ch_frb_io {
#if 0
}; // pacify emacs c-mode
#endif

static string
vstringprintf(const char* format, va_list lst) {
    char temps[256];
    // truncates if length > size of 'temps'
    int n = vsnprintf(temps, sizeof(temps), format, lst);
    if (n < 0)
        throw runtime_error("vstringprintf failed: " + string(strerror(errno)));
    if (n < 256)
        return string(temps);
    // Try again with larger temp buffer
    char* temp2 = new char[n+1];
    n = vsnprintf(temp2, n+1, format, lst);
    if (n < 0)
        throw runtime_error("vstringprintf(2) failed: " + string(strerror(errno)));
    string s(temp2);
    delete[] temp2;
    return s;
}

std::string
__attribute__ ((format(printf,1,2)))
stringprintf(const char* format, ...) {
    va_list lst;
    va_start(lst, format);
    string s = vstringprintf(format, lst);
    va_end(lst);
    return s;
}

// Holds a ZeroMQ socket that is used to talk to multiple logging
// servers.
class chime_log_socket {
    typedef std::lock_guard<std::mutex> scoped_lock;

public:
    chime_log_socket() :
        _ctx(NULL),
        _socket(NULL),
        _mutex(),
        _local(true),
        _name(),
        _threadnames()
    {}

    ~chime_log_socket() {
        if (_socket)
            delete _socket;
        if (_ctx)
            delete _ctx;
    }

    void set_local(bool loc) {
        scoped_lock l(_mutex);
        _local = loc;
    }

    void set_name(const std::string &name) {
        scoped_lock l(_mutex);
        _name = name;
    }

    void set_thread_name(const std::string &name) {
        scoped_lock l(_mutex);
        _threadnames[std::this_thread::get_id()] = name;
    }

    void open_socket(zmq::context_t* ctx) {
        scoped_lock l(_mutex);
        if (_socket)
            throw runtime_error("chime_log_socket::open_socket called but socket is already open.");
        if (!ctx)
            ctx = _ctx = new zmq::context_t();
        _socket = new zmq::socket_t(*ctx, ZMQ_PUB);

        if (!_name.length()) {
            char tmp[256];
            gethostname(tmp, 256);
            _name = tmp;
            cout << "Set hostname: " << _name << endl;
        }
        // Send buffer: ZMQ_SNDHWM: default 1000 messages
    }

    void close_socket() {
        scoped_lock l(_mutex);
        if (_socket)
            delete _socket;
        _socket = NULL;
    }

    void add_server(const std::string &port) {
        scoped_lock l(_mutex);
        if (!_socket)
            throw runtime_error("chime_log_socket::add_server called but socket has not been initialized.");
        _socket->connect(port.c_str());
    }

    void remove_server(const std::string &port) {
        scoped_lock l(_mutex);
        if (!_socket)
            throw runtime_error("chime_log_socket::remove_server called but socket has not been initialized.");
        _socket->disconnect(port.c_str());
    }

    void send(std::string header, std::string msg, bool do_assert) {
        scoped_lock l(_mutex);
        string tname = get_thread_name();
        if (_local) {
            if (do_assert)
                // Assume we want to know where it was...
                cout << header << endl;
            cout << "[" << tname << "] " << msg << endl;
        }
        if (!_socket)
            return;
        msg = _name + " " + tname + " " + header + " " + msg;
        _socket->send(static_cast<const void*>(msg.data()), msg.size());
    }

protected:
    std::string get_thread_name() {
        std::thread::id tid = std::this_thread::get_id();
        auto it = _threadnames.find(tid);
        if (it == _threadnames.end()) {
            std::ostringstream ss;
            ss << "Thread-" << tid;
            return ss.str();
        }
        return it->second;
    }

    zmq::context_t* _ctx;
    zmq::socket_t* _socket;

    // Mutex used to protect the socket (and also _socket/_ctx state)
    std::mutex _mutex;

    // Print to cout also?
    bool _local;

    // Client name to send
    std::string _name;

    // Thread name map
    std::map<std::thread::id, std::string> _threadnames;
};

// GLOBALS for logging.
static chime_log_socket logsock;

void chime_log_open_socket(zmq::context_t* ctx) {
    logsock.open_socket(ctx);
}

void chime_log_close_socket() {
    logsock.close_socket();
}

void chime_log_local(bool loc) {
    logsock.set_local(loc);
}

void chime_log_set_name(const std::string &name) {
    logsock.set_name(name);
}

void chime_log_set_thread_name(const std::string &name) {
    logsock.set_thread_name(name);
}

void chime_log_add_server(const std::string &port) {
    logsock.add_server(port);
}

void chime_log_remove_server(const std::string &port) {
    logsock.remove_server(port);
}

void chime_log(log_level lev, const char* file, int line, const char* function,
               const std::string &msg, bool do_assert) {
    struct timeval tv;
    string datestring;
    if (gettimeofday(&tv, NULL)) {
        cout << "Error calling gettimeofday(): " << strerror(errno) << endl;
    } else {
        struct tm cal;
        if (!gmtime_r(&tv.tv_sec, &cal)) {
            cout << "Error calling gmtime_r(): " << strerror(errno) << endl;
        } else {
            datestring = stringprintf("%04i-%02i-%02i-%02i:%02i:%02i.%03i",
                                      cal.tm_year + 1900, cal.tm_mon + 1, cal.tm_mday,
                                      cal.tm_hour, cal.tm_min, cal.tm_sec,
                                      int(tv.tv_usec / 1000));
        }
    }
    string levstring = (lev == log_level_debug ? "DEBUG" :
                        (lev == log_level_info ? "INFO" :
                         (lev == log_level_warn ? "WARN" :
                          (lev == log_level_err ? "ERROR" : "XXX"))));
    string header = (levstring +
                     stringprintf(" %s:%i [%s] ", file, line, function) +
                     datestring);
    logsock.send(header, msg, do_assert);
}

void
__attribute__ ((format(printf,5,6)))
chime_logf(enum log_level lev, const char* file, int line, const char* function, const char* pattern, ...) {
    va_list lst;
    va_start(lst, pattern);
    string s = vstringprintf(pattern, lst);
    va_end(lst);
    chime_log(lev, file, line, function, s);
}

chime_log_server::chime_log_server(std::ostream& out,
                                   zmq::context_t* ctx,
                                   const std::string &hostname,
                                   int port) :
    _out(out),
    _quit(false)
{
    if (!ctx)
        ctx = _ctx = new zmq::context_t();
    _socket = new zmq::socket_t(*ctx, ZMQ_SUB);
    _socket->setsockopt(ZMQ_SUBSCRIBE, "", 0);

    string addr = "tcp://" + hostname + ":";
    if (port == -1)
        addr = addr + "*";
    else
        addr = addr + std::to_string(port);

    _socket->bind(addr.c_str());

    char addrx[256];
    size_t addrsz = 256;
    _socket->getsockopt(ZMQ_LAST_ENDPOINT,
                        reinterpret_cast<void*>(addrx), &addrsz);
    _address = string(addrx);
    //cout << "Bound to address " << _address << endl;

    // When binding "*", the returned address is like "tcp://0.0.0.0:6534".
    // Replace "0.0.0.0" by my IP address
    size_t i = _address.find("0.0.0.0");
    if (i != std::string::npos) {
        string ipaddress = "0.0.0.0";
        char name[256];
        if (gethostname(name, 256)) {
            cout << "Failed to gethostname(): " << strerror(errno) << endl;
        } else {
            //cout << "Hostname: " << name << endl;
            struct addrinfo* addrs = NULL;
            if (getaddrinfo(name, NULL, NULL, &addrs)) {
                cout << "Failed to getaddrinfo(): " << gai_strerror(errno) << endl;
            } else {
                struct addrinfo* a;
                for(a = addrs; a != NULL; a = a->ai_next) {
                    if (a->ai_family != AF_INET)
                        continue;
                    char dots[INET_ADDRSTRLEN];
                    struct sockaddr_in* sin = reinterpret_cast<struct sockaddr_in*>(a->ai_addr);
                    if (!inet_ntop(AF_INET, &(sin->sin_addr), dots, INET_ADDRSTRLEN)) {
                        cout << "Failed to inet_ntop: " << strerror(errno) << endl;
                    } else {
                        ipaddress = dots;
                        //cout << "My address: " << dots << endl;
                        break;
                    }
                }
                freeaddrinfo(addrs);
            }
        }
        _address.replace(i, 7, ipaddress);
        //cout << "Replaced address: " << _address << endl;
    }
}

chime_log_server::~chime_log_server() {
    delete _socket;
    if (_ctx) {
        delete _ctx;
    }
}

std::string chime_log_server::get_address() {
    return _address;
}

static string msg_string(zmq::message_t &msg) {
    return string(static_cast<const char*>(msg.data()), msg.size());
}

void chime_log_server::run() {

    void* p_sock = _socket->operator void*();
    zmq_pollitem_t pollitems[] = {
        { p_sock, 0, ZMQ_POLLIN, 0 },
    };

    for (;;) {
        zmq::message_t msg;
        try {

            int r = zmq::poll(pollitems, 1, 1000);
            if (r == -1) {
                cout << "log server: zmq::poll error: " << strerror(errno) << endl;
                break;
            }

            if (_quit) {
                cout << "log server: _quit!" << endl;
                break;
            }

            if (!pollitems[0].revents & ZMQ_POLLIN) {
                cout << "log server: no input ready" << endl;
                continue;
            }

            if (!_socket->recv(&msg)) {
                _out << "log server: failed to receive message" << endl;
                break;
            }
        } catch (const zmq::error_t& e) {
            _out << "log server: error receiving message: " << e.what() << endl;
            break;
        }
        _out << msg_string(msg) << endl;
    }
    cout << "log server: exiting" << endl;
}

// Starts a new thread to run this server.
std::thread chime_log_server::start() {
    thread t(std::bind(&chime_log_server::run, this));
    t.detach();
    return t;
}

void chime_log_server::stop() {
    _quit = true;
}

} // namespace

<commit_msg>add parens for ambiguous statement<commit_after>#include <cstdlib>
#include <map>
#include <stdarg.h> // for va_start/va_end
#include <thread>
#include <mutex>
#include <functional>
#include <iostream>
#include <ostream>
#include <sstream>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <zmq.hpp>
#include "chlog.hpp"

using namespace std;
using namespace ch_frb_io;

namespace ch_frb_io {
#if 0
}; // pacify emacs c-mode
#endif

static string
vstringprintf(const char* format, va_list lst) {
    char temps[256];
    // truncates if length > size of 'temps'
    int n = vsnprintf(temps, sizeof(temps), format, lst);
    if (n < 0)
        throw runtime_error("vstringprintf failed: " + string(strerror(errno)));
    if (n < 256)
        return string(temps);
    // Try again with larger temp buffer
    char* temp2 = new char[n+1];
    n = vsnprintf(temp2, n+1, format, lst);
    if (n < 0)
        throw runtime_error("vstringprintf(2) failed: " + string(strerror(errno)));
    string s(temp2);
    delete[] temp2;
    return s;
}

std::string
__attribute__ ((format(printf,1,2)))
stringprintf(const char* format, ...) {
    va_list lst;
    va_start(lst, format);
    string s = vstringprintf(format, lst);
    va_end(lst);
    return s;
}

// Holds a ZeroMQ socket that is used to talk to multiple logging
// servers.
class chime_log_socket {
    typedef std::lock_guard<std::mutex> scoped_lock;

public:
    chime_log_socket() :
        _ctx(NULL),
        _socket(NULL),
        _mutex(),
        _local(true),
        _name(),
        _threadnames()
    {}

    ~chime_log_socket() {
        if (_socket)
            delete _socket;
        if (_ctx)
            delete _ctx;
    }

    void set_local(bool loc) {
        scoped_lock l(_mutex);
        _local = loc;
    }

    void set_name(const std::string &name) {
        scoped_lock l(_mutex);
        _name = name;
    }

    void set_thread_name(const std::string &name) {
        scoped_lock l(_mutex);
        _threadnames[std::this_thread::get_id()] = name;
    }

    void open_socket(zmq::context_t* ctx) {
        scoped_lock l(_mutex);
        if (_socket)
            throw runtime_error("chime_log_socket::open_socket called but socket is already open.");
        if (!ctx)
            ctx = _ctx = new zmq::context_t();
        _socket = new zmq::socket_t(*ctx, ZMQ_PUB);

        if (!_name.length()) {
            char tmp[256];
            gethostname(tmp, 256);
            _name = tmp;
            cout << "Set hostname: " << _name << endl;
        }
        // Send buffer: ZMQ_SNDHWM: default 1000 messages
    }

    void close_socket() {
        scoped_lock l(_mutex);
        if (_socket)
            delete _socket;
        _socket = NULL;
    }

    void add_server(const std::string &port) {
        scoped_lock l(_mutex);
        if (!_socket)
            throw runtime_error("chime_log_socket::add_server called but socket has not been initialized.");
        _socket->connect(port.c_str());
    }

    void remove_server(const std::string &port) {
        scoped_lock l(_mutex);
        if (!_socket)
            throw runtime_error("chime_log_socket::remove_server called but socket has not been initialized.");
        _socket->disconnect(port.c_str());
    }

    void send(std::string header, std::string msg, bool do_assert) {
        scoped_lock l(_mutex);
        string tname = get_thread_name();
        if (_local) {
            if (do_assert)
                // Assume we want to know where it was...
                cout << header << endl;
            cout << "[" << tname << "] " << msg << endl;
        }
        if (!_socket)
            return;
        msg = _name + " " + tname + " " + header + " " + msg;
        _socket->send(static_cast<const void*>(msg.data()), msg.size());
    }

protected:
    std::string get_thread_name() {
        std::thread::id tid = std::this_thread::get_id();
        auto it = _threadnames.find(tid);
        if (it == _threadnames.end()) {
            std::ostringstream ss;
            ss << "Thread-" << tid;
            return ss.str();
        }
        return it->second;
    }

    zmq::context_t* _ctx;
    zmq::socket_t* _socket;

    // Mutex used to protect the socket (and also _socket/_ctx state)
    std::mutex _mutex;

    // Print to cout also?
    bool _local;

    // Client name to send
    std::string _name;

    // Thread name map
    std::map<std::thread::id, std::string> _threadnames;
};

// GLOBALS for logging.
static chime_log_socket logsock;

void chime_log_open_socket(zmq::context_t* ctx) {
    logsock.open_socket(ctx);
}

void chime_log_close_socket() {
    logsock.close_socket();
}

void chime_log_local(bool loc) {
    logsock.set_local(loc);
}

void chime_log_set_name(const std::string &name) {
    logsock.set_name(name);
}

void chime_log_set_thread_name(const std::string &name) {
    logsock.set_thread_name(name);
}

void chime_log_add_server(const std::string &port) {
    logsock.add_server(port);
}

void chime_log_remove_server(const std::string &port) {
    logsock.remove_server(port);
}

void chime_log(log_level lev, const char* file, int line, const char* function,
               const std::string &msg, bool do_assert) {
    struct timeval tv;
    string datestring;
    if (gettimeofday(&tv, NULL)) {
        cout << "Error calling gettimeofday(): " << strerror(errno) << endl;
    } else {
        struct tm cal;
        if (!gmtime_r(&tv.tv_sec, &cal)) {
            cout << "Error calling gmtime_r(): " << strerror(errno) << endl;
        } else {
            datestring = stringprintf("%04i-%02i-%02i-%02i:%02i:%02i.%03i",
                                      cal.tm_year + 1900, cal.tm_mon + 1, cal.tm_mday,
                                      cal.tm_hour, cal.tm_min, cal.tm_sec,
                                      int(tv.tv_usec / 1000));
        }
    }
    string levstring = (lev == log_level_debug ? "DEBUG" :
                        (lev == log_level_info ? "INFO" :
                         (lev == log_level_warn ? "WARN" :
                          (lev == log_level_err ? "ERROR" : "XXX"))));
    string header = (levstring +
                     stringprintf(" %s:%i [%s] ", file, line, function) +
                     datestring);
    logsock.send(header, msg, do_assert);
}

void
__attribute__ ((format(printf,5,6)))
chime_logf(enum log_level lev, const char* file, int line, const char* function, const char* pattern, ...) {
    va_list lst;
    va_start(lst, pattern);
    string s = vstringprintf(pattern, lst);
    va_end(lst);
    chime_log(lev, file, line, function, s);
}

chime_log_server::chime_log_server(std::ostream& out,
                                   zmq::context_t* ctx,
                                   const std::string &hostname,
                                   int port) :
    _out(out),
    _quit(false)
{
    if (!ctx)
        ctx = _ctx = new zmq::context_t();
    _socket = new zmq::socket_t(*ctx, ZMQ_SUB);
    _socket->setsockopt(ZMQ_SUBSCRIBE, "", 0);

    string addr = "tcp://" + hostname + ":";
    if (port == -1)
        addr = addr + "*";
    else
        addr = addr + std::to_string(port);

    _socket->bind(addr.c_str());

    char addrx[256];
    size_t addrsz = 256;
    _socket->getsockopt(ZMQ_LAST_ENDPOINT,
                        reinterpret_cast<void*>(addrx), &addrsz);
    _address = string(addrx);
    //cout << "Bound to address " << _address << endl;

    // When binding "*", the returned address is like "tcp://0.0.0.0:6534".
    // Replace "0.0.0.0" by my IP address
    size_t i = _address.find("0.0.0.0");
    if (i != std::string::npos) {
        string ipaddress = "0.0.0.0";
        char name[256];
        if (gethostname(name, 256)) {
            cout << "Failed to gethostname(): " << strerror(errno) << endl;
        } else {
            //cout << "Hostname: " << name << endl;
            struct addrinfo* addrs = NULL;
            if (getaddrinfo(name, NULL, NULL, &addrs)) {
                cout << "Failed to getaddrinfo(): " << gai_strerror(errno) << endl;
            } else {
                struct addrinfo* a;
                for(a = addrs; a != NULL; a = a->ai_next) {
                    if (a->ai_family != AF_INET)
                        continue;
                    char dots[INET_ADDRSTRLEN];
                    struct sockaddr_in* sin = reinterpret_cast<struct sockaddr_in*>(a->ai_addr);
                    if (!inet_ntop(AF_INET, &(sin->sin_addr), dots, INET_ADDRSTRLEN)) {
                        cout << "Failed to inet_ntop: " << strerror(errno) << endl;
                    } else {
                        ipaddress = dots;
                        //cout << "My address: " << dots << endl;
                        break;
                    }
                }
                freeaddrinfo(addrs);
            }
        }
        _address.replace(i, 7, ipaddress);
        //cout << "Replaced address: " << _address << endl;
    }
}

chime_log_server::~chime_log_server() {
    delete _socket;
    if (_ctx) {
        delete _ctx;
    }
}

std::string chime_log_server::get_address() {
    return _address;
}

static string msg_string(zmq::message_t &msg) {
    return string(static_cast<const char*>(msg.data()), msg.size());
}

void chime_log_server::run() {

    void* p_sock = _socket->operator void*();
    zmq_pollitem_t pollitems[] = {
        { p_sock, 0, ZMQ_POLLIN, 0 },
    };

    for (;;) {
        zmq::message_t msg;
        try {

            int r = zmq::poll(pollitems, 1, 1000);
            if (r == -1) {
                cout << "log server: zmq::poll error: " << strerror(errno) << endl;
                break;
            }

            if (_quit) {
                cout << "log server: _quit!" << endl;
                break;
            }

            if (!(pollitems[0].revents & ZMQ_POLLIN)) {
                cout << "log server: no input ready" << endl;
                continue;
            }

            if (!_socket->recv(&msg)) {
                _out << "log server: failed to receive message" << endl;
                break;
            }
        } catch (const zmq::error_t& e) {
            _out << "log server: error receiving message: " << e.what() << endl;
            break;
        }
        _out << msg_string(msg) << endl;
    }
    cout << "log server: exiting" << endl;
}

// Starts a new thread to run this server.
std::thread chime_log_server::start() {
    thread t(std::bind(&chime_log_server::run, this));
    t.detach();
    return t;
}

void chime_log_server::stop() {
    _quit = true;
}

} // namespace

<|endoftext|>


<commit_before>// Copyright (C) 2017 - 2018 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include "copasi.h"

#include "COptMethodTruncatedNewton.h"
#include "COptProblem.h"
#include "COptItem.h"
#include "COptTask.h"

#include "parameterFitting/CFitProblem.h"
#include "copasi/core/CDataObjectReference.h"

COptMethodTruncatedNewton::COptMethodTruncatedNewton(const CDataContainer * pParent,
    const CTaskEnum::Method & methodType,
    const CTaskEnum::Task & taskType):
  COptMethod(pParent, methodType, taskType),
  mpTruncatedNewton(new FTruncatedNewtonTemplate<COptMethodTruncatedNewton>(this, &COptMethodTruncatedNewton::sFun)),
  mpCTruncatedNewton(new CTruncatedNewton())
{
  initObjects();
}

COptMethodTruncatedNewton::COptMethodTruncatedNewton(const COptMethodTruncatedNewton & src,
    const CDataContainer * pParent):
  COptMethod(src, pParent),
  mpTruncatedNewton(new FTruncatedNewtonTemplate<COptMethodTruncatedNewton>(this, &COptMethodTruncatedNewton::sFun)),
  mpCTruncatedNewton(new CTruncatedNewton())
{initObjects();}

COptMethodTruncatedNewton::~COptMethodTruncatedNewton()
{
  pdelete(mpTruncatedNewton);
  pdelete(mpCTruncatedNewton);
  cleanup();
}

void COptMethodTruncatedNewton::initObjects()
{
  addObjectReference("Current Iteration", mIteration, CDataObject::ValueInt);
}

bool COptMethodTruncatedNewton::optimise()
{
  if (!initialize()) return false;

  if (mLogVerbosity > 0)
    mMethodLog.enterLogEntry(
      COptLogEntry(
        "Truncated Newton algorithm started",
        "For more information about this method see: http://copasi.org/Support/User_Manual/Methods/Optimization_Methods/Truncated_Newton/"
      )
    );

  C_FLOAT64 fest;
  C_INT lw, ierror = 0;
  lw = 14 * mVariableSize;

  CVector< C_FLOAT64 > up(mVariableSize);
  CVector< C_FLOAT64 > low(mVariableSize);
  CVector< C_INT > iPivot(mVariableSize);
  CVector< C_FLOAT64 > dwork(lw);

  up = std::numeric_limits< C_FLOAT64 >::max();
  low = - std::numeric_limits< C_FLOAT64 >::max();

  // initial point is the first guess but we have to make sure that
  // we are within the parameter domain
  C_INT i, repeat;
  bool pointInParameterDomain = true;

  for (i = 0; i < mVariableSize; i++)
    {
      const COptItem & OptItem = *(*mpOptItem)[i];

      // :TODO: In COPASI the bounds are not necessarry fixed.
      // Since evaluate checks for boundaries and constraints this is not
      // needed. The question remaining is how does tnbc_ handle unconstraint problems?
      // low[i] = *OptItem.getLowerBoundValue();
      // up[i] = *OptItem.getUpperBoundValue();

      mCurrent[i] = OptItem.getStartValue();

      switch (OptItem.checkConstraint(mCurrent[i]))
        {
          case - 1:
            mCurrent[i] = *OptItem.getLowerBoundValue();
            pointInParameterDomain = false;
            break;

          case 1:
            mCurrent[i] = *OptItem.getUpperBoundValue();
            pointInParameterDomain = false;
            break;

          case 0:
            break;
        }

      // set the value
      *mContainerVariables[i] = (mCurrent[i]);
    }

  if (!pointInParameterDomain && (mLogVerbosity > 0))
    mMethodLog.enterLogEntry(COptLogEntry("Initial point outside parameter domain."));

  // Report the first value as the current best
  mBestValue = evaluate();
  mBest = mCurrent;
  mContinue = mpOptProblem->setSolution(mBestValue, mBest);

  repeat = 0;

  //tnbc_ wants a signed int for loglevel...
  C_INT msglvl;
  msglvl = (int) mLogVerbosity;

  while (repeat < 10 && mContinue)
    {
      repeat++;

      // estimate minimum is 1/10 initial function value
      fest = (1 - pow(0.9, (C_FLOAT64) repeat)) * mEvaluationValue;
      ierror = 0;

      // minimise
      try
        {
          mpCTruncatedNewton->tnbc_(&ierror,
                                    &mVariableSize,
                                    mCurrent.array(),
                                    &fest,
                                    mGradient.array(),
                                    dwork.array(),
                                    &lw,
                                    mpTruncatedNewton,
                                    low.array(),
                                    up.array(),
                                    iPivot.array(),
                                    &msglvl,
                                    &mMethodLog);

          mEvaluationValue = fest;
        }

      // This signals that the user opted to interrupt
      catch (bool)
        {
          break;
        }

      if (ierror < 0)
        fatalError(); // Invalid parameter values.

      // The way the method is currently implemented may lead to parameters just outside the boundaries.
      // We need to check whether the current value is within the boundaries or whether the corrected
      // leads to an improved solution.

      bool withinBounds = true;

      for (i = 0; i < mVariableSize; i++)
        {
          const COptItem & OptItem = *(*mpOptItem)[i];

          //force it to be within the bounds
          switch (OptItem.checkConstraint(mCurrent[i]))
            {
              case - 1:
                withinBounds = false;
                mCurrent[i] = *OptItem.getLowerBoundValue();
                break;

              case 1:
                withinBounds = false;
                mCurrent[i] = *OptItem.getUpperBoundValue();
                break;

              case 0:
                break;
            }

          *mContainerVariables[i] = (mCurrent[i]);
        }

      evaluate();

      // Is the corrected value better than solution?
      if (mEvaluationValue < mBestValue)
        {
          // We found a new best value lets report it.
          // and store that value
          mBest = mCurrent;
          mBestValue = mEvaluationValue;

          mContinue = mpOptProblem->setSolution(mBestValue, mBest);

          // We found a new best value lets report it.
          mpParentTask->output(COutputInterface::DURING);
        }

      // We found a solution
      if (withinBounds)
        break;

      // Choosing another starting point will be left to the user
#ifdef XXXX

      // Try another starting point
      for (i = 0; i < mVariableSize; i++)
        {
          mCurrent[i] *= 1.2;
          const COptItem & OptItem = *(*mpOptItem)[i];

          //force it to be within the bounds
          switch (OptItem.checkConstraint(mCurrent[i]))
            {
              case - 1:
                mCurrent[i] = *OptItem.getLowerBoundValue();
                break;

              case 1:
                mCurrent[i] = *OptItem.getUpperBoundValue();
                break;

              case 0:
                break;
            }

          *mContainerVariables[i] = (mCurrent[i]);
        }

      evaluate();

      // Check whether we improved
      if (mEvaluationValue < mBestValue)
        {
          // We found a new best value lets report it.
          // and store that value
          mBest = mCurrent;
          mBestValue = mEvaluationValue;

          mContinue = mpOptProblem->setSolution(mBestValue, mBest);

          // We found a new best value lets report it.
          mpParentTask->output(COutputInterface::DURING);
        }

#endif // XXXX

      if (mLogVerbosity > 0)
        mMethodLog.enterLogEntry(
          COptLogEntry(
            "Solution parameters outside of the boundaries. Repeating calculations from current border position ("
            + std::to_string(repeat) + ")")
        );
    }

  if (mLogVerbosity > 0)
    mMethodLog.enterLogEntry(COptLogEntry("Algorithm finished."));

  return true;
}

bool COptMethodTruncatedNewton::initialize()
{
  cleanup();

  if (!COptMethod::initialize()) return false;

  mVariableSize = (C_INT) mpOptItem->size();
  mCurrent.resize(mVariableSize);
  mBest.resize(mVariableSize);

  mContinue = true;
  mBestValue = std::numeric_limits<C_FLOAT64>::infinity();
  mGradient.resize(mVariableSize);

  return true;
}

bool COptMethodTruncatedNewton::cleanup()
{
  return true;
}

// callback function, evaluate the value of the objective function and its gradient
//(by finite differences), translated by f2c, edited by Pedro and then modified for COPASI by Joseph
C_INT COptMethodTruncatedNewton::sFun(C_INT *n, C_FLOAT64 *x, C_FLOAT64 *f, C_FLOAT64 *g)
{
  C_INT i;

  // set the parameter values
  for (i = 0; i < *n; i++)
    *mContainerVariables[i] = (x[i]);

  //carry out the function evaluation
  *f = evaluate();

  // Check whether we improved
  if (mEvaluationValue < mBestValue)
    {
      // We found a new best value lets report it.
      // and store that value
      for (i = 0; i < *n; i++)
        mBest[i] = x[i];

      mBestValue = mEvaluationValue;
      mContinue = mpOptProblem->setSolution(mBestValue, mBest);

      // We found a new best value lets report it.
      mpParentTask->output(COutputInterface::DURING);
    }

  // Calculate the gradient
  for (i = 0; i < *n && mContinue; i++)
    {
      if (x[i] != 0.0)
        {
          *mContainerVariables[i] = (x[i] * 1.001);
          g[i] = (evaluate() - *f) / (x[i] * 0.001);
          else
            {
              // why use 1e-7? shouldn't this be epsilon, or something like that?
              *mContainerVariables[i] = (1e-7);
              g[i] = (evaluate() - *f) / 1e-7;

              if (mLogVerbosity > 2)
                {
                  std::ostringstream auxStream;
                  auxStream << "Calculating gradient for zero valued parameter " << i << ", using 1e-7, results in " << g[i] << ".";
                  mMethodLog.enterLogEntry(COptLogEntry(auxStream.str()));
                }
            }

          *mContainerVariables[i] = (x[i]);
        }

      if (!mContinue)
        throw bool(mContinue);

      return 0;
    }

  const C_FLOAT64 & COptMethodTruncatedNewton::evaluate()
  {
    // We do not need to check whether the parametric constraints are fulfilled
    // since the parameters are created within the bounds.
    mContinue = mpOptProblem->calculate();
    mEvaluationValue = mpOptProblem->getCalculateValue();

    // when we leave the either the parameter or functional domain
    // we penalize the objective value by forcing it to be larger
    // than the best value recorded so far.
    if (mEvaluationValue < mBestValue &&
        (!mpOptProblem->checkParametricConstraints() ||
         !mpOptProblem->checkFunctionalConstraints()))
      mEvaluationValue = mBestValue + mBestValue - mEvaluationValue;

    return mEvaluationValue;
  }

  unsigned C_INT32 COptMethodTruncatedNewton::getMaxLogVerbosity() const
  {
    return 1;
  }
<commit_msg>removed cyclic call to tnbc_, now only one call<commit_after>// Copyright (C) 2017 - 2018 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include "copasi.h"

#include "COptMethodTruncatedNewton.h"
#include "COptProblem.h"
#include "COptItem.h"
#include "COptTask.h"

#include "parameterFitting/CFitProblem.h"
#include "copasi/core/CDataObjectReference.h"

COptMethodTruncatedNewton::COptMethodTruncatedNewton(const CDataContainer * pParent,
    const CTaskEnum::Method & methodType,
    const CTaskEnum::Task & taskType):
  COptMethod(pParent, methodType, taskType),
  mpTruncatedNewton(new FTruncatedNewtonTemplate<COptMethodTruncatedNewton>(this, &COptMethodTruncatedNewton::sFun)),
  mpCTruncatedNewton(new CTruncatedNewton())
{
  initObjects();
}

COptMethodTruncatedNewton::COptMethodTruncatedNewton(const COptMethodTruncatedNewton & src,
    const CDataContainer * pParent):
  COptMethod(src, pParent),
  mpTruncatedNewton(new FTruncatedNewtonTemplate<COptMethodTruncatedNewton>(this, &COptMethodTruncatedNewton::sFun)),
  mpCTruncatedNewton(new CTruncatedNewton())
{initObjects();}

COptMethodTruncatedNewton::~COptMethodTruncatedNewton()
{
  pdelete(mpTruncatedNewton);
  pdelete(mpCTruncatedNewton);
  cleanup();
}

void COptMethodTruncatedNewton::initObjects()
{
  addObjectReference("Current Iteration", mIteration, CDataObject::ValueInt);
}

bool COptMethodTruncatedNewton::optimise()
{
  if (!initialize()) return false;

  if (mLogVerbosity > 0)
    mMethodLog.enterLogEntry(
      COptLogEntry(
        "Truncated Newton algorithm started",
        "For more information about this method see: http://copasi.org/Support/User_Manual/Methods/Optimization_Methods/Truncated_Newton/"
      )
    );

  C_FLOAT64 fest;
  C_INT lw, ierror = 0;
  lw = 14 * mVariableSize;

  CVector< C_FLOAT64 > up(mVariableSize);
  CVector< C_FLOAT64 > low(mVariableSize);
  CVector< C_INT > iPivot(mVariableSize);
  CVector< C_FLOAT64 > dwork(lw);

  up = std::numeric_limits< C_FLOAT64 >::max();
  low = - std::numeric_limits< C_FLOAT64 >::max();

  // initial point is the first guess but we have to make sure that
  // we are within the parameter domain
  C_INT i, repeat;
  bool pointInParameterDomain = true;

  for (i = 0; i < mVariableSize; i++)
    {
      const COptItem & OptItem = *(*mpOptItem)[i];

      // :TODO: In COPASI the bounds are not necessarry fixed.
      // Since evaluate checks for boundaries and constraints this is not
      // needed. The question remaining is how does tnbc_ handle unconstraint problems?
      // low[i] = *OptItem.getLowerBoundValue();
      // up[i] = *OptItem.getUpperBoundValue();

      mCurrent[i] = OptItem.getStartValue();

      switch (OptItem.checkConstraint(mCurrent[i]))
        {
          case - 1:
            mCurrent[i] = *OptItem.getLowerBoundValue();
            pointInParameterDomain = false;
            break;

          case 1:
            mCurrent[i] = *OptItem.getUpperBoundValue();
            pointInParameterDomain = false;
            break;

          case 0:
            break;
        }

      // set the value
      *mContainerVariables[i] = (mCurrent[i]);
    }

  if (!pointInParameterDomain && (mLogVerbosity > 0))
    mMethodLog.enterLogEntry(COptLogEntry("Initial point outside parameter domain."));

  // Report the first value as the current best
  mBestValue = evaluate();
  mBest = mCurrent;
  mContinue = mpOptProblem->setSolution(mBestValue, mBest);

  //tnbc_ wants a signed int for loglevel...
  C_INT msglvl;
  msglvl = (int) mLogVerbosity;

  // estimate minimum is 1/10 initial function value (which is now in mBestValue)
  fest = 0.1 * mBestValue;
  ierror = 0;

  // minimise
  try
    {
      mpCTruncatedNewton->tnbc_(&ierror,
                                &mVariableSize,
                                mCurrent.array(),
                                &fest,
                                mGradient.array(),
                                dwork.array(),
                                &lw,
                                mpTruncatedNewton,
                                low.array(),
                                up.array(),
                                iPivot.array(),
                                &msglvl,
                                &mMethodLog);
      mEvaluationValue = fest;

      // Is the corrected value better than solution?
      if (mEvaluationValue < mBestValue)
        {
          // We found a new best value lets report it.
          // and store that value
          mBest = mCurrent;
          mBestValue = mEvaluationValue;

          mContinue = mpOptProblem->setSolution(mBestValue, mBest);

          // We found a new best value lets report it.
          mpParentTask->output(COutputInterface::DURING);
        }
    }
  // This signals that the user opted to interrupt
  catch (bool)
    {
      break;
    }

  if (ierror < 0)
    fatalError(); // Invalid parameter values.

  /*
   * TODO: THIS SEEMS TO BE FALSE; THIS TEST SHOULD NOT BE DONE!
   * THIS SECTION CANDIDATE FOR REMOVAL!
   */

  // The way the method is currently implemented may lead to parameters just outside the boundaries.
  // We need to check whether the current value is within the boundaries or whether the corrected
  // leads to an improved solution.
  bool withinBounds = true;

  for (i = 0; i < mVariableSize; i++)
    {
      const COptItem & OptItem = *(*mpOptItem)[i];

      //force it to be within the bounds
      switch (OptItem.checkConstraint(mCurrent[i]))
        {
          case - 1:
            withinBounds = false;
            mCurrent[i] = *OptItem.getLowerBoundValue();

            if (mLogVerbosity > 1)
              mMethodLog.enterLogEntry(COptLogEntry("Parameter " + std::to_string(i) + " below lower bound. Reseting."));

            break;

          case 1:
            withinBounds = false;
            mCurrent[i] = *OptItem.getUpperBoundValue();

            if (mLogVerbosity > 1)
              mMethodLog.enterLogEntry(COptLogEntry("Parameter " + std::to_string(i) + " above upper bound. Reseting."));

            break;

          case 0:
            break;
        }

      *mContainerVariables[i] = (mCurrent[i]);
    }

  if (!withinBounds)
    {
      if (mLogVerbosity > 0)
        mMethodLog.enterLogEntry(
          COptLogEntry("Solution parameters outside of the boundaries. Repeating calculations from current border position."));

      evaluate();

      // Is the corrected value better than solution?
      if (mEvaluationValue < mBestValue)
        {
          // We found a new best value lets report it.
          // and store that value
          mBest = mCurrent;
          mBestValue = mEvaluationValue;

          mContinue = mpOptProblem->setSolution(mBestValue, mBest);

          // We found a new best value lets report it.
          mpParentTask->output(COutputInterface::DURING);
        }
    }

  /*
   * END OF SECTION CANDIDATE FOR REMOVAL
   */

  if (mLogVerbosity > 0)
    mMethodLog.enterLogEntry(COptLogEntry("Algorithm finished."));

  return true;
}

bool COptMethodTruncatedNewton::initialize()
{
  cleanup();

  if (!COptMethod::initialize()) return false;

  mVariableSize = (C_INT) mpOptItem->size();
  mCurrent.resize(mVariableSize);
  mBest.resize(mVariableSize);

  mContinue = true;
  mBestValue = std::numeric_limits<C_FLOAT64>::infinity();
  mGradient.resize(mVariableSize);

  return true;
}

bool COptMethodTruncatedNewton::cleanup()
{
  return true;
}

// callback function, evaluate the value of the objective function and its gradient
//(by finite differences), translated by f2c, edited by Pedro and then modified for COPASI by Joseph
C_INT COptMethodTruncatedNewton::sFun(C_INT *n, C_FLOAT64 *x, C_FLOAT64 *f, C_FLOAT64 *g)
{
  C_INT i;

  // set the parameter values
  for (i = 0; i < *n; i++)
    *mContainerVariables[i] = (x[i]);

  //carry out the function evaluation
  *f = evaluate();

  // Check whether we improved
  if (mEvaluationValue < mBestValue)
    {
      // We found a new best value lets report it.
      // and store that value
      for (i = 0; i < *n; i++)
        mBest[i] = x[i];

      mBestValue = mEvaluationValue;
      mContinue = mpOptProblem->setSolution(mBestValue, mBest);

      // We found a new best value lets report it.
      mpParentTask->output(COutputInterface::DURING);
    }

  // Calculate the gradient
  for (i = 0; i < *n && mContinue; i++)
    {
      if (x[i] != 0.0)
        {
          *mContainerVariables[i] = (x[i] * 1.001);
          g[i] = (evaluate() - *f) / (x[i] * 0.001);
          else
            {
              // why use 1e-7? shouldn't this be epsilon, or something like that?
              *mContainerVariables[i] = (1e-7);
              g[i] = (evaluate() - *f) / 1e-7;

              if (mLogVerbosity > 2)
                {
                  std::ostringstream auxStream;
                  auxStream << "Calculating gradient for zero valued parameter " << i << ", using 1e-7, results in " << g[i] << ".";
                  mMethodLog.enterLogEntry(COptLogEntry(auxStream.str()));
                }
            }

          *mContainerVariables[i] = (x[i]);
        }

      if (!mContinue)
        throw bool(mContinue);

      return 0;
    }

  const C_FLOAT64 & COptMethodTruncatedNewton::evaluate()
  {
    // We do not need to check whether the parametric constraints are fulfilled
    // since the parameters are created within the bounds.
    mContinue = mpOptProblem->calculate();
    mEvaluationValue = mpOptProblem->getCalculateValue();

    // when we leave the either the parameter or functional domain
    // we penalize the objective value by forcing it to be larger
    // than the best value recorded so far.
    if (mEvaluationValue < mBestValue &&
        (!mpOptProblem->checkParametricConstraints() ||
         !mpOptProblem->checkFunctionalConstraints()))
      mEvaluationValue = mBestValue + mBestValue - mEvaluationValue;

    return mEvaluationValue;
  }

  unsigned C_INT32 COptMethodTruncatedNewton::getMaxLogVerbosity() const
  {
    return 1;
  }
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "helpviewer.h"

#if defined(QT_NO_WEBKIT)

#include "helpconstants.h"
#include "helpviewer_p.h"
#include "helpmanager.h"

#include <QtGui/QApplication>
#include <QtGui/QClipboard>
#include <QtGui/QContextMenuEvent>
#include <QtGui/QKeyEvent>
#include <QtGui/QMenu>

#include <QtHelp/QHelpEngineCore>

using namespace Find;
using namespace Help;
using namespace Help::Internal;

// -- HelpViewer

HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
    : QTextBrowser(parent)
    , d(new HelpViewerPrivate(zoom))
{
    QPalette p = palette();
    p.setColor(QPalette::Inactive, QPalette::Highlight,
        p.color(QPalette::Active, QPalette::Highlight));
    p.setColor(QPalette::Inactive, QPalette::HighlightedText,
        p.color(QPalette::Active, QPalette::HighlightedText));
    setPalette(p);

    installEventFilter(this);
    document()->setDocumentMargin(8);

    QFont font = viewerFont();
    font.setPointSize(int(font.pointSize() + zoom));
    setViewerFont(font);

    connect(this, SIGNAL(sourceChanged(QUrl)), this, SIGNAL(titleChanged()));
    connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool)));
}

HelpViewer::~HelpViewer()
{
    delete d;
}

QFont HelpViewer::viewerFont() const
{
    const QHelpEngineCore &engine = HelpManager::helpEngineCore();
    return qVariantValue<QFont>(engine.customValue(QLatin1String("font"),
        qApp->font()));
}

void HelpViewer::setViewerFont(const QFont &newFont)
{
    if (font() != newFont) {
        d->forceFont = true;
        setFont(newFont);
        d->forceFont = false;
    }
}

void HelpViewer::scaleUp()
{
    if (d->zoomCount < 10) {
        d->zoomCount++;
        d->forceFont = true;
        zoomIn();
        d->forceFont = false;
    }
}

void HelpViewer::scaleDown()
{
    if (d->zoomCount > -5) {
        d->zoomCount--;
        d->forceFont = true;
        zoomOut();
        d->forceFont = false;
    }
}

void HelpViewer::resetScale()
{
    if (d->zoomCount != 0) {
        d->forceFont = true;
        zoomOut(d->zoomCount);
        d->forceFont = false;
    }
    d->zoomCount = 0;
}

qreal HelpViewer::scale() const
{
    return d->zoomCount;
}

QString HelpViewer::title() const
{
    return documentTitle();
}

void HelpViewer::setTitle(const QString &title)
{
    setDocumentTitle(title);
}

QUrl HelpViewer::source() const
{
    return QTextBrowser::source();
}

void HelpViewer::setSource(const QUrl &url)
{
    const QString &string = url.toString();
    if (url.isValid() && string != QLatin1String("help")) {
        if (launchWithExternalApp(url))
            return;

        const QHelpEngineCore &engine = HelpManager::instance().helpEngineCore();
        const QUrl &resolvedUrl = engine.findFile(url);
        if (resolvedUrl.isValid()) {
            QTextBrowser::setSource(resolvedUrl);
            emit loadFinished(true);
            return;
        }
    }

    QTextBrowser::setSource(url);
    setHtml(string == Help::Constants::AboutBlank ? AboutBlankPage
        : PageNotFoundMessage.arg(url.toString()));
    emit loadFinished(true);
}

QString HelpViewer::selectedText() const
{
    return textCursor().selectedText();
}

bool HelpViewer::isForwardAvailable() const
{
    return QTextBrowser::isForwardAvailable();
}

bool HelpViewer::isBackwardAvailable() const
{
    return QTextBrowser::isBackwardAvailable();
}

bool HelpViewer::findText(const QString &text, IFindSupport::FindFlags flags,
    bool incremental, bool fromSearch)
{
    QTextDocument *doc = document();
    QTextCursor cursor = textCursor();
    if (!doc || cursor.isNull())
        return false;

    const int position = cursor.selectionStart();
    if (incremental)
        cursor.setPosition(position);

    QTextDocument::FindFlags f = IFindSupport::textDocumentFlagsForFindFlags(flags);
    QTextCursor found = doc->find(text, cursor, f);
    if (found.isNull()) {
        if ((flags & Find::IFindSupport::FindBackward) == 0)
            cursor.movePosition(QTextCursor::Start);
        else
            cursor.movePosition(QTextCursor::End);
        found = doc->find(text, cursor, f);
    }

    if (fromSearch) {
        cursor.beginEditBlock();
        viewport()->setUpdatesEnabled(false);

        QTextCharFormat marker;
        marker.setForeground(Qt::red);
        cursor.movePosition(QTextCursor::Start);
        setTextCursor(cursor);

        while (find(text)) {
            QTextCursor hit = textCursor();
            hit.mergeCharFormat(marker);
        }

        viewport()->setUpdatesEnabled(true);
        cursor.endEditBlock();
    }

    bool cursorIsNull = found.isNull();
    if (cursorIsNull) {
        found = textCursor();
        found.setPosition(position);
    }
    setTextCursor(found);
    return cursorIsNull;
}

// -- public slots

void HelpViewer::copy()
{
    QTextBrowser::copy();
}

void HelpViewer::forward()
{
    QTextBrowser::forward();
}

void HelpViewer::backward()
{
    QTextBrowser::backward();
}

// -- protected

void HelpViewer::keyPressEvent(QKeyEvent *e)
{
    if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier)
        || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) {
        QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier,
            e->text(), e->isAutoRepeat(), e->count());
        e = event;
    }
    QTextBrowser::keyPressEvent(e);
}

void HelpViewer::wheelEvent(QWheelEvent *e)
{
    if (e->modifiers() == Qt::ControlModifier) {
        e->accept();
        e->delta() > 0 ? scaleUp() : scaleDown();
    } else {
        QTextBrowser::wheelEvent(e);
    }
}

void HelpViewer::mousePressEvent(QMouseEvent *e)
{
#ifdef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(e))
        return;
#endif
    QTextBrowser::mousePressEvent(e);
}

void HelpViewer::mouseReleaseEvent(QMouseEvent *e)
{
#ifndef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(e))
        return;
#endif

    bool controlPressed = e->modifiers() & Qt::ControlModifier;
    if ((controlPressed && d->hasAnchorAt(this, e->pos())) ||
        (e->button() == Qt::MidButton && d->hasAnchorAt(this, e->pos()))) {
        d->openLinkInNewPage();
        return;
    }

    QTextBrowser::mouseReleaseEvent(e);
}

// -- private slots

void HelpViewer::actionChanged()
{
    // stub
}

void HelpViewer::setLoadFinished(bool ok)
{
    Q_UNUSED(ok)
    emit sourceChanged(source());
}

// -- private

bool HelpViewer::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::FontChange && !d->forceFont)
        return true;
    return QTextBrowser::eventFilter(obj, event);
}

void HelpViewer::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu menu(QLatin1String(""), 0);

    QUrl link;
    QAction *copyAnchorAction = 0;
    if (d->hasAnchorAt(this, event->pos())) {
        link = anchorAt(event->pos());
        if (link.isRelative())
            link = source().resolved(link);
        menu.addAction(tr("Open Link"), d, SLOT(openLink()));
        menu.addAction(tr("Open Link as New Page"), d, SLOT(openLinkInNewPage()));

        if (!link.isEmpty() && link.isValid())
            copyAnchorAction = menu.addAction(tr("Copy Link"));
    } else if (!selectedText().isEmpty()) {
        menu.addAction(tr("Copy"), this, SLOT(copy()));
    } else {
        menu.addAction(tr("Reload"), this, SLOT(reload()));
    }

    if (copyAnchorAction == menu.exec(event->globalPos()))
        QApplication::clipboard()->setText(link.toString());
}

QVariant HelpViewer::loadResource(int type, const QUrl &name)
{
    QByteArray ba;
    if (type < 4) {
        const QHelpEngineCore &engine = HelpManager::instance().helpEngineCore();
        ba = engine.fileData(name);
        if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) {
            QImage image;
            image.loadFromData(ba, "svg");
            if (!image.isNull())
                return image;
        }
    }
    return ba;
}

#endif  // QT_NO_WEBKIT
<commit_msg>The return value was reversed, though not checked really.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "helpviewer.h"

#if defined(QT_NO_WEBKIT)

#include "helpconstants.h"
#include "helpviewer_p.h"
#include "helpmanager.h"

#include <QtGui/QApplication>
#include <QtGui/QClipboard>
#include <QtGui/QContextMenuEvent>
#include <QtGui/QKeyEvent>
#include <QtGui/QMenu>

#include <QtHelp/QHelpEngineCore>

using namespace Find;
using namespace Help;
using namespace Help::Internal;

// -- HelpViewer

HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
    : QTextBrowser(parent)
    , d(new HelpViewerPrivate(zoom))
{
    QPalette p = palette();
    p.setColor(QPalette::Inactive, QPalette::Highlight,
        p.color(QPalette::Active, QPalette::Highlight));
    p.setColor(QPalette::Inactive, QPalette::HighlightedText,
        p.color(QPalette::Active, QPalette::HighlightedText));
    setPalette(p);

    installEventFilter(this);
    document()->setDocumentMargin(8);

    QFont font = viewerFont();
    font.setPointSize(int(font.pointSize() + zoom));
    setViewerFont(font);

    connect(this, SIGNAL(sourceChanged(QUrl)), this, SIGNAL(titleChanged()));
    connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool)));
}

HelpViewer::~HelpViewer()
{
    delete d;
}

QFont HelpViewer::viewerFont() const
{
    const QHelpEngineCore &engine = HelpManager::helpEngineCore();
    return qVariantValue<QFont>(engine.customValue(QLatin1String("font"),
        qApp->font()));
}

void HelpViewer::setViewerFont(const QFont &newFont)
{
    if (font() != newFont) {
        d->forceFont = true;
        setFont(newFont);
        d->forceFont = false;
    }
}

void HelpViewer::scaleUp()
{
    if (d->zoomCount < 10) {
        d->zoomCount++;
        d->forceFont = true;
        zoomIn();
        d->forceFont = false;
    }
}

void HelpViewer::scaleDown()
{
    if (d->zoomCount > -5) {
        d->zoomCount--;
        d->forceFont = true;
        zoomOut();
        d->forceFont = false;
    }
}

void HelpViewer::resetScale()
{
    if (d->zoomCount != 0) {
        d->forceFont = true;
        zoomOut(d->zoomCount);
        d->forceFont = false;
    }
    d->zoomCount = 0;
}

qreal HelpViewer::scale() const
{
    return d->zoomCount;
}

QString HelpViewer::title() const
{
    return documentTitle();
}

void HelpViewer::setTitle(const QString &title)
{
    setDocumentTitle(title);
}

QUrl HelpViewer::source() const
{
    return QTextBrowser::source();
}

void HelpViewer::setSource(const QUrl &url)
{
    const QString &string = url.toString();
    if (url.isValid() && string != QLatin1String("help")) {
        if (launchWithExternalApp(url))
            return;

        const QHelpEngineCore &engine = HelpManager::instance().helpEngineCore();
        const QUrl &resolvedUrl = engine.findFile(url);
        if (resolvedUrl.isValid()) {
            QTextBrowser::setSource(resolvedUrl);
            emit loadFinished(true);
            return;
        }
    }

    QTextBrowser::setSource(url);
    setHtml(string == Help::Constants::AboutBlank ? AboutBlankPage
        : PageNotFoundMessage.arg(url.toString()));
    emit loadFinished(true);
}

QString HelpViewer::selectedText() const
{
    return textCursor().selectedText();
}

bool HelpViewer::isForwardAvailable() const
{
    return QTextBrowser::isForwardAvailable();
}

bool HelpViewer::isBackwardAvailable() const
{
    return QTextBrowser::isBackwardAvailable();
}

bool HelpViewer::findText(const QString &text, IFindSupport::FindFlags flags,
    bool incremental, bool fromSearch)
{
    QTextDocument *doc = document();
    QTextCursor cursor = textCursor();
    if (!doc || cursor.isNull())
        return false;

    const int position = cursor.selectionStart();
    if (incremental)
        cursor.setPosition(position);

    QTextDocument::FindFlags f = IFindSupport::textDocumentFlagsForFindFlags(flags);
    QTextCursor found = doc->find(text, cursor, f);
    if (found.isNull()) {
        if ((flags & Find::IFindSupport::FindBackward) == 0)
            cursor.movePosition(QTextCursor::Start);
        else
            cursor.movePosition(QTextCursor::End);
        found = doc->find(text, cursor, f);
    }

    if (fromSearch) {
        cursor.beginEditBlock();
        viewport()->setUpdatesEnabled(false);

        QTextCharFormat marker;
        marker.setForeground(Qt::red);
        cursor.movePosition(QTextCursor::Start);
        setTextCursor(cursor);

        while (find(text)) {
            QTextCursor hit = textCursor();
            hit.mergeCharFormat(marker);
        }

        viewport()->setUpdatesEnabled(true);
        cursor.endEditBlock();
    }

    bool cursorIsNull = found.isNull();
    if (cursorIsNull) {
        found = textCursor();
        found.setPosition(position);
    }
    setTextCursor(found);
    return !cursorIsNull;
}

// -- public slots

void HelpViewer::copy()
{
    QTextBrowser::copy();
}

void HelpViewer::forward()
{
    QTextBrowser::forward();
}

void HelpViewer::backward()
{
    QTextBrowser::backward();
}

// -- protected

void HelpViewer::keyPressEvent(QKeyEvent *e)
{
    if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier)
        || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) {
        QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier,
            e->text(), e->isAutoRepeat(), e->count());
        e = event;
    }
    QTextBrowser::keyPressEvent(e);
}

void HelpViewer::wheelEvent(QWheelEvent *e)
{
    if (e->modifiers() == Qt::ControlModifier) {
        e->accept();
        e->delta() > 0 ? scaleUp() : scaleDown();
    } else {
        QTextBrowser::wheelEvent(e);
    }
}

void HelpViewer::mousePressEvent(QMouseEvent *e)
{
#ifdef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(e))
        return;
#endif
    QTextBrowser::mousePressEvent(e);
}

void HelpViewer::mouseReleaseEvent(QMouseEvent *e)
{
#ifndef Q_OS_LINUX
    if (handleForwardBackwardMouseButtons(e))
        return;
#endif

    bool controlPressed = e->modifiers() & Qt::ControlModifier;
    if ((controlPressed && d->hasAnchorAt(this, e->pos())) ||
        (e->button() == Qt::MidButton && d->hasAnchorAt(this, e->pos()))) {
        d->openLinkInNewPage();
        return;
    }

    QTextBrowser::mouseReleaseEvent(e);
}

// -- private slots

void HelpViewer::actionChanged()
{
    // stub
}

void HelpViewer::setLoadFinished(bool ok)
{
    Q_UNUSED(ok)
    emit sourceChanged(source());
}

// -- private

bool HelpViewer::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::FontChange && !d->forceFont)
        return true;
    return QTextBrowser::eventFilter(obj, event);
}

void HelpViewer::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu menu(QLatin1String(""), 0);

    QUrl link;
    QAction *copyAnchorAction = 0;
    if (d->hasAnchorAt(this, event->pos())) {
        link = anchorAt(event->pos());
        if (link.isRelative())
            link = source().resolved(link);
        menu.addAction(tr("Open Link"), d, SLOT(openLink()));
        menu.addAction(tr("Open Link as New Page"), d, SLOT(openLinkInNewPage()));

        if (!link.isEmpty() && link.isValid())
            copyAnchorAction = menu.addAction(tr("Copy Link"));
    } else if (!selectedText().isEmpty()) {
        menu.addAction(tr("Copy"), this, SLOT(copy()));
    } else {
        menu.addAction(tr("Reload"), this, SLOT(reload()));
    }

    if (copyAnchorAction == menu.exec(event->globalPos()))
        QApplication::clipboard()->setText(link.toString());
}

QVariant HelpViewer::loadResource(int type, const QUrl &name)
{
    QByteArray ba;
    if (type < 4) {
        const QHelpEngineCore &engine = HelpManager::instance().helpEngineCore();
        ba = engine.fileData(name);
        if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) {
            QImage image;
            image.loadFromData(ba, "svg");
            if (!image.isNull())
                return image;
        }
    }
    return ba;
}

#endif  // QT_NO_WEBKIT
<|endoftext|>