text:
/**
 * @file llconversationlog.h
 *
 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2012, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llagent.h"
#include "llavatarnamecache.h"
#include "llconversationlog.h"
#include "lldiriterator.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
// <FS:CR>
#include "llviewercontrol.h"
#include "fsfloaterim.h"
// </FS:CR>

#include <boost/foreach.hpp>
#include "boost/lexical_cast.hpp"

// <FS:CR> Commenting out, let the user decide
//const S32Days CONVERSATION_LIFETIME = (S32Days)30; // lifetime of LLConversation is 30 days by spec

struct ConversationParams : public LLInitParam::Block<ConversationParams>
{
	Mandatory<U64Seconds >	time;
	Mandatory<std::string>						timestamp;
	Mandatory<SessionType>						conversation_type;
	Mandatory<std::string>						conversation_name,
												history_filename;
	Mandatory<LLUUID>							session_id,
												participant_id;
	Mandatory<bool>								has_offline_ims;
};

/************************************************************************/
/*             LLConversation implementation                            */
/************************************************************************/

LLConversation::LLConversation(const ConversationParams& params)
:	mTime(params.time),
	mTimestamp(params.timestamp.isProvided() ? params.timestamp : createTimestamp(params.time)),
	mConversationType(params.conversation_type),
	mConversationName(params.conversation_name),
	mHistoryFileName(params.history_filename),
	mSessionID(params.session_id),
	mParticipantID(params.participant_id),
	mHasOfflineIMs(params.has_offline_ims)
{
	setListenIMFloaterOpened();
}

LLConversation::LLConversation(const LLIMModel::LLIMSession& session)
:	mTime(time_corrected()),
	mTimestamp(createTimestamp(mTime)),
	mConversationType(session.mSessionType),
	mConversationName(session.mName),
	mHistoryFileName(session.mHistoryFileName),
	mSessionID(session.isOutgoingAdHoc() ? session.generateOutgoingAdHocHash() : session.mSessionID),
	mParticipantID(session.mOtherParticipantID),
	mHasOfflineIMs(session.mHasOfflineMessage)
{
	setListenIMFloaterOpened();
}

LLConversation::LLConversation(const LLConversation& conversation)
{
	mTime				= conversation.getTime();
	mTimestamp			= conversation.getTimestamp();
	mConversationType	= conversation.getConversationType();
	mConversationName	= conversation.getConversationName();
	mHistoryFileName	= conversation.getHistoryFileName();
	mSessionID			= conversation.getSessionID();
	mParticipantID		= conversation.getParticipantID();
	mHasOfflineIMs		= conversation.hasOfflineMessages();

	setListenIMFloaterOpened();
}

LLConversation::~LLConversation()
{
	mIMFloaterShowedConnection.disconnect();
}

void LLConversation::updateTimestamp()
{
	mTime = (U64Seconds)time_corrected();
	mTimestamp = createTimestamp(mTime);
}

void LLConversation::onIMFloaterShown(const LLUUID& session_id)
{
	if (mSessionID == session_id)
	{
		mHasOfflineIMs = false;
	}
}

// static
const std::string LLConversation::createTimestamp(const U64Seconds& utc_time)
{
	std::string timeStr;
	LLSD substitution;
	substitution["datetime"] = (S32)utc_time.value();

	timeStr = "["+LLTrans::getString ("TimeMonth")+"]/["
				 +LLTrans::getString ("TimeDay")+"]/["
				 +LLTrans::getString ("TimeYear")+"] ["
				 +LLTrans::getString ("TimeHour")+"]:["
				 +LLTrans::getString ("TimeMin")+"]";

	LLStringUtil::format (timeStr, substitution);
	return timeStr;
}

bool LLConversation::isOlderThan(U32Days days) const
{
	U64Seconds now(time_corrected());
	U32Days age = now - mTime;

	return age > days;
}

void LLConversation::setListenIMFloaterOpened()
{
	// <FS:CR> [Firestorm Communications UI]
	//LLFloaterIMSession* floater = LLFloaterIMSession::findInstance(mSessionID);
	FSFloaterIM* floater = FSFloaterIM::findInstance(mSessionID);

	//bool offline_ims_visible = LLFloaterIMSession::isVisible(floater) && floater->hasFocus();
	bool offline_ims_visible = FSFloaterIM::isVisible(floater) && floater->hasFocus();

	// we don't need to listen for im floater with this conversation is opened
	// if floater is already opened or this conversation doesn't have unread offline messages
	if (mHasOfflineIMs && !offline_ims_visible)
	{
		//mIMFloaterShowedConnection = LLFloaterIMSession::setIMFloaterShowedCallback(boost::bind(&LLConversation::onIMFloaterShown, this, _1));
		mIMFloaterShowedConnection = FSFloaterIM::setIMFloaterShowedCallback(boost::bind(&LLConversation::onIMFloaterShown, this, _1));
		// </FS:CR>
	}
	else
	{
		mHasOfflineIMs = false;
	}
}

/************************************************************************/
/*             LLConversationLogFriendObserver implementation           */
/************************************************************************/

// Note : An LLSingleton like LLConversationLog cannot be an LLFriendObserver
// at the same time.
// This is because avatar observers are deleted by the observed object which
// conflicts with the way LLSingleton are deleted.

class LLConversationLogFriendObserver : public LLFriendObserver
{
public:
	LLConversationLogFriendObserver() {}
	virtual ~LLConversationLogFriendObserver() {}
	virtual void changed(U32 mask);
};

void LLConversationLogFriendObserver::changed(U32 mask)
{
	if (mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE))
	{
		LLConversationLog::instance().notifyObservers();
	}
}

/************************************************************************/
/*             LLConversationLog implementation                         */
/************************************************************************/

LLConversationLog::LLConversationLog() :
	mAvatarNameCacheConnection(),
	mLoggingEnabled(false)
{
}

void LLConversationLog::enableLogging(S32 log_mode)
{
	mLoggingEnabled = log_mode > 0;
	if (log_mode > 0)
	{
		mConversations.clear();
		loadFromFile(getFileName());
		LLIMMgr::instance().addSessionObserver(this);
		mNewMessageSignalConnection = LLIMModel::instance().addNewMsgCallback(boost::bind(&LLConversationLog::onNewMessageReceived, this, _1));

		mFriendObserver = new LLConversationLogFriendObserver;
		LLAvatarTracker::instance().addObserver(mFriendObserver);
	}
	else
	{
		saveToFile(getFileName());

		LLIMMgr::instance().removeSessionObserver(this);
		mNewMessageSignalConnection.disconnect();
		LLAvatarTracker::instance().removeObserver(mFriendObserver);
	}

	notifyObservers();
}

void LLConversationLog::logConversation(const LLUUID& session_id, BOOL has_offline_msg)
{
	const LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
	LLConversation* conversation = findConversation(session);

	if (session && session->mOtherParticipantID != gAgentID)
	{
    	if (conversation)
		{
			if(has_offline_msg)
			{
				updateOfflineIMs(session, has_offline_msg);
			}
			updateConversationTimestamp(conversation);
		}
		else
		{
			createConversation(session);
		}
	}
}

void LLConversationLog::createConversation(const LLIMModel::LLIMSession* session)
{
	if (session)
	{
		LLConversation conversation(*session);
		mConversations.push_back(conversation);

		if (LLIMModel::LLIMSession::P2P_SESSION == session->mSessionType)
		{
			if (mAvatarNameCacheConnection.connected())
			{
				mAvatarNameCacheConnection.disconnect();
			}
			mAvatarNameCacheConnection = LLAvatarNameCache::get(session->mOtherParticipantID, boost::bind(&LLConversationLog::onAvatarNameCache, this, _1, _2, session));
		}

		notifyObservers();
	}
}

void LLConversationLog::updateConversationName(const LLIMModel::LLIMSession* session, const std::string& name)
{
	if (!session)
	{
		return;
	}

	LLConversation* conversation = findConversation(session);
	if (conversation)
	{
		conversation->setConversationName(name);
		notifyParticularConversationObservers(conversation->getSessionID(), LLConversationLogObserver::CHANGED_NAME);
	}
}

void LLConversationLog::updateOfflineIMs(const LLIMModel::LLIMSession* session, BOOL new_messages)
{
	if (!session)
	{
		return;
	}

	LLConversation* conversation = findConversation(session);
	if (conversation)
	{
		conversation->setOfflineMessages(new_messages);
		notifyParticularConversationObservers(conversation->getSessionID(), LLConversationLogObserver::CHANGED_OfflineIMs);
	}
}

void LLConversationLog::updateConversationTimestamp(LLConversation* conversation)
{
	if (conversation)
	{
		conversation->updateTimestamp();
		notifyParticularConversationObservers(conversation->getSessionID(), LLConversationLogObserver::CHANGED_TIME);
	}
}

LLConversation* LLConversationLog::findConversation(const LLIMModel::LLIMSession* session)
{
	if (session)
	{
		const LLUUID session_id = session->isOutgoingAdHoc() ? session->generateOutgoingAdHocHash() : session->mSessionID;

		conversations_vec_t::iterator conv_it = mConversations.begin();
		for(; conv_it != mConversations.end(); ++conv_it)
		{
			if (conv_it->getSessionID() == session_id)
			{
				return &*conv_it;
			}
		}
	}

	return NULL;
}

void LLConversationLog::removeConversation(const LLConversation& conversation)
{
	conversations_vec_t::iterator conv_it = mConversations.begin();
	for(; conv_it != mConversations.end(); ++conv_it)
	{
		if (conv_it->getSessionID() == conversation.getSessionID() && conv_it->getTime() == conversation.getTime())
		{
			mConversations.erase(conv_it);
			notifyObservers();
			cache();
			return;
		}
	}
}

const LLConversation* LLConversationLog::getConversation(const LLUUID& session_id)
{
	conversations_vec_t::const_iterator conv_it = mConversations.begin();
	for(; conv_it != mConversations.end(); ++conv_it)
	{
		if (conv_it->getSessionID() == session_id)
		{
			return &*conv_it;
		}
	}

	return NULL;
}

void LLConversationLog::addObserver(LLConversationLogObserver* observer)
{
	mObservers.insert(observer);
}

void LLConversationLog::removeObserver(LLConversationLogObserver* observer)
{
	mObservers.erase(observer);
}

void LLConversationLog::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg)
{
	logConversation(session_id, has_offline_msg);
}

void LLConversationLog::cache()
{
	if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0)
	{
		saveToFile(getFileName());
	}
}

void LLConversationLog::getListOfBackupLogs(std::vector<std::string>& list_of_backup_logs)
{
	// get Users log directory
	std::string dirname = gDirUtilp->getPerAccountChatLogsDir();

	// add final OS dependent delimiter
	dirname += gDirUtilp->getDirDelimiter();

	// create search pattern
	std::string pattern = "conversation.log.backup*";

	LLDirIterator iter(dirname, pattern);
	std::string filename;
	while (iter.next(filename))
	{
		list_of_backup_logs.push_back(gDirUtilp->add(dirname, filename));
	}
}

void LLConversationLog::deleteBackupLogs()
{
	std::vector<std::string> backup_logs;
	getListOfBackupLogs(backup_logs);

	BOOST_FOREACH(const std::string& fullpath, backup_logs)
	{
		LLFile::remove(fullpath);
	}
}

bool LLConversationLog::moveLog(const std::string &originDirectory, const std::string &targetDirectory)
{

	std::string backupFileName;
	unsigned backupFileCount = 0;

	//Does the file exist in the current path, if it does lets move it
	if(LLFile::isfile(originDirectory))
	{
		//The target directory contains that file already, so lets store it
		if(LLFile::isfile(targetDirectory))
		{
			backupFileName = targetDirectory + ".backup";

			//If needed store backup file as .backup1 etc.
			while(LLFile::isfile(backupFileName))
			{
				++backupFileCount;
				backupFileName = targetDirectory + ".backup" + boost::lexical_cast<std::string>(backupFileCount);
			}

			//Rename the file to its backup name so it is not overwritten
			LLFile::rename(targetDirectory, backupFileName);
		}

		//Move the file from the current path to target path
		if(LLFile::rename(originDirectory, targetDirectory) != 0)
		{
			return false;
		}
	}

	return true;
}

void LLConversationLog::initLoggingState()
{
    if (gSavedPerAccountSettings.controlExists("KeepConversationLogTranscripts"))
    {
        LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get();
        S32 log_mode = keep_log_ctrlp->getValue();
        keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2));
        if (log_mode > 0)
        {
            enableLogging(log_mode);
        }
    }
}

std::string LLConversationLog::getFileName()
{
	std::string filename = "conversation";
	std::string log_address = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename);
	if (!log_address.empty())
	{
		log_address += ".log";
	}
	return log_address;
}

bool LLConversationLog::saveToFile(const std::string& filename)
{
	// <FS:Ansariel> Don't try to access
	if (gDirUtilp->getLindenUserDir().empty())
	{
		LL_INFOS() << "Can't access conversation log - no user directory set yet." << LL_ENDL;
		return false;
	}
	// </FS:Ansariel>

	if (!filename.size())
	{
		LL_WARNS() << "Call log list filename is empty!" << LL_ENDL;
		return false;
	}

	LLFILE* fp = LLFile::fopen(filename, "wb");
	if (!fp)
	{
		LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL;
		return false;
	}

	std::string participant_id;
	std::string conversation_id;

	conversations_vec_t::const_iterator conv_it = mConversations.begin();
	for (; conv_it != mConversations.end(); ++conv_it)
	{
		conv_it->getSessionID().toString(conversation_id);
		conv_it->getParticipantID().toString(participant_id);

		bool is_adhoc = (conv_it->getConversationType() == LLIMModel::LLIMSession::ADHOC_SESSION);
		std::string conv_name = is_adhoc ? conv_it->getConversationName() : LLURI::escape(conv_it->getConversationName());
		std::string file_name = is_adhoc ? conv_it->getHistoryFileName() : LLURI::escape(conv_it->getHistoryFileName());

		// examples of two file entries
		// [1343221177] 0 1 0 John Doe| 7e4ec5be-783f-49f5-71dz-16c58c64c145 4ec62a74-c246-0d25-2af6-846beac2aa55 john.doe|
		// [1343222639] 2 0 0 Ad-hoc Conference| c3g67c89-c479-4c97-b21d-32869bcfe8rc 68f1c33e-4135-3e3e-a897-8c9b23115c09 Ad-hoc Conference hash597394a0-9982-766d-27b8-c75560213b9a|
		fprintf(fp, "[%lld] %d %d %d %s| %s %s %s|\n",
				(S64)conv_it->getTime().value(),
				(S32)conv_it->getConversationType(),
				(S32)0,
				(S32)conv_it->hasOfflineMessages(),
				conv_name.c_str(),
				participant_id.c_str(),
				conversation_id.c_str(),
				file_name.c_str());
	}
	fclose(fp);
	return true;
}
bool LLConversationLog::loadFromFile(const std::string& filename)
{
	// <FS:Ansariel> Don't try to access
	if (gDirUtilp->getLindenUserDir().empty())
	{
		LL_INFOS() << "Can't access conversation log - no user directory set yet." << LL_ENDL;
		return false;
	}
	// </FS:Ansariel>

	if(!filename.size())
	{
		LL_WARNS() << "Call log list filename is empty!" << LL_ENDL;
		return false;
	}

	LLFILE* fp = LLFile::fopen(filename, "rb");
	if (!fp)
	{
		LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL;
		return false;
	}
	bool purge_required = false;
	// <FS:Beq> FIRE-30705 protect against silly display names that cause lines to exceed max string length
	// char buffer[MAX_STRING];
	static constexpr int BUFFER_1K { 1024 }; // long enough to handle the most extreme Unicode nonsense and some to spare
	char buffer[BUFFER_1K];
	// </FS:Beq>
	char conv_name_buffer[MAX_STRING];
	char part_id_buffer[MAX_STRING];
	char conv_id_buffer[MAX_STRING];
	char history_file_name[MAX_STRING];
	S32 has_offline_ims;
	S32 stype;
	S64 time;
	// before CHUI-348 it was a flag of conversation voice state
	int prereserved_unused;

	// <FS:Beq/> FIRE-30705 protect against silly display names that cause lines to exceed max string length
	// while (!feof(fp) && fgets(buffer, MAX_STRING, fp))
	// {
	// 	conv_name_buffer[0] = '\0';
	// 	part_id_buffer[0]	= '\0';
	// 	conv_id_buffer[0]	= '\0';
	memset( buffer, '\0', BUFFER_1K );
	while (!feof(fp) && fgets(buffer, BUFFER_1K, fp))
	{
		// force blank for added safety
		memset( conv_name_buffer, '\0', MAX_STRING );
		memset( part_id_buffer, '\0', MAX_STRING );
		memset( conv_id_buffer, '\0', MAX_STRING );
		memset( history_file_name, '\0', MAX_STRING );
	// </FS:Beq>
		sscanf(buffer, "[%lld] %d %d %d %[^|]| %s %s %[^|]|",
				&time,
				&stype,
				&prereserved_unused,
				&has_offline_ims,
				conv_name_buffer,
				part_id_buffer,
				conv_id_buffer,
				history_file_name);

		bool is_adhoc = ((SessionType)stype == LLIMModel::LLIMSession::ADHOC_SESSION);
		std::string conv_name = is_adhoc ? conv_name_buffer : LLURI::unescape(conv_name_buffer);
		std::string file_name = is_adhoc ? history_file_name : LLURI::unescape(history_file_name);

		ConversationParams params;
		params.time(LLUnits::Seconds::fromValue(time))
			.conversation_type((SessionType)stype)
			.has_offline_ims(has_offline_ims)
			.conversation_name(conv_name)
			.participant_id(LLUUID(part_id_buffer))
			.session_id(LLUUID(conv_id_buffer))
			.history_filename(file_name);

		LLConversation conversation(params);

		// CHUI-325
		// The conversation log should be capped to the last 30 days. Conversations with the last utterance
		// being over 30 days old should be purged from the conversation log text file on login.
		// <FS:CR> Shut up, CHUI-325 Let the user decide.
		U32 CONVERSATION_LIFETIME = gSavedSettings.getU32("FSConversationLogLifetime");
		if (conversation.isOlderThan( U32Days(CONVERSATION_LIFETIME) ) )
		{
			purge_required = true;
			continue;
		}

		mConversations.push_back(conversation);
		memset( buffer, '\0', BUFFER_1K ); // <FS:Beq> FIRE-30705 clear buffer down
	}
	fclose(fp);

	if(purge_required)
	{
		LLFile::remove(filename);
		cache();
	}

	notifyObservers();
	return true;
}

void LLConversationLog::notifyObservers()
{
	std::set<LLConversationLogObserver*>::const_iterator iter = mObservers.begin();
	for (; iter != mObservers.end(); ++iter)
	{
		(*iter)->changed();
	}
}

void LLConversationLog::notifyParticularConversationObservers(const LLUUID& session_id, U32 mask)
{
	std::set<LLConversationLogObserver*>::const_iterator iter = mObservers.begin();
	for (; iter != mObservers.end(); ++iter)
	{
		(*iter)->changed(session_id, mask);
	}
}

void LLConversationLog::onNewMessageReceived(const LLSD& data)
{
	const LLUUID session_id = data["session_id"].asUUID();
	logConversation(session_id, false);
}

void LLConversationLog::onAvatarNameCache(const LLUUID& participant_id, const LLAvatarName& av_name, const LLIMModel::LLIMSession* session)
{
	mAvatarNameCacheConnection.disconnect();
	updateConversationName(session, av_name.getCompleteName());
}

void LLConversationLog::onClearLog()
{
	LLNotificationsUtil::add("PreferenceChatClearLog", LLSD(), LLSD(), boost::bind(&LLConversationLog::onClearLogResponse, this, _1, _2));
}

void LLConversationLog::onClearLogResponse(const LLSD& notification, const LLSD& response)
{
	if (0 == LLNotificationsUtil::getSelectedOption(notification, response))
	{
		mConversations.clear();
		notifyObservers();
		cache();
		deleteBackupLogs();
	}
}

max_stars_repo_name: SaladDais/LLUDP-Encryption

max_issues_repo_name: SaladDais/LLUDP-Encryption

max_forks_repo_name: SaladDais/LLUDP-Encryption


text:
/*
 * hierarchical_optimizer.tpp
 *
 *  Created on: Apr 25, 2019
 *      Author: Gregory Kramida
 *   Copyright: 2019 Gregory Kramida
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
#pragma once

//libraries
#include <Eigen/Eigen>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>

//local
#include "hierarchical_optimizer.hpp"
#include "../nonrigid_optimization/hierarchical/optimizer_with_telemetry.hpp"
#include "eigen_numpy.hpp"
#include "../math/typedefs.hpp"

namespace bp = boost::python;
namespace impl = nonrigid_optimization::hierarchical;
namespace eig = Eigen;

namespace python_export {
namespace hierarchical_optimizer {

template<typename ScalarContainer, typename VectorContainer>
void export_algorithms(const char* suffix) {
	auto sufy = [&](const char* name) {
		return (std::string(name) + std::string(suffix));
	};
	bp::scope outer =
			bp::class_<impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>>(sufy("HierarchicalOptimizer").c_str(),
					bp::init<
							bp::optional<
									bool, bool,
									int, float, int, float,
									float, float, eig::VectorXf,
									typename impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::ResamplingStrategy,
									typename impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters,
									typename impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::LoggingParameters> >(
							bp::args("tikhonov_term_enabled",
									"gradient_kernel_enabled",

									"maximum_chunk_size",
									"rate",
									"maximum_iteration_count",
									"maximum_warp_update_threshold",

									"data_term_amplifier",
									"tikhonov_strength",
									"kernel",

									"resampling_strategy",

									"verbosity_parameters",
									"logging_parameters"
									)))
					.def("optimize", &impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::optimize,
					"Find optimal warp to map given live SDF to given canonical SDF",
					bp::args("canonical_field", "live_field"))
					.def("get_per_level_convergence_reports",
					&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::get_per_level_convergence_reports)
					.def("get_per_level_iteration_data",
					&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::get_per_level_iteration_data)
					;
	bp::enum_<typename impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::ResamplingStrategy>(
			"ResamplingStrategy")
			.value("NEAREST_AND_AVERAGE",
			impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::ResamplingStrategy::NEAREST_AND_AVERAGE)
			.value("LINEAR",
			impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::ResamplingStrategy::LINEAR);
	bp::class_<typename impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters>(
			"VerbosityParameters",
			"Parameters that control verbosity to stdout. "
					"Assumes being used in an \"immutable\" manner, i.e. just a structure that holds values",
			bp::init<bp::optional<bool, bool, bool, bool, bool>>(
					bp::args(/*"self",*/
					"print_max_warp_update",
							"print_iteration_mean_tsdf_difference",
							"print_iteration_std_tsdf_difference",
							"print_iteration_data_energy",
							"print_iteration_tikhonov_energy")))
			.add_property("print_iteration_max_warp_update",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters
			::print_iteration_max_warp_update)
			.add_property("print_iteration_mean_tsdf_difference",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters
			::print_iteration_mean_tsdf_difference)
			.add_property("print_iteration_std_tsdf_difference",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters
			::print_iteration_std_tsdf_difference)
			.add_property("print_iteration_data_energy",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters
			::print_iteration_data_energy)
			.add_property("print_iteration_tikhonov_energy",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters
			::print_iteration_tikhonov_energy)
			//============================================
			.add_property("print_per_iteration_info",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters
			::print_per_iteration_info)
			.add_property("print_per_level_info",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::VerbosityParameters
			::print_per_level_info)
			;

	bp::class_<typename impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::LoggingParameters>(
			"LoggingParameters",
			"Parameters that control what intermediate results are gathered during run",
			bp::init<bp::optional<bool, bool>>(
					bp::args(
							"collect_per_level_convergence_reports",
							"collect_per_level_iteration_data"
							)))
			.add_property("collect_per_level_convergence_reports",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::LoggingParameters::collect_per_level_convergence_reports)
			.add_property("collect_per_level_iteration_data",
			&impl::OptimizerWithTelemetry<ScalarContainer, VectorContainer>::LoggingParameters::collect_per_level_iteration_data)
			;

}

} // namespace hierarchical_optimizer
} // namespace python_export

ext: tpp

max_stars_repo_name: Algomorph/LevelSetFusionExperimentsCPP

max_issues_repo_name: Algomorph/LevelSetFusionExperimentsCPP

max_forks_repo_name: Algomorph/LevelSetFusionExperimentsCPP


text:
// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

#include <boost/hana/detail/variadic/drop_into.hpp>

#include <boost/hana/assert.hpp>
#include <boost/hana/equal.hpp>

#include <laws/base.hpp>
namespace hana = boost::hana;
namespace vd = hana::detail::variadic;
using hana::test::ct_eq;

struct non_pod { virtual ~non_pod() { } };

int main() {
    hana::test::_injection<0> f{};

    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<0>(f)(),
        f()
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<0>(f)(ct_eq<0>{}),
        f(ct_eq<0>{})
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<0>(f)(ct_eq<0>{}, ct_eq<1>{}),
        f(ct_eq<0>{}, ct_eq<1>{})
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<0>(f)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
        f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
    ));

    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<1>(f)(ct_eq<0>{}),
        f()
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<1>(f)(ct_eq<0>{}, ct_eq<1>{}),
        f(ct_eq<1>{})
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<1>(f)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
        f(ct_eq<1>{}, ct_eq<2>{})
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<1>(f)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
        f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
    ));

    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<2>(f)(ct_eq<0>{}, ct_eq<1>{}),
        f()
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<2>(f)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
        f(ct_eq<2>{})
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<2>(f)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
        f(ct_eq<2>{}, ct_eq<3>{})
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        vd::drop_into<2>(f)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{}),
        f(ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{})
    ));

    // make sure we can use non-pods
    vd::drop_into<1>(f)(ct_eq<0>{}, non_pod{});
    vd::drop_into<1>(f)(non_pod{}, ct_eq<1>{});
}

ext: cpp


text:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "starspace.h"
#include <iostream>
#include <boost/algorithm/string/predicate.hpp>

using namespace std;
using namespace starspace;

int main(int argc, char** argv) {
  shared_ptr<Args> args = make_shared<Args>();
  args->parseArgs(argc, argv);
  args->printArgs();

  StarSpace sp(args);
  if (args->isTrain) {
    if (!args->initModel.empty()) {
      if (boost::algorithm::ends_with(args->initModel, ".tsv")) {
        sp.initFromTsv(args->initModel);
      } else {
        sp.initFromSavedModel(args->initModel);
        cout << "------Loaded model args:\n";
        args->printArgs();
      }
    } else {
      sp.init();
    }
    sp.train();
    sp.saveModel(args->model);
    sp.saveModelTsv(args->model + ".tsv");
  } else {
    if (boost::algorithm::ends_with(args->model, ".tsv")) {
      sp.initFromTsv(args->model);
    } else {
      sp.initFromSavedModel(args->model);
      cout << "------Loaded model args:\n";
      args->printArgs();
    }
    sp.evaluate();
  }

  return 0;
}


text:
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "StateMachine.hpp"

#include <glog/logging.h>
#include <boost/foreach.hpp>

#include "Status.hpp"

StateMachine::StateMachine()
{
  //TODO : change this to RECONCILING_TASKS after we can put the taskMap to zookeeper
  currentPhase = Phase::BOOTSTRAP_MON;
}

StateMachine::StateMachine(Config* _config) : config(_config)
{
  //TODO : change this to RECONCILING_TASKS after we can put the taskMap to zookeeper
  currentPhase = Phase::BOOTSTRAP_MON;
  defaultHostConfig = HostConfig(_config);
}

StateMachine::~StateMachine(){}

void StateMachine::addStagingTask(
      string taskId,
      string executorId,
      TaskType taskType,
      string hostname,
      string slaveId)
{
  Status currentStatus = Status::STAGING;
  switch (taskType) {
    case TaskType::MON:
      monStagingNum++;
      break;
    case TaskType::OSD:
      osdStagingNum++;
      break;
    case TaskType::RADOSGW:
      radosgwStagingNum++;
      break;
  }
  TaskState taskState(
        taskId,
        executorId,
        taskType,
        hostname,
        slaveId,
        currentStatus);
  taskMap[taskId] = taskState;
}
//TODO: Optimize this. How about this? define a inner clss Counter and
//use a hashmap<TaskType,Counters> to unify the counters update
void StateMachine::updateCounters(
    TaskType taskType,
    Status oldStatus,
    Status newStatus)
{
  if ((oldStatus == Status::STAGING || oldStatus == Status::STARTING)
       && newStatus == Status::RUNNING) {
    switch (taskType) {
      case TaskType::MON:
        monRunningNum++;
        monStagingNum--;
        break;
      case TaskType::OSD:
        osdRunningNum++;
        osdStagingNum--;
        break;
      case TaskType::RADOSGW:
        radosgwRunningNum++;
        radosgwStagingNum--;
      break;
    }
  }

  if (oldStatus == Status::STAGING && newStatus == Status::FAILED) {
    switch (taskType) {
      case TaskType::MON:
        monStagingNum--;
        break;
      case TaskType::OSD:
        osdStagingNum--;
        break;
      case TaskType::RADOSGW:
        radosgwStagingNum--;
      break;
    }
  }
  if (oldStatus == Status::RUNNING && newStatus == Status::FAILED) {
    switch (taskType) {
      case TaskType::MON:
        monRunningNum--;
        break;
      case TaskType::OSD:
        osdRunningNum--;
        break;
      case TaskType::RADOSGW:
        radosgwRunningNum--;
      break;
    }
  }
  printCounters();
}

void StateMachine::printCounters()
{
  LOG(INFO) <<"Current Counters:";
  LOG(INFO) <<"monRunningNum: " <<monRunningNum;
  LOG(INFO) <<"monStagingNum: " <<monStagingNum;
  LOG(INFO) <<"osdRunningNum: " <<osdRunningNum;
  LOG(INFO) <<"osdStagingNum: " <<osdStagingNum;
  LOG(INFO) <<"radosgwRunningNum: " <<radosgwRunningNum;
  LOG(INFO) <<"radosgwStagingNum: " <<radosgwStagingNum;

}

void StateMachine::moveState()
{
  if (monRunningNum < 1) {
    currentPhase = Phase::BOOTSTRAP_MON;
  } else if (osdRunningNum < 3) {
    currentPhase = Phase::BOOTSTRAP_OSD;
  } else if (radosgwRunningNum < 1) {
    currentPhase = Phase::BOOTSTRAP_RADOSGW;
  } else {
    currentPhase = Phase::WAINTING_REQUEST;
  }
  LOG(INFO) << "After moveState: "
      << static_cast<int>(currentPhase);
}

void StateMachine::decreaseOSDIndex()
{
  osdIndex--;
}

//TODO: how about this ? merge the three updateTaskTo<*> functions
void StateMachine::updateTaskToRunning(string taskId)
{
  auto it = taskMap.find(taskId);
  if (it != taskMap.end()) {
    LOG(INFO) << "Update the taskState to RUNNING for " << taskId;
    TaskState& taskState = taskMap[taskId];
    updateCounters(taskState.taskType,
        taskState.currentStatus,
        Status::RUNNING);
    taskState.currentStatus = Status::RUNNING;
    LOG(INFO) << "After update: ";
    LOG(INFO) << taskState.toString();
    moveState();
  } else {
    LOG(ERROR) << "No value found in taskMap with key: " << taskId;
  }

}

void StateMachine::updateTaskToWaitingOSDID(string taskId)
{
  auto it = taskMap.find(taskId);
  if (it != taskMap.end()) {
    LOG(INFO) << "Update the taskState to WAITING_OSDID for " << taskId;
    TaskState& taskState = taskMap[taskId];
    updateCounters(taskState.taskType,
        taskState.currentStatus,
        Status::WAITING_OSDID);
    taskState.currentStatus = Status::WAITING_OSDID;
    LOG(INFO) << "After update: ";
    LOG(INFO) << taskState.toString();
  } else {
    LOG(ERROR) << "No value found in taskMap with key: " << taskId;
  }

}

void StateMachine::updateTaskToStarting(string taskId)
{
  auto it = taskMap.find(taskId);
  if (it != taskMap.end()) {
    LOG(INFO) << "Update the taskState to STARTING for " << taskId;
    TaskState& taskState = taskMap[taskId];
    updateCounters(taskState.taskType,
        taskState.currentStatus,
        Status::STARTING);
    taskState.currentStatus = Status::STARTING;
    LOG(INFO) << "After update: ";
    LOG(INFO) << taskState.toString();
  } else {
    LOG(ERROR) << "No value found in taskMap with key: " << taskId;
  }
}

void StateMachine::updateTaskToFailed(string taskId)
{
  auto it = taskMap.find(taskId);
  if (it != taskMap.end()) {
    LOG(INFO) << "Update the taskState to Failed for " << taskId;
    TaskState& taskState = taskMap[taskId];
    updateCounters(taskState.taskType,
        taskState.currentStatus,
        Status::FAILED);
    taskState.currentStatus = Status::FAILED;
    LOG(INFO) << "After update: ";
    LOG(INFO) << taskState.toString();
    moveState();
  } else {
    LOG(ERROR) << "No value found in taskMap with key: " << taskId;
  }

}

bool StateMachine::nextMove(TaskType& taskType, int& token, string hostName)
{
  Phase currentPhase = getCurrentPhase();
  HostConfig* hostconfig = getConfig(hostName);
  //TODO:
  //put the check here will reduce efficiency since a host can launch Disk task and
  //all tasks expecpt OSD task in one launchTask(). But if we put this check only in OSD phase,
  //then we need to add the disk TaskInfo together with other tasks in one
  //vector<TaskInfo> to use the same offer. Or Mesos will report error that
  //this offer is invalid since other task have used it.
  //will implement this later.
  if (hostconfig->isPreparingDisk()) {
    LOG(INFO) << hostName << " is preparing disks, need to decline this offer";
    return false;
  }
  switch (currentPhase) {
    case Phase::RECONCILING_TASKS:
    case Phase::BOOTSTRAP_MON:
      taskType = TaskType::MON;
      if (monStagingNum < 1 && (monStagingNum + monRunningNum) < 1) {
        token = monIndex++;
        return true;
      } else {
        return false;
      }
      break;
    case Phase::BOOTSTRAP_OSD:
      taskType = TaskType::OSD;
      if (osdStagingNum < 3 && (osdStagingNum + osdRunningNum) < 3) {
        token = osdIndex++;
        return true;
      } else {
        return false;
      }
      break;
    case Phase::BOOTSTRAP_RADOSGW:
      taskType = TaskType::RADOSGW;
      if (radosgwStagingNum < 1) {
        token = radosgwIndex++;
        return true;
      } else {
        return false;
      }
      break;
    case Phase::WAINTING_REQUEST:
      taskType = TaskType::OSD;
      token = osdIndex++;
      return true;
      break;
  }
  return false;
}

void StateMachine::addConfig(string hostname)
{
  auto it = hostConfigMap.find(hostname);
  if (it != hostConfigMap.end()) {
    HostConfig hc = hostConfigMap[hostname];
    hc.reload();
  } else {
    HostConfig hc(hostname);
    LOG(INFO)<<"add this host config:";
    LOG(INFO)<<hc.toString();
    hostConfigMap[hostname] = hc;
  }
}

HostConfig* StateMachine::getConfig(string hostname)
{
  auto it = hostConfigMap.find(hostname);
  if (it != hostConfigMap.end()) {
    HostConfig* hc = &hostConfigMap[hostname];
    return hc;
  } else {
    return &defaultHostConfig;
  }
}

TaskState StateMachine::getInitialMon()
{
  TaskState taskState;
  string prefix = "mon0";
  //TODO: use BOOST_FOREACH to optimize this
  for ( auto it = taskMap.begin(); it != taskMap.end(); it++) {
    taskState = static_cast<TaskState>(it->second);
    string taskId = taskState.taskId;
    if ( taskId.substr(0, prefix.size()) == prefix) {
      return taskState;
    }
  }
  return taskState;
}

vector<TaskState> StateMachine::getWaitingOSDTask()
{
  vector<TaskState> vc;
  TaskState taskState;
  for ( auto it = taskMap.begin(); it != taskMap.end(); it++) {
    taskState = static_cast<TaskState>(it->second);
    if (taskState.taskType == TaskType::OSD
        && taskState.currentStatus == Status::WAITING_OSDID){
      vc.push_back(taskState);
    }
  }
  return vc;
}

void StateMachine::addPendingOSDID(int osdID)
{
  pendingOSDID.push_back(osdID);
}

vector<int>* StateMachine::getPendingOSDID()
{
  return &pendingOSDID;
}

Phase StateMachine::getCurrentPhase()
{
  return currentPhase;
}

max_stars_repo_name: vivint-smarthome/ceph-mesos

max_issues_repo_name: vivint-smarthome/ceph-mesos

max_forks_repo_name: vivint-smarthome/ceph-mesos


text:
#include <Python.h>
#include <boost/python.hpp>
#include "FabMapVocabluary.h"
#include "ChowLiuTree.h"
#include "openFABMAPPython.h"

BOOST_PYTHON_MODULE(openFABMAP)
{
    boost::python::class_<pyof2::FabMapVocabluary, std::shared_ptr<pyof2::FabMapVocabluary>>(
            "Vocabluary", boost::python::no_init);

    boost::python::class_<pyof2::FabMapVocabluaryBuilder, std::shared_ptr<pyof2::FabMapVocabluaryBuilder>>(
            "VocabluaryBuilder", boost::python::init<boost::python::dict>())
        .def("add_training_image", &pyof2::FabMapVocabluaryBuilder::addTrainingImage)
        .def("build_vocabluary", &pyof2::FabMapVocabluaryBuilder::buildVocabluary);

    boost::python::class_<pyof2::ChowLiuTree, std::shared_ptr<pyof2::ChowLiuTree>>(
            "ChowLiuTree", boost::python::init<std::shared_ptr<pyof2::FabMapVocabluary>, boost::python::dict>())
        .def("add_training_image", &pyof2::ChowLiuTree::addTrainingImage)
        .def("build_chow_liu_tree", &pyof2::ChowLiuTree::buildChowLiuTree)
        .def("save", &pyof2::ChowLiuTree::save)
        .def("load", &pyof2::ChowLiuTree::load)
        .staticmethod("load");

    boost::python::class_<pyof2::OpenFABMAPPython, std::shared_ptr<pyof2::OpenFABMAPPython>>(
            "OpenFABMAP", boost::python::init<
                std::shared_ptr<pyof2::ChowLiuTree>,
                boost::python::dict>())
        .def("load_and_process_image", &pyof2::OpenFABMAPPython::loadAndProcessImage)
        .def("get_last_match", &pyof2::OpenFABMAPPython::getLastMatch)
        .def("get_all_loop_closures", &pyof2::OpenFABMAPPython::getAllLoopClosures);
}

max_stars_repo_name: mttgdd/openfabmap-python

max_issues_repo_name: mttgdd/openfabmap-python

max_forks_repo_name: mttgdd/openfabmap-python


text: #include <boost/units/physical_dimensions/conductivity.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
// Part of the Jade Engine -- Copyright (c) Christian Neumüller 2012--2013
// This file is subject to the terms of the BSD 2-Clause License.
// See LICENSE.txt or http://opensource.org/licenses/BSD-2-Clause

#include "TileCollideableGroup.hpp"

#include "comp/TileCollisionComponent.hpp"
#include "compsys/Entity.hpp"
#include "Logfile.hpp"
#include "Tilemap.hpp"

#include <array>
#include <boost/current_function.hpp>
#include <functional>
#include <unordered_set>

TileCollideableInfo::TileCollideableInfo(jd::Tilemap& tilemap):
    m_tilemap(tilemap)
{
}

void TileCollideableInfo::setProxy(unsigned tileId, TileCollisionComponent* proxy)
{
    if (!proxy) {
        std::size_t const erasedCount = m_proxyEntities.erase(tileId);
        assert(erasedCount < 2);
        if (!erasedCount)
            LOG_W("Attempt to unset a proxy, which was not set.");
    } else if (!m_proxyEntities.insert(std::make_pair(tileId, proxy)).second)
        throw std::logic_error(
            BOOST_CURRENT_FUNCTION +
            std::string(": cannot assign proxy entity: already assigned"));
}

 WeakRef<TileCollisionComponent> TileCollideableInfo::proxy(unsigned tileId)
{
    auto const it = m_proxyEntities.find(tileId);
    if (it != m_proxyEntities.end())
        return it->second;
    return static_cast<Component*>(nullptr);
}

void TileCollideableInfo::setColliding(Vector3u pos, TileCollisionComponent* e)
{
    auto const it = m_entities.find(pos);
    bool const found = it != m_entities.end();
    if (e) {
        if (found) {
            it->second->notifyOverride(pos, *e);
            it->second = e;
        } else {
            bool const success = m_entities.insert(std::make_pair(pos, e)).second;
            assert(success);
            (void)success;
        }
    } else if (found) {
        m_entities.erase(pos);
    } else {
        LOG_W("Attempt to unregister a TileCollisionComponent which was not registered.");
    }
}

 WeakRef<TileCollisionComponent> TileCollideableInfo::colliding(Vector3u pos)
{
    auto const it = m_entities.find(pos);
    if (it != m_entities.end())
        return it->second;
    return static_cast<Component*>(nullptr);
}

Vector3u TileCollideableInfo::mapsize() const
{
    return m_tilemap.size();
}

Collision TileCollideableInfo::makeCollision(
    Vector3u pos, Entity* e, sf::FloatRect const& r)
{
    auto const iEntity = m_entities.find(pos);
    sf::Vector2i const ipos2(static_cast<int>(pos.x), static_cast<int>(pos.y));
    if (iEntity != m_entities.end()) {
        if (e)
            iEntity->second->notifyCollision(pos, *e, r);
         return Collision(
            iEntity->second->parent(),
            m_tilemap.globalTileRect(ipos2));
    } else {
        unsigned const tileId = m_tilemap[pos];
        auto const iProxy = m_proxyEntities.find(tileId);
        if (iProxy != m_proxyEntities.end()) {
            if (e)
                iProxy->second->notifyCollision(pos, *e, r);
            return Collision(
                iProxy->second->parent(),
                m_tilemap.globalTileRect(ipos2));
        }
    } // if no entity at pos registered
    return Collision();
}

std::vector<Collision> TileCollideableInfo::colliding(
    sf::FloatRect const& r, Entity* e, std::vector<Vector3u>* positions)
{
    sf::Vector2u begin;
    sf::Vector2u last;
    std::size_t const intersectingCount = mapCorners(r, begin, last);

    std::vector<Collision> result;
    if (intersectingCount <= 0)
        return result;
    result.reserve(intersectingCount);

    Vector3u pos;
    for (pos.z = 0; pos.z < m_tilemap.size().z; ++pos.z) {
        for (pos.x = begin.x; pos.x <= last.x; ++pos.x) {
            for (pos.y = begin.y; pos.y <= last.y; ++pos.y) {
                auto const c = makeCollision(pos, e, r);
                if (c.entity) {
                    if (positions)
                        positions->push_back(pos);
                    result.push_back(c);
                }
            } // for y
        } // for x
    } // for z
    return result;
}

namespace {
    std::array<sf::Vector2i, 8> surroundingTiles(sf::Vector2i p)
    {
        std::array<sf::Vector2i, 8> result;
        result.fill(p);

        // 012
        // 3p4
        // 567
        --result[0].x; --result[0].y;
                       --result[1].y;
        ++result[2].x; --result[2].y;
        --result[3].x;
        ++result[4].x;
        --result[5].x; ++result[5].y;
                       ++result[6].y;
        ++result[7].x; ++result[7].y;

        return result;
    }
}

std::vector<Collision> TileCollideableInfo::colliding(
    sf::Vector2f gp1, sf::Vector2f gp2, std::vector<Vector3u>* positions)
{
    sf::Vector2u p1;
    sf::Vector2u p2;

    std::vector<Collision> result;

    if (!clipToMap(gp1, gp2, p1, p2))
        return result;

    result.reserve(static_cast<std::size_t>(
        jd::math::abs(static_cast<sf::Vector2f>(p2 - p1)) * mapsize().z));

    sf::Vector2u pos = p1;
    sf::Vector2u lastPos = p1;
    for (;;) {
        Vector3u idx(pos.x, pos.y, 0);
        for (; idx.z < m_tilemap.size().z; ++idx.z) {
            auto const c = makeCollision(idx, nullptr, sf::FloatRect());
            if (c.entity) {
                if (positions)
                    positions->push_back(idx);
                result.push_back(c);
            }
        }
        bool found;
        sf::Vector2u const nextPos = findNext(pos, lastPos, p1, p2, &found);
        if (!found)
            break;

        lastPos = pos;
        pos = nextPos;
    }
    return result;
}

bool TileCollideableInfo::clipToMap(
    sf::Vector2f lineStart, sf::Vector2f lineEnd,
    sf::Vector2u& clipStart, sf::Vector2u& clipEnd)
{
    clipStart = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(lineStart));
    clipEnd = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(lineEnd));

    if (!jd::clipLine(clipStart, clipEnd, sf::Rect<unsigned>(
        0, 0, m_tilemap.size().x - 1, m_tilemap.size().y - 1)))
        return false;
    return true;
}

sf::Vector2u TileCollideableInfo::findNext(
    sf::Vector2u pos, sf::Vector2u oldPos_,
    sf::Vector2u lineStart, sf::Vector2u lineEnd,
    bool* found)
{
    sf::Vector2i const oldPos(oldPos_);
    auto const surrounding(surroundingTiles(static_cast<sf::Vector2i>(pos)));
    for (sf::Vector2i next : surrounding) {
        using jd::vec_cast;
        if (next != oldPos &&
            m_tilemap.isValidPosition(jd::vec2to3(next, 0)) &&
            jd::onLine(vec_cast<int>(lineStart), vec_cast<int>(lineEnd), next)
        ) {
            if (found)
                *found = true;
            return static_cast<sf::Vector2u>(next);
        }
    }
    if (found)
        *found = false;
    return pos;
}

std::size_t TileCollideableInfo::mapCorners(
    sf::FloatRect const& r,
    sf::Vector2u& begin_out,
    sf::Vector2u& last_out)
{
    auto begin = m_tilemap.tilePosFromGlobal(jd::topLeft(r));
    begin.x = std::max(begin.x, 0);
    begin.y = std::max(begin.y, 0);
    auto last = m_tilemap.tilePosFromGlobal(jd::bottomRightIn(r));
    auto isize = jd::vec_cast<int>(m_tilemap.size());
    last.x = std::min(last.x, isize.x - 1);
    last.y = std::min(last.y, isize.y - 1);

    int intersectingPerLayer = (last.x - begin.x + 1) * (last.y - begin.y + 1);
    if (intersectingPerLayer <= 0) {
        return 0;
    }

    begin_out = jd::vec_cast<unsigned>(begin);
    last_out = jd::vec_cast<unsigned>(last);

    return static_cast<unsigned>(intersectingPerLayer) * m_tilemap.size().z;
}

template <typename Pred>
std::vector<Collision> filter(
        std::vector<Collision>&& collisions,
        std::vector<Vector3u>&& positions,
        Pred pred)
{
    std::size_t i = 0;
    while (i < collisions.size()) {
        if (!pred(positions[i].z)) {
            auto off = static_cast<std::ptrdiff_t>(i);
            collisions.erase(collisions.begin() + off);
            positions.erase(positions.begin() + off);
        } else {
            ++i;
        }
    }
    return collisions;
}

TileLayersCollideableGroup::TileLayersCollideableGroup(
    TileCollideableInfo* data,
    unsigned firstLayer, unsigned endLayer):
    m_data(data),
    m_firstLayer(firstLayer),
    m_endLayer(endLayer)
{
    // must call setEndLayer before setFirstLayer
    // to check if map has enough layers
    setEndLayer(endLayer);
    setFirstLayer(firstLayer);
}

void TileLayersCollideableGroup::setFirstLayer(unsigned layer)
{
    if (layer >= m_endLayer)
        throw std::out_of_range("first layer >= end layer");
    assert(layer < m_data->mapsize().z);
    m_firstLayer = layer;
}

void TileLayersCollideableGroup::setEndLayer(unsigned layer)
{
    if (layer <= m_firstLayer)
        throw std::out_of_range("end layer <= first layer");
    if (layer >= m_data->mapsize().z)
        throw std::out_of_range("end layer >= count of layers");
    m_endLayer = layer;
}

std::vector<Collision> TileLayersCollideableGroup::colliding(
    sf::FloatRect const& r, Entity* e)
{
    if (m_firstLayer == m_endLayer) // was clear() called?
        return std::vector<Collision>();
    if (isUnfiltered())
        return m_data->colliding(r, e);

    std::vector<Vector3u> positions;
    return filter(
        m_data->colliding(r, e, &positions),
        std::move(positions),
        std::bind(&TileLayersCollideableGroup::layerInRange, this, std::placeholders::_1));
}

std::vector<Collision> TileLayersCollideableGroup::colliding(
    sf::Vector2f lineStart, sf::Vector2f lineEnd)
{
    if (m_firstLayer == m_endLayer) // was clear() called?
        return std::vector<Collision>();
    if (isUnfiltered())
        return m_data->colliding(lineStart, lineEnd);

    std::vector<Vector3u> positions;
    return filter(
        m_data->colliding(lineStart, lineEnd, &positions),
        std::move(positions),
        std::bind(&TileLayersCollideableGroup::layerInRange, this, std::placeholders::_1));
}

bool TileLayersCollideableGroup::isUnfiltered() const {
    return m_firstLayer == 0 && m_endLayer == m_data->mapsize().z;
}

std::vector<Collision> TileStackCollideableGroup::colliding(
    sf::FloatRect const& r, Entity* e)
{
    std::vector<Collision> result;

    if (!m_filter)
        return result;

    sf::Vector2u begin;
    sf::Vector2u last;
    std::size_t const intersectingCount = m_data->mapCorners(r, begin, last);

    if (intersectingCount <= 0)
        return result;
    result.reserve(intersectingCount);

    Vector3u pos;
    for (pos.x = begin.x; pos.x <= last.x; ++pos.x) {
        for (pos.y = begin.y; pos.y <= last.y; ++pos.y) {
            std::vector<Info> stack;
            auto const pos2 = jd::vec3to2(pos);

            for (pos.z = 0; pos.z < m_data->mapsize().z; ++pos.z) {
                auto c = m_data->makeCollision(pos, e, r);
                if (c.entity)
                    stack.emplace_back(m_data->tilemap()[pos], c.entity);
                else
                    stack.emplace_back();
            } // for z
            m_filter(pos2, stack);
            processStack(
                stack,
                result,
                m_data->tilemap().globalTileRect(sf::Vector2i(pos2)));
        } // for y
    } // for x
    return result;
}

void TileStackCollideableGroup::processStack(
    std::vector<Info>& stack, std::vector<Collision>& result,
    sf::FloatRect const& r) const
{
    for (auto const& info: stack) {
        if (!info.discard && info.entity.valid())
            result.emplace_back(info.entity.getOpt(), r);
    } // for info: stack
}

std::vector<Collision> TileStackCollideableGroup::colliding(
    sf::Vector2f gp1, sf::Vector2f gp2)
{
    std::vector<Collision> result;

    if (!m_filter)
        return result;

    sf::Vector2u p1;
    sf::Vector2u p2;
    if (!m_data->clipToMap(gp1, gp2, p1, p2))
        return result;

    result.reserve(static_cast<std::size_t>(
        jd::math::abs(
            jd::vec_cast<float>(p2) - jd::vec_cast<float>(p1)
        ) * m_data->mapsize().z));

    sf::Vector2u pos = p1;
    sf::Vector2u lastPos = p1;
    for (;;) {
        std::vector<Info> stack;
        Vector3u idx(pos.x, pos.y, 0);
        for (; idx.z < m_data->mapsize().z; ++idx.z) {
            auto const c = m_data->makeCollision(idx, nullptr, sf::FloatRect());
            if (c.entity)
                stack.emplace_back(m_data->tilemap()[idx], c.entity);
            else
                stack.emplace_back();
        }
        m_filter(pos, stack);
        processStack(
            stack, result, m_data->tilemap().globalTileRect(sf::Vector2i(pos)));

        bool found;
        sf::Vector2u const nextPos = m_data->findNext(pos, lastPos, p1, p2, &found);
        if (!found)
            break;
        lastPos = pos;
        pos = nextPos;
    }
    return result;
}

    TileStackCollideableGroup::FilterCallback
TileStackCollideableGroup::setFilter(FilterCallback filter)
{
    auto oldfilter = m_filter;
    m_filter = filter;
    return oldfilter;
}


text:
//Link to Boost
#define BOOST_TEST_DYN_LINK

//VERY IMPORTANT - include this last
//#include <boost/test/included/unit_test.hpp>
#include <boost/test/unit_test.hpp>

#include "test.h"
#include "../HomotopyContinuation.h"
#include "../BetheHomotopy.h"

// test suite
BOOST_FIXTURE_TEST_SUITE(Demo_suite, SimpleTestFixture, * utf::label("UnityStartSystem"))

/*
BOOST_AUTO_TEST_CASE(Demo2)
{
    SolvedBetheEquation start(6, 2);
    BetaHomotopy hom(0.5235, &start);
    //BetaHomotopy hom(0.2578, &start);
    //BetaHomotopy hom(0.25502, &start);
    HomotopyContinuation hc(1000);

    std::cout << "begin demo2" << std::endl;
    hc.solve(hom);
    for (int i = 0; i < hom.numberOfRoots(); i++) {
        Vector root = hom.getRoot(i);
        std::cout << "demo2 root=" << root << ", eval=" << hom.evalTarget(root) << std::endl;
    }
    std::cout << "end demo2" << std::endl;
}*/

var_t normalPhase(var_t phase) {
    if (phase.real() < .0) {
        phase += 2 * Pi;
    } else {
        phase -= floor(phase.real() / (2.0 * Pi)) * 2 * Pi;
    }
    return phase;
}

BOOST_AUTO_TEST_CASE(Demo3, * utf::disabled())
{
//    ExpandedBetaHomotopy hom(0.523599 * 2, &numerator, &denominator);
    elem_t beta = Pi;
    elem_t expectedMomentumDiff = .0;
    ExpandedBetaHomotopy hom(6, 2, beta);
    hom.setSteps(1000);
    BetheRootCache cache(6, 2);
    BetheHomotopyContinuation hc;

    std::cout << "begin demo3" << std::endl;
    for (int i = 0; i < cache.numberOfRoots(); i++) {
        std::string file = "BS_L6M2r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        Vector startRoot = cache.getRoot(i);
        InvertableSolution sol(startRoot, 6);
        hc.solve(hom, sol);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << "end demo3" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo4, * utf::disabled())
{
    ExpandedBetaHomotopy hom(6, 3, 0.5235);
    hom.setSteps(1000);
    BetheRootCache cache(6, 3);
    BetheHomotopyContinuation hc;

    std::cout << "begin demo4" << std::endl;
    for (int i = 0; i < cache.numberOfRoots(); i++) {
        std::string file = "BS_L6M3r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        Vector startRoot = cache.getRoot(i);
        InvertableSolution sol(startRoot, 6);
        hc.solve(hom, sol);
        std::cout << "startRoot=" << startRoot << std::endl;
//        BOOST_TEST_INFO("root=" << sol.normalRoot() << ", startRoot=" << startRoot);
//        BOOST_TEST((sol.normalRoot()-startRoot).norm() < 1e-3);
        std::cout << "root=" << sol.normalRoot() << ", eval=" << hom.evalTarget(sol).norm() << std::endl;
    }
    std::cout << "end demo4" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo5, * utf::disabled())
{
    ExpandedBetaHomotopy hom(7, 2, 0.4488);
    hom.setSteps(1000);
    BetheRootCache cache(7, 2);
    BetheHomotopyContinuation hc;

    std::cout << "begin demo5" << std::endl;
    for (int i = 0; i < cache.numberOfRoots(); i++) {
        std::string file = "BS_L7M2r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        Vector startRoot = cache.getRoot(i);
        InvertableSolution sol(startRoot, 7);
        hc.solve(hom, sol);
//        BOOST_TEST_INFO("root=" << sol.normalRoot() << ", startRoot=" << startRoot);
//        BOOST_TEST((sol.normalRoot() - startRoot).norm() < 1e-3);
        std::cout << "demo5 root=" << sol.normalRoot() << ", eval=" << hom.evalTarget(sol);
        std::cout << ", momentum="<< momentum(sol.normalRoot()) <<  std::endl;
        std::cout << "start root=" << startRoot;
        std::cout << ", momentum="<< momentum(startRoot) << std::endl << std::endl;
    }
    std::cout << "end demo5" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo6, * utf::disabled())
{
    int L = 6;
    int M = 2;
    int steps = 1000;
    elem_t totalPhase = Pi;
    elem_t expectedMomentumDiff = .0;
    PoleFreeBetheHomotopy hom(L, M, totalPhase);
    hom.setSteps(steps);
    BetheRootCache cache(L, M);
    BetheHomotopyContinuation hc;

    std::cout << "begin demo6" << std::endl;
    for (int i = 0; i < cache.numberOfRoots(); i++) {
        std::string file = "Demo6_BS_L" + ToString(L)+ "M" + ToString(M)+ "r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        Vector startRoot = cache.getRoot(i);
        BetheSolution sol(startRoot, L, 0.0, totalPhase / steps);
        hc.solve(hom, sol);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << "end demo6" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo7, * utf::disabled())
{
    int L = 6;
    int M = 3;
    int steps = 1000;
    elem_t totalPhase = Pi;
    elem_t expectedMomentumDiff = .0;
    PoleFreeBetheHomotopy hom(L, M, totalPhase);
    hom.setSteps(steps);
    BetheRootCache cache(L, M);
    BetheHomotopyContinuation hc;

    std::cout << "begin demo7" << std::endl;
    for (int i = 0; i < cache.numberOfRoots(); i++) {
        std::string file = "Demo7_BS_L" + ToString(L)+ "M" + ToString(M)+ "r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        Vector startRoot = cache.getRoot(i);
        BetheSolution sol(startRoot, L, 0.0, totalPhase / steps);
        hc.solve(hom, sol);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << "end demo7" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo8, * utf::disabled())
{
    int L = 7;
    int M = 2;
    int steps = 3000;
    elem_t totalPhase = Pi;
    elem_t expectedMomentumDiff = .0;
    PoleFreeBetheHomotopy hom(L, M, totalPhase);
    hom.setSteps(steps);
    BetheRootCache cache(L, M);
    BetheHomotopyContinuation hc;
    SET_LOG_LEVEL(Info);

    // i = 1, 3, 8 failed.
    // i = 1 fail at two identical infinity roots
    // i = 3 and 8 fail at two conjugate finite roots.
    std::cout << "begin demo8" << std::endl;
    for (int i = 1; i < cache.numberOfRoots() && i < 2; i++) {
        std::string file = "Demo8_BS_L" + ToString(L)+ "M" + ToString(M)+ "r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        Vector startRoot = cache.getRoot(i);
        BetheSolution sol(startRoot, L, 0.0, totalPhase / hom.getSteps());
        hc.solve(hom, sol);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("i=" << i << ", m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << "end demo8" << std::endl;
    SET_LOG_LEVEL(Error);
}

BOOST_AUTO_TEST_CASE(Demo9, * utf::disabled())
{
    int L = 7;
    int M = 3;
    int steps = 6000;
    elem_t totalPhase = Pi;
    elem_t expectedMomentumDiff = .0;
    PoleFreeBetheHomotopy hom(L, M, totalPhase);
    hom.setSteps(steps);
    BetheRootCache cache(L, M);
    BetheHomotopyContinuation hc;

    // i = 0 fail at 2 identical infinite roots
    // i = 1 fail at 2 identical infinite roots
    // i = 4 fail at 2 conjugate finite roots
    // i=10 fail at 2 identical infinities
    // i = 11 fail at 2 identical infinities
    std::cout << "begin demo9" << std::endl;
    std::vector<bool> hasInfinity;
    for (int i = 6; i < cache.numberOfRoots() && i < 7; i++) {
        std::string file = "BS_L" + ToString(L)+ "M" + ToString(M)+ "r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        hc.hasInfinity = false;
        Vector startRoot = cache.getRoot(i);
        BetheSolution sol(startRoot, L, 0.0, totalPhase / steps);
        hc.solve(hom, sol);
        hasInfinity.push_back(hc.hasInfinity);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("i=" << i << ", m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << hasInfinity << std::endl;
    std::cout << "end demo9" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo10a, * utf::disabled())
{
    int L = 8;
    int M = 3;
    elem_t totalPhase = random(1.0, 2.0) * Pi;
    elem_t expectedMomentumDiff = floatMod(2 * M * totalPhase, 2 * Pi);
    PoleFreeBetheHomotopy hom(L, M, totalPhase);
    BetheRootCache cache(L, M);
    BetheHomotopyContinuation hc;

    SET_LOG_LEVEL(Info);
    std::cout << "begin demo10a" << std::endl;
    std::vector<bool> hasInfinity;
    for (int i = 17; i < cache.numberOfRoots() && i < 18; i++) {
        std::string file = "BS_L" + ToString(L)+ "M" + ToString(M)+ "r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        hc.hasInfinity = false;
        Vector startRoot = cache.getRoot(i);
        BetheSolution sol(startRoot, L, 0.0, totalPhase / hom.getSteps());
        hc.solve(hom, sol);
        hasInfinity.push_back(hc.hasInfinity);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("i=" << i << ", m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << hasInfinity << std::endl;
    std::cout << "end demo10" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo10, * utf::disabled())
{
    int L = 8;
    int M = 4;
    int steps = 3000;
    elem_t totalPhase = Pi;
    elem_t expectedMomentumDiff = .0;
    PoleFreeBetheHomotopy hom(L, M, totalPhase);
    hom.setSteps(steps);
    BetheRootCache cache(L, M);
    BetheHomotopyContinuation hc;

    // i = 5 four infinities, two pairs of conjugates
    // i = 6 three infinities, of which two are conjugates
    // i = 10 two identical infinities, two conjugates
    // i = 13 three infinities, of which two are conjugates
    std::cout << "begin demo10" << std::endl;
    std::vector<bool> hasInfinity;
    for (int i = 0; i < cache.numberOfRoots(); i++) {
        std::string file = "BS_L" + ToString(L)+ "M" + ToString(M)+ "r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        hc.hasInfinity = false;
        Vector startRoot = cache.getRoot(i);
        BetheSolution sol(startRoot, L, 0.0, totalPhase / steps);
        hc.solve(hom, sol);
        hasInfinity.push_back(hc.hasInfinity);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("i=" << i << ", m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << hasInfinity << std::endl;
    std::cout << "end demo10" << std::endl;
}

BOOST_AUTO_TEST_CASE(Demo11, * utf::disabled())
{
    int L = 12;
    int M = 6;
    int steps = 2000;
    elem_t totalPhase = Pi;
    elem_t expectedMomentumDiff = .0;
    PoleFreeBetheHomotopy hom(L, M, totalPhase);
    hom.setSteps(steps);
    BetheRootCache cache(L, M);
    BetheHomotopyContinuation hc;

    // i = 7 two finite conjugates
    // i = 8 two finite conjugates, two identical finite roots
    // i = 9 two identical finite, two singulars
    // i = 10 two pairs of finite conjugates
    std::vector<int> failed;
    std::cout << "begin demo11" << std::endl;
    for (int i = 0; i < cache.numberOfRoots(); i++) {
        std::string file = "BS_L" + ToString(L)+ "M" + ToString(M)+ "r" + ToString(i) + ".txt";
        hc.setTraceFile(file);
        Vector startRoot = cache.getRoot(i);
        BetheSolution sol(startRoot, L, 0.0, totalPhase / steps);
        hc.solve(hom, sol);
        elem_t m1 = momentum(startRoot);
        elem_t m2 = momentum(sol.normalRoot());
        BOOST_TEST_INFO("i=" << i << ", m1/Pi=" << m1/(elem_t)Pi << ", m2/Pi=" << m2/(elem_t)Pi);
        BOOST_TEST(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4);
        if (!(std::abs(floatMod(m2 - m1, 2.0 * Pi) - expectedMomentumDiff) < 1e-4)) {
            failed.push_back(i);
        }
        std::cout << "from " << startRoot << std::endl;
        std::cout << "to " << sol.normalRoot() << ", error=" << hom.evalTarget(sol) << std::endl;
    }
    std::cout << "Failed cases: " << failed << std::endl;
    std::cout << "end demo11" << std::endl;
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: gaolichen/bethesolver

max_issues_repo_name: gaolichen/bethesolver

max_forks_repo_name: gaolichen/bethesolver


text:
#pragma once

#include <string>
#include <type_traits>

#include <boost/optional.hpp>

#include <msw/format.hpp>
#include <msw/noncopyable.hpp>

#include <dawn/log/log.hpp>

namespace dawn
{
    struct logger
        : msw::noncopyable
    {
                                    explicit logger   (std::string const& prefix                                                            ) ;
                                             logger   (std::string const& prefix, log::level lifetime_level                                 ) ;
                                             logger   (std::string const& prefix, std::string const& specificity                            ) ;
                                             logger   (std::string const& prefix, std::string const& specificity, log::level lifetime_level ) ;
        template <typename T>                logger   (std::string const& prefix, T const&                                                  ) ;
        template <typename T>                logger   (std::string const& prefix, T const&                      , log::level lifetime_level ) ;
                                             ~logger  ()                                                                                ;

        template <typename ...Args> void     debug    (Args&& ...) const ;
        template <typename ...Args> void     info     (Args&& ...) const ;
        template <typename ...Args> void     warning  (Args&& ...) const ;
        template <typename ...Args> void     error    (Args&& ...) const ;
        template <typename ...Args> void     critical (Args&& ...) const ;

    private:

        template <typename T> typename std::enable_if<std::is_pointer<T>::value, std::string>::type  format_value(T const&);
        template <typename T> typename std::enable_if<!std::is_pointer<T>::value, std::string>::type format_value(T const&);

        std::string                 const prefix_         ;
        boost::optional<log::level> const lifetime_level_ ;
    };
}

namespace dawn
{
    inline logger::logger(std::string const& prefix)
        : prefix_( prefix )
    {}
    inline logger::logger(std::string const& prefix, log::level lifetime_level)
        : prefix_         ( prefix         )
        , lifetime_level_ ( lifetime_level )
    {
        if ( *lifetime_level_ >  log::level::info  ) throw std::runtime_error("lifetime level must be no more level::info");
        if ( *lifetime_level_ == log::level::debug ) debug ("+") ;
        if ( *lifetime_level_ == log::level::info  ) info  ("+") ;
    }
    inline logger::logger(std::string const& prefix, std::string const& specificity)
        : logger(prefix + "[" + specificity + "]")
    {}
    inline logger::logger(std::string const& prefix, std::string const& specificity, log::level lifetime_level)
        : logger(prefix + "[" + specificity + "]", lifetime_level)
    {}
    template <typename T>
    logger::logger(std::string const& prefix, T const& v)
        : logger(prefix, format_value(v))
    {}
    template <typename T>
    logger::logger(std::string const& prefix, T const& v, log::level lifetime_level)
        : logger(prefix, format_value(v), lifetime_level)
    {}

    inline logger::~logger()
    {
        if (lifetime_level_)
        {
            if ( *lifetime_level_ == log::level::debug ) debug ("~") ;
            if ( *lifetime_level_ == log::level::info  ) info  ("~") ;
        }
    }

#define DAWN_LOG_PRINT(L)\
    template <typename ...Args>\
    void logger::L(Args&& ...args) const\
    {\
        log::pref_##L(prefix_, std::forward<Args>(args)...);\
    }
    DAWN_LOG_PRINT( debug    )
    DAWN_LOG_PRINT( info     )
    DAWN_LOG_PRINT( warning  )
    DAWN_LOG_PRINT( error    )
    DAWN_LOG_PRINT( critical )
#undef DAWN_LOG_PRINT

    template <typename T>
    typename std::enable_if<std::is_pointer<T>::value, std::string>::type logger::format_value(T const& v)
    {
        return msw::format(static_cast<void const*>(v));
    }
    template <typename T>
    typename std::enable_if<!std::is_pointer<T>::value, std::string>::type logger::format_value(T const& v)
    {
        return msw::format(v);
    }
}

max_stars_repo_name: yklishevich/RubetekIOS-CPP-releases

max_issues_repo_name: yklishevich/RubetekIOS-CPP-releases

max_forks_repo_name: yklishevich/RubetekIOS-CPP-releases


text: #include <boost/callable_traits/args.hpp>


text:
// Boost.Range library
//
// Copyright Neil Groves 2014. Use, modification and distribution is subject
// to the Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see http://www.boost.org/libs/range
//

#include "mock_range.hpp"
#include <boost/range/adaptor/adjacent_filtered.hpp>

namespace
{

struct always_true
{
    typedef bool result_type;

    bool operator()(int, int) const
    {
        return true;
    }
};

} // anonymous namespace

int main(int, const char**)
{
    using boost::range::unit_test::mock_range;
    using boost::adaptors::adjacent_filter;

    // This next line should fail when Boost.Range concept checking is
    // enabled since the adjacent_filtered adaptor takes at least a
    // ForwardRange.
    return adjacent_filter(
            mock_range<boost::single_pass_traversal_tag>(),
            always_true()).front();
}


text:
//
//  Copyright (C) 2015-2017 Greg Landrum
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#define PY_ARRAY_UNIQUE_SYMBOL rdmoldraw2d_array_API
#include <RDBoost/python.h>
#include <GraphMol/ROMol.h>
#include <RDBoost/Wrap.h>

#include <GraphMol/MolDraw2D/MolDraw2D.h>
#include <GraphMol/MolDraw2D/MolDraw2DUtils.h>

#include <GraphMol/MolDraw2D/MolDraw2DSVG.h>
#include <Geometry/point.h>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#ifdef RDK_BUILD_CAIRO_SUPPORT
#include <cairo.h>
#include <GraphMol/MolDraw2D/MolDraw2DCairo.h>
#endif

namespace python = boost::python;

namespace RDKit {
namespace {
void tagAtomHelper(MolDraw2DSVG &self, const ROMol &mol, double radius,
                   python::object pyo) {
  std::map<std::string, std::string> events;
  if (pyo) {
    python::dict tDict = python::extract<python::dict>(pyo);
    python::list keys = tDict.keys();
    python::list vals = tDict.values();
    for (unsigned int i = 0;
         i < python::extract<unsigned int>(keys.attr("__len__")()); ++i) {
      events[python::extract<std::string>(keys[i])] =
          python::extract<std::string>(vals[i]);
    }
  }
  self.tagAtoms(mol, radius, events);
}
void pyDictToColourMap(python::object pyo, ColourPalette &res) {
  python::dict tDict = python::extract<python::dict>(pyo);
  for (unsigned int i = 0;
       i < python::extract<unsigned int>(tDict.keys().attr("__len__")()); ++i) {
    python::tuple tpl = python::extract<python::tuple>(tDict.values()[i]);
    float r = python::extract<float>(tpl[0]);
    float g = python::extract<float>(tpl[1]);
    float b = python::extract<float>(tpl[2]);
    DrawColour clr(r, g, b);
    res[python::extract<int>(tDict.keys()[i])] = clr;
  }
}
ColourPalette *pyDictToColourMap(python::object pyo) {
  ColourPalette *res = nullptr;
  if (pyo) {
    res = new ColourPalette;
    pyDictToColourMap(pyo, *res);
  }
  return res;
}
void pyDictToDoubleMap(python::object pyo, std::map<int, double> &res) {
  python::dict tDict = python::extract<python::dict>(pyo);
  for (unsigned int i = 0;
       i < python::extract<unsigned int>(tDict.keys().attr("__len__")()); ++i) {
    double r = python::extract<double>(tDict.values()[i]);
    res[python::extract<int>(tDict.keys()[i])] = r;
  }
}
std::map<int, double> *pyDictToDoubleMap(python::object pyo) {
  std::map<int, double> *res = nullptr;
  if (pyo) {
    res = new std::map<int, double>;
    pyDictToDoubleMap(pyo, *res);
  }
  return res;
}

DrawColour pyTupleToDrawColour(const python::tuple tpl) {
  float r = python::extract<float>(tpl[0]);
  if (r > 1 || r < 0) {
    throw ValueErrorException("RGB color value needs to be between 0 and 1.");
  }
  float g = python::extract<float>(tpl[1]);
  if (g > 1 || g < 0) {
    throw ValueErrorException("RGB color value needs to be between 0 and 1.");
  }
  float b = python::extract<float>(tpl[2]);
  if (b > 1 || b < 0) {
    throw ValueErrorException("RGB color value needs to be between 0 and 1.");
  }
  DrawColour clr(r, g, b);
  return clr;
}
void pyListToColourVec(python::object pyo, std::vector<DrawColour> &res) {
  res.clear();
  python::list tList = python::extract<python::list>(pyo);
  for (unsigned int i = 0;
       i < python::extract<unsigned int>(tList.attr("__len__")()); ++i) {
    python::tuple tpl = python::extract<python::tuple>(tList[i]);
    res.push_back(pyTupleToDrawColour(tpl));
  }
}
}  // namespace

void drawMoleculeHelper1(MolDraw2D &self, const ROMol &mol,
                         python::object highlight_atoms,
                         python::object highlight_atom_map,
                         python::object highlight_atom_radii, int confId,
                         std::string legend) {
  std::unique_ptr<std::vector<int>> highlightAtoms =
      pythonObjectToVect(highlight_atoms, static_cast<int>(mol.getNumAtoms()));
  ColourPalette *ham = pyDictToColourMap(highlight_atom_map);
  std::map<int, double> *har = pyDictToDoubleMap(highlight_atom_radii);

  self.drawMolecule(mol, legend, highlightAtoms.get(), ham, har, confId);

  delete ham;
  delete har;
}
void drawMoleculeHelper2(MolDraw2D &self, const ROMol &mol,
                         python::object highlight_atoms,
                         python::object highlight_bonds,
                         python::object highlight_atom_map,
                         python::object highlight_bond_map,
                         python::object highlight_atom_radii, int confId,
                         std::string legend) {
  std::unique_ptr<std::vector<int>> highlightAtoms =
      pythonObjectToVect(highlight_atoms, static_cast<int>(mol.getNumAtoms()));
  std::unique_ptr<std::vector<int>> highlightBonds =
      pythonObjectToVect(highlight_bonds, static_cast<int>(mol.getNumBonds()));
  // FIX: support these
  ColourPalette *ham = pyDictToColourMap(highlight_atom_map);
  ColourPalette *hbm = pyDictToColourMap(highlight_bond_map);
  std::map<int, double> *har = pyDictToDoubleMap(highlight_atom_radii);

  self.drawMolecule(mol, legend, highlightAtoms.get(), highlightBonds.get(),
                    ham, hbm, har, confId);

  delete ham;
  delete hbm;
  delete har;
}

void prepareAndDrawMoleculeHelper(
    MolDraw2D &drawer, const ROMol &mol, std::string legend,
    python::object highlight_atoms, python::object highlight_bonds,
    python::object highlight_atom_map, python::object highlight_bond_map,
    python::object highlight_atom_radii, int confId) {
  std::unique_ptr<std::vector<int>> highlightAtoms =
      pythonObjectToVect(highlight_atoms, static_cast<int>(mol.getNumAtoms()));
  std::unique_ptr<std::vector<int>> highlightBonds =
      pythonObjectToVect(highlight_bonds, static_cast<int>(mol.getNumBonds()));
  // FIX: support these
  ColourPalette *ham = pyDictToColourMap(highlight_atom_map);
  ColourPalette *hbm = pyDictToColourMap(highlight_bond_map);
  std::map<int, double> *har = pyDictToDoubleMap(highlight_atom_radii);
  MolDraw2DUtils::prepareAndDrawMolecule(
      drawer, mol, legend, highlightAtoms.get(), highlightBonds.get(), ham, hbm,
      har, confId);

  delete ham;
  delete hbm;
  delete har;
}

void drawMoleculesHelper2(MolDraw2D &self, python::object pmols,
                          python::object highlight_atoms,
                          python::object highlight_bonds,
                          python::object highlight_atom_map,
                          python::object highlight_bond_map,
                          python::object highlight_atom_radii,
                          python::object pconfIds, python::object plegends) {
  std::unique_ptr<std::vector<ROMol *>> mols =
      pythonObjectToVect<ROMol *>(pmols);
  if (mols == nullptr || !mols->size()) {
    return;
  }
  unsigned int nThere = mols->size();
  std::unique_ptr<std::vector<std::vector<int>>> highlightAtoms;
  if (highlight_atoms) {
    if (python::extract<unsigned int>(highlight_atoms.attr("__len__")()) !=
        nThere) {
      throw ValueErrorException(
          "If highlightAtoms is provided it must be the same length as the "
          "molecule list.");
    }
    highlightAtoms.reset(new std::vector<std::vector<int>>(nThere));
    for (unsigned int i = 0; i < nThere; ++i) {
      pythonObjectToVect(highlight_atoms[i], (*highlightAtoms)[i]);
    }
  }
  std::unique_ptr<std::vector<std::vector<int>>> highlightBonds;
  if (highlight_bonds) {
    if (python::extract<unsigned int>(highlight_bonds.attr("__len__")()) !=
        nThere) {
      throw ValueErrorException(
          "If highlightBonds is provided it must be the same length as the "
          "molecule list.");
    }
    highlightBonds.reset(new std::vector<std::vector<int>>(nThere));
    for (unsigned int i = 0; i < nThere; ++i) {
      pythonObjectToVect(highlight_bonds[i], (*highlightBonds)[i]);
    }
  }

  std::unique_ptr<std::vector<ColourPalette>> highlightAtomMap;
  if (highlight_atom_map) {
    if (python::extract<unsigned int>(highlight_atom_map.attr("__len__")()) !=
        nThere) {
      throw ValueErrorException(
          "If highlightAtomMap is provided it must be the same length as the "
          "molecule list.");
    }
    highlightAtomMap.reset(new std::vector<ColourPalette>(nThere));
    for (unsigned int i = 0; i < nThere; ++i) {
      pyDictToColourMap(highlight_atom_map[i], (*highlightAtomMap)[i]);
    }
  }
  std::unique_ptr<std::vector<ColourPalette>> highlightBondMap;
  if (highlight_bond_map) {
    if (python::extract<unsigned int>(highlight_bond_map.attr("__len__")()) !=
        nThere) {
      throw ValueErrorException(
          "If highlightBondMap is provided it must be the same length as the "
          "molecule list.");
    }
    highlightBondMap.reset(new std::vector<ColourPalette>(nThere));
    for (unsigned int i = 0; i < nThere; ++i) {
      pyDictToColourMap(highlight_bond_map[i], (*highlightBondMap)[i]);
    }
  }
  std::unique_ptr<std::vector<std::map<int, double>>> highlightRadii;
  if (highlight_atom_radii) {
    if (python::extract<unsigned int>(highlight_atom_radii.attr("__len__")()) !=
        nThere) {
      throw ValueErrorException(
          "If highlightAtomRadii is provided it must be the same length as the "
          "molecule list.");
    }
    highlightRadii.reset(new std::vector<std::map<int, double>>(nThere));
    for (unsigned int i = 0; i < nThere; ++i) {
      pyDictToDoubleMap(highlight_atom_radii[i], (*highlightRadii)[i]);
    }
  }
  // std::unique_ptr<std::vector<int> > highlightAtoms =
  //     pythonObjectToVect(highlight_atoms,
  //     static_cast<int>(mol.getNumAtoms()));
  // std::unique_ptr<std::vector<int> > highlightBonds =
  //     pythonObjectToVect(highlight_bonds,
  //     static_cast<int>(mol.getNumBonds()));
  // FIX: support these
  // std::map<int, DrawColour> *ham = pyDictToColourMap(highlight_atom_map);
  // std::map<int, DrawColour> *hbm = pyDictToColourMap(highlight_bond_map);
  // std::map<int, double> *har = pyDictToDoubleMap(highlight_atom_radii);
  //
  std::unique_ptr<std::vector<int>> confIds = pythonObjectToVect<int>(pconfIds);
  std::unique_ptr<std::vector<std::string>> legends =
      pythonObjectToVect<std::string>(plegends);

  self.drawMolecules(*mols, legends.get(), highlightAtoms.get(),
                     highlightBonds.get(), highlightAtomMap.get(),
                     highlightBondMap.get(), highlightRadii.get(),
                     confIds.get());
}

void drawReactionHelper(MolDraw2D &self, const ChemicalReaction &rxn,
                        bool highlightByReactant,
                        python::object phighlightColorsReactants,
                        python::object pconfIds) {
  std::unique_ptr<std::vector<DrawColour>> highlightColorsReactants;
  if (phighlightColorsReactants) {
    highlightColorsReactants.reset(new std::vector<DrawColour>);
    pyListToColourVec(phighlightColorsReactants, *highlightColorsReactants);
  }

  std::unique_ptr<std::vector<int>> confIds = pythonObjectToVect<int>(pconfIds);

  self.drawReaction(rxn, highlightByReactant, highlightColorsReactants.get(),
                    confIds.get());
}

#ifdef RDK_BUILD_CAIRO_SUPPORT
python::object getCairoDrawingText(const RDKit::MolDraw2DCairo &self) {
  std::string res = self.getDrawingText();
  python::object retval = python::object(
      python::handle<>(PyBytes_FromStringAndSize(res.c_str(), res.length())));
  return retval;
}
#endif
ROMol *prepMolForDrawing(const ROMol *m, bool kekulize = true,
                         bool addChiralHs = true, bool wedgeBonds = true,
                         bool forceCoords = false) {
  auto *res = new RWMol(*m);
  MolDraw2DUtils::prepareMolForDrawing(*res, kekulize, addChiralHs, wedgeBonds,
                                       forceCoords);
  return static_cast<ROMol *>(res);
}

python::tuple colourToPyTuple(const DrawColour &clr) {
  python::list res;
  res.append(clr.get<0>());
  res.append(clr.get<1>());
  res.append(clr.get<2>());

  return python::tuple(res);
}
python::object getBgColour(const RDKit::MolDrawOptions &self) {
  return colourToPyTuple(self.backgroundColour);
}
python::object getHighlightColour(const RDKit::MolDrawOptions &self) {
  return colourToPyTuple(self.highlightColour);
}
void setBgColour(RDKit::MolDrawOptions &self, python::tuple tpl) {
  self.backgroundColour = pyTupleToDrawColour(tpl);
}
void setHighlightColour(RDKit::MolDrawOptions &self, python::tuple tpl) {
  self.highlightColour = pyTupleToDrawColour(tpl);
}
python::object getSymbolColour(const RDKit::MolDrawOptions &self) {
  return colourToPyTuple(self.symbolColour);
}
void setSymbolColour(RDKit::MolDrawOptions &self, python::tuple tpl) {
  self.symbolColour = pyTupleToDrawColour(tpl);
}
void useDefaultAtomPalette(RDKit::MolDrawOptions &self) {
  assignDefaultPalette(self.atomColourPalette);
}
void useBWAtomPalette(RDKit::MolDrawOptions &self) {
  assignBWPalette(self.atomColourPalette);
}
void updateAtomPalette(RDKit::MolDrawOptions &self, python::object cmap) {
  pyDictToColourMap(cmap, self.atomColourPalette);
}
void setAtomPalette(RDKit::MolDrawOptions &self, python::object cmap) {
  self.atomColourPalette.clear();
  updateAtomPalette(self, cmap);
}

void addMoleculeMetadata(const RDKit::MolDraw2DSVG &self, const RDKit::ROMol &m,
                         int confId) {
  self.addMoleculeMetadata(m, confId);
}

}  // namespace RDKit

BOOST_PYTHON_MODULE(rdMolDraw2D) {
  python::scope().attr("__doc__") =
      "Module containing a C++ implementation of 2D molecule drawing";
  std::string docString;

  python::class_<std::map<int, std::string>>("IntStringMap")
      .def(python::map_indexing_suite<std::map<int, std::string>, true>());

  docString = "Drawing options";
  python::class_<RDKit::MolDrawOptions, boost::noncopyable>("MolDrawOptions",
                                                            docString.c_str())
      .def_readwrite("dummiesAreAttachments",
                     &RDKit::MolDrawOptions::dummiesAreAttachments)
      .def_readwrite("circleAtoms", &RDKit::MolDrawOptions::circleAtoms)
      .def("getBackgroundColour", &RDKit::getBgColour,
           "method returning the background colour")
      .def("getHighlightColour", &RDKit::getHighlightColour,
           "method returning the highlight colour")
      .def("setBackgroundColour", &RDKit::setBgColour,
           "method for setting the background colour")
      .def("setHighlightColour", &RDKit::setHighlightColour,
           "method for setting the highlight colour")
      .def("getSymbolColour", &RDKit::getSymbolColour,
           "method returning the symbol colour")
      .def("setSymbolColour", &RDKit::setSymbolColour,
           "method for setting the symbol colour")
      .def("useDefaultAtomPalette", &RDKit::useDefaultAtomPalette,
           "use the default colour palette for atoms and bonds")
      .def("useBWAtomPalette", &RDKit::useBWAtomPalette,
           "use the black & white palette for atoms and bonds")
      .def("updateAtomPalette", &RDKit::updateAtomPalette,
           "updates the palette for atoms and bonds from a dictionary mapping "
           "ints to 3-tuples")
      .def(
          "setAtomPalette", &RDKit::setAtomPalette,
          "sets the palette for atoms and bonds from a dictionary mapping ints "
          "to 3-tuples")
      .def_readwrite("atomLabels", &RDKit::MolDrawOptions::atomLabels,
                     "maps indices to atom labels")
      .def_readwrite("atomLabelDeuteriumTritium",
                     &RDKit::MolDrawOptions::atomLabelDeuteriumTritium,
                     "labels deuterium as D and tritium as T")
      .def_readwrite("continuousHighlight",
                     &RDKit::MolDrawOptions::continuousHighlight)
      .def_readwrite("fillHighlights", &RDKit::MolDrawOptions::fillHighlights)
      .def_readwrite("flagCloseContactsDist",
                     &RDKit::MolDrawOptions::flagCloseContactsDist)
      .def_readwrite("atomRegions", &RDKit::MolDrawOptions::atomRegions,
                     "regions to outline")
      .def_readwrite("includeAtomTags", &RDKit::MolDrawOptions::includeAtomTags,
                     "include atom tags in output")
      .def_readwrite("clearBackground", &RDKit::MolDrawOptions::clearBackground,
                     "clear the background before drawing a molecule")
      .def_readwrite("legendFontSize", &RDKit::MolDrawOptions::legendFontSize,
                     "font size in pixels of the legend (if drawn)")
      .def_readwrite(
          "multipleBondOffset", &RDKit::MolDrawOptions::multipleBondOffset,
          "offset (in Angstroms) for the extra lines in a multiple bond")
      .def_readwrite("padding", &RDKit::MolDrawOptions::padding,
                     "fraction of empty space to leave around molecule")
      .def_readwrite(
          "bondLineWidth", &RDKit::MolDrawOptions::bondLineWidth,
          "if positive, this overrides the default line width for bonds")
      .def_readwrite("additionalAtomLabelPadding",
                     &RDKit::MolDrawOptions::additionalAtomLabelPadding,
                     "additional padding to leave around atom labels. "
                     "Expressed as a fraction of the font size.");
  docString = "Drawer abstract base class";
  python::class_<RDKit::MolDraw2D, boost::noncopyable>(
      "MolDraw2D", docString.c_str(), python::no_init)
      .def("SetFontSize", &RDKit::MolDraw2D::setFontSize,
           "change the default font size")
      .def("FontSize", &RDKit::MolDraw2D::fontSize, "get the default font size")
      .def(
          "DrawMolecule", RDKit::drawMoleculeHelper1,
          (python::arg("self"), python::arg("mol"),
           python::arg("highlightAtoms") = python::object(),
           python::arg("highlightAtomColors") = python::object(),
           python::arg("highlightAtomRadii") = python::object(),
           python::arg("confId") = -1, python::arg("legend") = std::string("")),
          "renders a molecule\n")
      .def(
          "DrawMolecule", RDKit::drawMoleculeHelper2,
          (python::arg("self"), python::arg("mol"),
           python::arg("highlightAtoms"), python::arg("highlightBonds"),
           python::arg("highlightAtomColors") = python::object(),
           python::arg("highlightBondColors") = python::object(),
           python::arg("highlightAtomRadii") = python::object(),
           python::arg("confId") = -1, python::arg("legend") = std::string("")),
          "renders a molecule\n")
      .def("DrawMolecules", RDKit::drawMoleculesHelper2,
           (python::arg("self"), python::arg("mols"),
            python::arg("highlightAtoms") = python::object(),
            python::arg("highlightBonds") = python::object(),
            python::arg("highlightAtomColors") = python::object(),
            python::arg("highlightBondColors") = python::object(),
            python::arg("highlightAtomRadii") = python::object(),
            python::arg("confIds") = python::object(),
            python::arg("legends") = python::object()),
           "renders multiple molecules\n")
      .def("DrawReaction", RDKit::drawReactionHelper,
           (python::arg("self"), python::arg("rxn"),
            python::arg("highlightByReactant") = false,
            python::arg("highlightColorsReactants") = python::object(),
            python::arg("confIds") = python::object()),
           "renders a reaction\n")
      .def("Width", &RDKit::MolDraw2D::width,
           "get the width of the drawing canvas")
      .def("Height", &RDKit::MolDraw2D::height,
           "get the height of the drawing canvas")
      .def("SetOffset", &RDKit::MolDraw2D::setOffset,
           "set the offset (in drawing coordinates) for the drawing")
      .def("Offset", &RDKit::MolDraw2D::offset,
           "returns the offset (in drawing coordinates) for the drawing")
      .def("SetScale", &RDKit::MolDraw2D::setScale,
           "uses the values provided to set the drawing scaling")
      .def("SetLineWidth", &RDKit::MolDraw2D::setLineWidth,
           "set the line width being used")
      .def("LineWidth", &RDKit::MolDraw2D::lineWidth,
           "returns the line width being used")
      .def("DrawString", &RDKit::MolDraw2D::drawString,
           (python::arg("self"), python::arg("string"), python::arg("pos")),
           "add text to the canvas")
      .def("GetDrawCoords",
           (RDGeom::Point2D(RDKit::MolDraw2D::*)(const RDGeom::Point2D &)
                const) &
               RDKit::MolDraw2D::getDrawCoords,
           (python::arg("self"), python::arg("point")),
           "get the coordinates in drawing space for a particular point in "
           "molecule space")
      .def("GetDrawCoords",
           (RDGeom::Point2D(RDKit::MolDraw2D::*)(int) const) &
               RDKit::MolDraw2D::getDrawCoords,
           (python::arg("self"), python::arg("atomIndex")),
           "get the coordinates in drawing space for a particular atom")
      .def("drawOptions",
           (RDKit::MolDrawOptions & (RDKit::MolDraw2D::*)()) &
               RDKit::MolDraw2D::drawOptions,
           python::return_internal_reference<
               1, python::with_custodian_and_ward_postcall<0, 1>>(),
           "Returns a modifiable version of the current drawing options");
  docString = "SVG molecule drawer";
  python::class_<RDKit::MolDraw2DSVG, python::bases<RDKit::MolDraw2D>,
                 boost::noncopyable>("MolDraw2DSVG", docString.c_str(),
                                     python::init<int, int>())
      .def(python::init<int, int, int, int>())
      .def("FinishDrawing", &RDKit::MolDraw2DSVG::finishDrawing,
           "add the last bits of SVG to finish the drawing")
      .def("AddMoleculeMetadata", RDKit::addMoleculeMetadata,
           (python::arg("mol"), python::arg("confId") = -1),
           "add RDKit-specific information to the bottom of the drawing")
      .def("TagAtoms", RDKit::tagAtomHelper,
           (python::arg("mol"), python::arg("radius") = 0.2,
            python::arg("events") = python::object()),
           "allow atom selection in the SVG")
      .def("GetDrawingText", &RDKit::MolDraw2DSVG::getDrawingText,
           "return the SVG");

#ifdef RDK_BUILD_CAIRO_SUPPORT
  docString = "Cairo molecule drawer";
  python::class_<RDKit::MolDraw2DCairo, python::bases<RDKit::MolDraw2D>,
                 boost::noncopyable>("MolDraw2DCairo", docString.c_str(),
                                     python::init<int, int>())
      .def(python::init<int, int, int, int>())
      .def("FinishDrawing", &RDKit::MolDraw2DCairo::finishDrawing,
           "add the last bits to finish the drawing")
      .def("GetDrawingText", &RDKit::getCairoDrawingText,
           "return the PNG data as a string")
      .def("WriteDrawingText", &RDKit::MolDraw2DCairo::writeDrawingText,
           "write the PNG data to the named file");
#endif
  docString =
      "Does some cleanup operations on the molecule to prepare it to draw "
      "nicely.\n"
      "The operations include: kekulization, addition of chiral Hs (so that we "
      "can draw\n"
      "wedges to them), wedging of bonds at chiral centers, and generation of "
      "a 2D\n"
      "conformation if the molecule does not already have a conformation\n"
      "\nReturns a modified copy of the molecule.\n";
  python::def(
      "PrepareMolForDrawing", &RDKit::prepMolForDrawing,
      (python::arg("mol"), python::arg("kekulize") = true,
       python::arg("addChiralHs") = true, python::arg("wedgeBonds") = true,
       python::arg("forceCoords") = false),
      docString.c_str(),
      python::return_value_policy<python::manage_new_object>());
  python::def(
      "PrepareAndDrawMolecule", &RDKit::prepareAndDrawMoleculeHelper,
      (python::arg("drawer"), python::arg("mol"), python::arg("legend") = "",
       python::arg("highlightAtoms") = python::object(),
       python::arg("highlightBonds") = python::object(),
       python::arg("highlightAtomColors") = python::object(),
       python::arg("highlightBondColors") = python::object(),
       python::arg("highlightAtomRadii") = python::object(),
       python::arg("confId") = -1),
      "Preps a molecule for drawing and actually draws it\n");
}