<commit_before>// Time:  O(n * (C(2n, n) - C(2n, n - 1))), this is at most
// Space: O(n * (C(2n, n) - C(2n, n - 1)))

class Solution {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<vector<vector<int>>> lookup(input.length() + 1,
                                           vector<vector<int>>(input.length() + 1, vector<int>()));
        return diffWaysToComputeRecu(input, 0, input.length(), lookup);
    }

    vector<int> diffWaysToComputeRecu(const string& input,
                                      const int start, const int end,
                                      vector<vector<vector<int>>>& lookup) {
        if (!lookup[start][end].empty()) {
            return lookup[start][end];
        }
        vector<int> result;
        for (int i = start; i < end; ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToComputeRecu(input, start, i, lookup));
                vector<int> right = move(diffWaysToComputeRecu(input, i + 1, end, lookup));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input.substr(start, end - start)));
        }
        lookup[start][end] = move(result);
        return lookup[start][end];
    }
};

// Time:  O(n * (C(2n, n) - C(2n, n - 1))), this is at least
// Space: O(C(2n, n) - C(2n, n - 1))
class Solution2 {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<int> result;
        for (int i = 0; i < input.size(); ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToCompute(input.substr(0, i)));
                vector<int> right = move(diffWaysToCompute(input.substr(i + 1)));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input));
        }
        return result;
    }
};
<commit_msg>Update different-ways-to-add-parentheses.cpp<commit_after>// Time:  O(n * (C(2n, n) - C(2n, n - 1))), this is at most
// Space: O(n * (C(2n, n) - C(2n, n - 1)))

class Solution {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<vector<vector<int>>> lookup(input.length() + 1,
                                           vector<vector<int>>(input.length() + 1));
        return diffWaysToComputeRecu(input, 0, input.length(), lookup);
    }

    vector<int> diffWaysToComputeRecu(const string& input,
                                      const int start, const int end,
                                      vector<vector<vector<int>>>& lookup) {
        if (!lookup[start][end].empty()) {
            return lookup[start][end];
        }
        vector<int> result;
        for (int i = start; i < end; ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToComputeRecu(input, start, i, lookup));
                vector<int> right = move(diffWaysToComputeRecu(input, i + 1, end, lookup));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input.substr(start, end - start)));
        }
        lookup[start][end] = move(result);
        return lookup[start][end];
    }
};

// Time:  O(n * (C(2n, n) - C(2n, n - 1))), this is at least
// Space: O(C(2n, n) - C(2n, n - 1))
class Solution2 {
  public:
    vector<int> diffWaysToCompute(string input) {
        vector<int> result;
        for (int i = 0; i < input.size(); ++i) {
            const auto cur = input[i];
            if (cur == '+' || cur == '-' || cur == '*') {
                vector<int> left = move(diffWaysToCompute(input.substr(0, i)));
                vector<int> right = move(diffWaysToCompute(input.substr(i + 1)));
                for (const auto& num1 : left) {
                    for (const auto& num2 : right) {
                        if (cur == '+') {
                            result.emplace_back(num1 + num2);
                        } else if (cur == '-') {
                            result.emplace_back(num1 - num2);
                        } else {
                            result.emplace_back(num1 * num2);
                        }
                    }
                }
            }
        }
        // If the input string contains only number.
        if (result.empty()) {
            result.emplace_back(stoi(input));
        }
        return result;
    }
};
<|endoftext|>


<commit_before>/*
 * This file is part of telepathy-nepomuk-service
 *
 * Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
 *   @author George Goldberg <george.goldberg@collabora.co.uk>
 *
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "contact.h"

#include <TelepathyQt4/Connection>
#include <TelepathyQt4/ContactCapabilities>
#include <TelepathyQt4/ContactManager>

#include <KDebug>

Contact::Contact(const Tp::ContactPtr &contact, QObject *parent)
 : QObject(parent),
   m_contact(contact)
{
    // Do nothing here because the signals/slots need to be connected in our
    // parent class before we start doing stuff.
    kDebug() << "Creating new contact";
}

void Contact::init()
{
    // We need to destroy ourself if the connection goes down.
    connect(m_contact->manager()->connection().data(),
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(deleteLater()));

    // Connect to signals for all properties we want to keep synced.
    connect(m_contact.data(),
            SIGNAL(presenceChanged(Tp::Presence)),
            SLOT(onPresenceChanged(Tp::Presence)));
    connect(m_contact.data(),
            SIGNAL(aliasChanged(QString)),
            SLOT(onAliasChanged(QString)));
    connect(m_contact.data(),
            SIGNAL(addedToGroup(QString)),
            SLOT(onAddedToGroup(QString)));
    connect(m_contact.data(),
            SIGNAL(removedFromGroup(QString)),
            SLOT(onRemovedFromGroup(QString)));
    connect(m_contact.data(),
            SIGNAL(capabilitiesChanged(Tp::ContactCapabilities)),
            SLOT(onCapabilitiesChanged(Tp::ContactCapabilities)));
    connect(m_contact.data(),
            SIGNAL(subscriptionStateChanged(Tp::Contact::PresenceState,Tp::Channel::GroupMemberChangeDetails)),
            SLOT(onSubscriptionStateChanged(Tp::Contact::PresenceState)));
    connect(m_contact.data(),
            SIGNAL(publishStateChanged(Tp::Contact::PresenceState,Tp::Channel::GroupMemberChangeDetails)),
            SLOT(onPublishStateChanged(Tp::Contact::PresenceState)));
    connect(m_contact.data(),
            SIGNAL(blockStatusChanged(bool,Tp::Channel::GroupMemberChangeDetails)),
            SLOT(onBlockStatusChanged(bool)));
    // FIXME: Connect to any other signals of sync-worthy properties here.

    // Emit a signal to notify the controller that a new contact has been created.
    emit created(m_contact->id());

    // Synthesize all the properties being changed
    // FIXME: Make this bit correct
    /*
    onPublishStateChanged(m_contact->publishState());
    onSubscriptionStateChanged(m_contact->subscriptionState());
    onBlockStatusChanged(m_contact->isBlocked());
    if (contact->capabilities() != 0) {
        onCapabilitiesChanged(m_contact->capabilities());
    }
    */
}

Contact::~Contact()
{
    kDebug();
}

void Contact::shutdown()
{
    // Signal this contact is destroyed so it can be removed from the Hash.
    emit contactDestroyed(m_contact->id(), m_contact);
}

void Contact::onAliasChanged(const QString& alias)
{
    emit aliasChanged(m_contact->id(), alias);
}

void Contact::onPresenceChanged(const Tp::Presence &presence)
{
    emit presenceChanged(m_contact->id(), presence.barePresence());
}

void Contact::onAddedToGroup(const QString &group)
{
    kDebug() << "On added to group " << group;

    emit groupsChanged(m_contact->id(), m_contact->groups());
}

void Contact::onRemovedFromGroup(const QString &group)
{
    kDebug() << "On removed from group " << group;

    emit groupsChanged(m_contact->id(), m_contact->groups());
}

void Contact::onBlockStatusChanged(bool blocked)
{
    emit blockStatusChanged(m_contact->id(), blocked);
}

void Contact::onPublishStateChanged(Tp::Contact::PresenceState state)
{
    emit publishStateChanged(m_contact->id(), state);
}

void Contact::onSubscriptionStateChanged(Tp::Contact::PresenceState state)
{
    emit subscriptionStateChanged(m_contact->id(), state);
}

void Contact::onCapabilitiesChanged(const Tp::ContactCapabilities &capabilities)
{
    // FIXME: Implement me!
}

#include "contact.moc"

<commit_msg>Stop using deprecated signals on Contact class.<commit_after>/*
 * This file is part of telepathy-nepomuk-service
 *
 * Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
 *   @author George Goldberg <george.goldberg@collabora.co.uk>
 *
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "contact.h"

#include <TelepathyQt4/Connection>
#include <TelepathyQt4/ContactCapabilities>
#include <TelepathyQt4/ContactManager>

#include <KDebug>

Contact::Contact(const Tp::ContactPtr &contact, QObject *parent)
 : QObject(parent),
   m_contact(contact)
{
    // Do nothing here because the signals/slots need to be connected in our
    // parent class before we start doing stuff.
    kDebug() << "Creating new contact";
}

void Contact::init()
{
    // We need to destroy ourself if the connection goes down.
    connect(m_contact->manager()->connection().data(),
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(deleteLater()));

    // Connect to signals for all properties we want to keep synced.
    connect(m_contact.data(),
            SIGNAL(presenceChanged(Tp::Presence)),
            SLOT(onPresenceChanged(Tp::Presence)));
    connect(m_contact.data(),
            SIGNAL(aliasChanged(QString)),
            SLOT(onAliasChanged(QString)));
    connect(m_contact.data(),
            SIGNAL(addedToGroup(QString)),
            SLOT(onAddedToGroup(QString)));
    connect(m_contact.data(),
            SIGNAL(removedFromGroup(QString)),
            SLOT(onRemovedFromGroup(QString)));
    connect(m_contact.data(),
            SIGNAL(capabilitiesChanged(Tp::ContactCapabilities)),
            SLOT(onCapabilitiesChanged(Tp::ContactCapabilities)));
    connect(m_contact.data(),
            SIGNAL(subscriptionStateChanged(Tp::Contact::PresenceState)),
            SLOT(onSubscriptionStateChanged(Tp::Contact::PresenceState)));
    connect(m_contact.data(),
            SIGNAL(publishStateChanged(Tp::Contact::PresenceState, QString)),
            SLOT(onPublishStateChanged(Tp::Contact::PresenceState)));
    // FIXME: Add support to the ontology for the message QString.
    connect(m_contact.data(),
            SIGNAL(blockStatusChanged(bool)),
            SLOT(onBlockStatusChanged(bool)));
    // FIXME: Connect to any other signals of sync-worthy properties here.

    // Emit a signal to notify the controller that a new contact has been created.
    emit created(m_contact->id());

    // Synthesize all the properties being changed
    // FIXME: Make this bit correct
    /*
    onPublishStateChanged(m_contact->publishState());
    onSubscriptionStateChanged(m_contact->subscriptionState());
    onBlockStatusChanged(m_contact->isBlocked());
    if (contact->capabilities() != 0) {
        onCapabilitiesChanged(m_contact->capabilities());
    }
    */
}

Contact::~Contact()
{
    kDebug();
}

void Contact::shutdown()
{
    // Signal this contact is destroyed so it can be removed from the Hash.
    emit contactDestroyed(m_contact->id(), m_contact);
}

void Contact::onAliasChanged(const QString& alias)
{
    emit aliasChanged(m_contact->id(), alias);
}

void Contact::onPresenceChanged(const Tp::Presence &presence)
{
    emit presenceChanged(m_contact->id(), presence.barePresence());
}

void Contact::onAddedToGroup(const QString &group)
{
    kDebug() << "On added to group " << group;

    emit groupsChanged(m_contact->id(), m_contact->groups());
}

void Contact::onRemovedFromGroup(const QString &group)
{
    kDebug() << "On removed from group " << group;

    emit groupsChanged(m_contact->id(), m_contact->groups());
}

void Contact::onBlockStatusChanged(bool blocked)
{
    emit blockStatusChanged(m_contact->id(), blocked);
}

void Contact::onPublishStateChanged(Tp::Contact::PresenceState state)
{
    emit publishStateChanged(m_contact->id(), state);
}

void Contact::onSubscriptionStateChanged(Tp::Contact::PresenceState state)
{
    emit subscriptionStateChanged(m_contact->id(), state);
}

void Contact::onCapabilitiesChanged(const Tp::ContactCapabilities &capabilities)
{
    // FIXME: Implement me!
}

#include "contact.moc"

<|endoftext|>


<commit_before>#include "ReAligner.h"
#include <vector>
#include <iostream>
#include <list>
#include <limits>

ReAligner::ReAligner()
{
}

ReAligner::~ReAligner()
{
}

Consensus &ReAligner::getConsensus(Alignment & alignment)
{
	// TODO (mock object only)
	return *new Consensus(0);
}

void ReAligner::calculateConsensusScore(Consensus & consensus, Alignment & alignment)
{
	// TODO: after calculating do: consensus.setScore(calculatedScore);
}

Metasymbol * ReAligner::getConsensusMetasymbol(std::list<char>& column, int height)
{
	return nullptr;
}

void ReAligner::getAlignment(AlignedFragment & read, Consensus & cons, double eps)
{
	int min = std::numeric_limits<int>::min();
	std::list<Metasymbol*> consPartList;

	Metasymbol* dashSym = new Metasymbol();
	dashSym->addSymbol('-');

	int delta = (int)(eps / 2);

	int readLen = read.getLength();
	int readOff = read.getOffset();
	int consLen = cons.getLength();

	// -- Consensus part construction --
	int consPartStart = readOff - delta;
	int frontDashes = (consPartStart < 0) ? -consPartStart : 0;
	consPartStart = (consPartStart < 0) ? 0 : consPartStart;
	int consPartEnd = readOff + readLen + delta;
	int backDashes = (consPartEnd > consLen) ? consPartEnd-consLen : 0;
	consPartEnd = (consPartEnd > consLen) ? consLen : consPartEnd;

	consPartList = cons.getPart(consPartStart, consPartEnd);

	for (int i = 0; i < backDashes; i++)
		consPartList.push_back(dashSym);
	for (int i = 0; i < frontDashes; i++)
		consPartList.push_front(dashSym);

	int consPartLen = consPartList.size();

	std::vector<Metasymbol*> consPart(std::begin(consPartList), std::end(consPartList));

	// -- NeedlemanWunsch algorithm --

	vector<vector<int>> valueTable;
	vector<vector<bool>> isDiagonal;
	for (int i = 0; i <= readLen; i++) {
		vector<int> rowInt;
		vector<bool> rowBool;
		for (int j = 0; j <= consPartLen; j++) {
			rowInt.push_back(min);
			rowBool.push_back(false);
		}
		valueTable.push_back(rowInt);
		isDiagonal.push_back(rowBool);
	}

	// Initial values
	for (int j = 0; j <= 2 * delta; j++) {
		valueTable[0][j] = -abs(j - delta);
	}

	// Main loop
	for (int i = 1; i <= readLen; i++) {
		for (int j = 1; j <= consPartLen; j++) {
			if (j >= i && j <= i + 2 * delta) {
				Metasymbol *sym = consPart[j - 1];
				int cost = -1;
				if (sym->contains(read.getAt(i - 1)) || sym->isDashOnly())
					cost = 0;

				int scoreDiag = valueTable[i - 1][j - 1] + cost;
				int scoreLeft = (valueTable[i][j - 1] == min) ? min : valueTable[i][j - 1] - 1;

				if (scoreDiag >= scoreLeft) {
					valueTable[i][j] = scoreDiag;
					isDiagonal[i][j] = true;
				}
				else {
					valueTable[i][j] = scoreLeft;
				}
			}
		}
	}

	int score = min;
	int endPoisition = 0;
	for (int i = 0; i <= 2 * delta; i++) {
		int currentValue = valueTable[readLen][consPartLen - i];
		if (score < currentValue) {
			score = currentValue;
			endPoisition = consPartLen - i;
		}
	}

	std::string newSequence = "";
	int tabi = readLen;
	int tabj = endPoisition;
	while (tabi > 0) {
		if (isDiagonal[tabi][tabj]) {
			newSequence = read.getAt(tabi-1) + newSequence;
			tabi--;
			tabj--;
		}
		else {
			newSequence = "-" + newSequence;
			tabj--;
		}
	}

	int newOffset = read.getOffset() + tabj - delta;

	read.setSequence(newSequence);
	read.setOffset(newOffset);

	return;
}

Consensus ReAligner::reAlign(Alignment & alignment, double epsilonPrecision, int numOfIterations)
{
	Consensus consensus = getConsensus(alignment);
	calculateConsensusScore(consensus, alignment);
	double initialScore = consensus.getScore();
	bool shouldContinue = true;
	int iteration = 1;
	int numOfReads = alignment.getSize();

	double minimalScore = initialScore;
	Consensus bestConsensus = consensus;

	while (shouldContinue) {
		std::cout << "Iterating...";

		for (int k = 0; k < numOfReads; k++) {
			// detach first fragment in a list - append it last after iteration
			AlignedFragment* sequence = alignment.PopFirst();
			dashFunction(*sequence);
			dashFunction(consensus);
			consensus = getConsensus(alignment);
			getAlignment(*sequence, consensus, sequence->getLength() * epsilonPrecision);

			alignment.AddFragment(sequence);
			consensus = getConsensus(alignment);
			if (consensus.getScore() < minimalScore) {
				bestConsensus = consensus;
				minimalScore = consensus.getScore();
			}
		}

		if (bestConsensus.getScore() >= initialScore || iteration == numOfIterations) {
			shouldContinue = false;
		}

		std::cout << "After " << iteration << " iterations score is: " << bestConsensus.getScore() << "   previous score : " << initialScore;
		initialScore = bestConsensus.getScore();
		iteration++;
	}

	return bestConsensus;
}

void ReAligner::dashFunction(Consensus &consensus)
{
	consensus.removeDashesFrontAndBack();
}

void ReAligner::dashFunction(AlignedFragment & fragment)
{
	fragment.removeDashesFrontAndBack();
}
<commit_msg>ReAligner::getColumn and ReAligner::getNumberOfColumns implemented.<commit_after>#include "ReAligner.h"
#include <vector>
#include <iostream>
#include <list>
#include <limits>
#include <algorithm>

ReAligner::ReAligner()
{
}

ReAligner::~ReAligner()
{
}

Consensus &ReAligner::getConsensus(Alignment & alignment)
{
	// TODO (mock object only)
	return *new Consensus(0);
}

void ReAligner::calculateConsensusScore(Consensus & consensus, Alignment & alignment)
{
	// TODO: after calculating do: consensus.setScore(calculatedScore);
}

Metasymbol * ReAligner::getConsensusMetasymbol(std::list<char>& column, int height)
{
	return nullptr;
}

void ReAligner::getAlignment(AlignedFragment & read, Consensus & cons, double eps)
{
	int min = std::numeric_limits<int>::min();
	std::list<Metasymbol*> consPartList;

	Metasymbol* dashSym = new Metasymbol();
	dashSym->addSymbol('-');

	int delta = (int)(eps / 2);

	int readLen = read.getLength();
	int readOff = read.getOffset();
	int consLen = cons.getLength();

	// -- Consensus part construction --
	int consPartStart = readOff - delta;
	int frontDashes = (consPartStart < 0) ? -consPartStart : 0;
	consPartStart = (consPartStart < 0) ? 0 : consPartStart;
	int consPartEnd = readOff + readLen + delta;
	int backDashes = (consPartEnd > consLen) ? consPartEnd-consLen : 0;
	consPartEnd = (consPartEnd > consLen) ? consLen : consPartEnd;

	consPartList = cons.getPart(consPartStart, consPartEnd);

	for (int i = 0; i < backDashes; i++)
		consPartList.push_back(dashSym);
	for (int i = 0; i < frontDashes; i++)
		consPartList.push_front(dashSym);

	int consPartLen = consPartList.size();

	std::vector<Metasymbol*> consPart(std::begin(consPartList), std::end(consPartList));

	// -- NeedlemanWunsch algorithm --

	vector<vector<int>> valueTable;
	vector<vector<bool>> isDiagonal;
	for (int i = 0; i <= readLen; i++) {
		vector<int> rowInt;
		vector<bool> rowBool;
		for (int j = 0; j <= consPartLen; j++) {
			rowInt.push_back(min);
			rowBool.push_back(false);
		}
		valueTable.push_back(rowInt);
		isDiagonal.push_back(rowBool);
	}

	// Initial values
	for (int j = 0; j <= 2 * delta; j++) {
		valueTable[0][j] = -abs(j - delta);
	}

	// Main loop
	for (int i = 1; i <= readLen; i++) {
		for (int j = 1; j <= consPartLen; j++) {
			if (j >= i && j <= i + 2 * delta) {
				Metasymbol *sym = consPart[j - 1];
				int cost = -1;
				if (sym->contains(read.getAt(i - 1)) || sym->isDashOnly())
					cost = 0;

				int scoreDiag = valueTable[i - 1][j - 1] + cost;
				int scoreLeft = (valueTable[i][j - 1] == min) ? min : valueTable[i][j - 1] - 1;

				if (scoreDiag >= scoreLeft) {
					valueTable[i][j] = scoreDiag;
					isDiagonal[i][j] = true;
				}
				else {
					valueTable[i][j] = scoreLeft;
				}
			}
		}
	}

	int score = min;
	int endPoisition = 0;
	for (int i = 0; i <= 2 * delta; i++) {
		int currentValue = valueTable[readLen][consPartLen - i];
		if (score < currentValue) {
			score = currentValue;
			endPoisition = consPartLen - i;
		}
	}

	std::string newSequence = "";
	int tabi = readLen;
	int tabj = endPoisition;
	while (tabi > 0) {
		if (isDiagonal[tabi][tabj]) {
			newSequence = read.getAt(tabi-1) + newSequence;
			tabi--;
			tabj--;
		}
		else {
			newSequence = "-" + newSequence;
			tabj--;
		}
	}

	int newOffset = read.getOffset() + tabj - delta;

	read.setSequence(newSequence);
	read.setOffset(newOffset);

	return;
}

Consensus ReAligner::reAlign(Alignment & alignment, double epsilonPrecision, int numOfIterations)
{
	Consensus consensus = getConsensus(alignment);
	calculateConsensusScore(consensus, alignment);
	double initialScore = consensus.getScore();
	bool shouldContinue = true;
	int iteration = 1;
	int numOfReads = alignment.getSize();

	double minimalScore = initialScore;
	Consensus bestConsensus = consensus;

	while (shouldContinue) {
		std::cout << "Iterating...";

		for (int k = 0; k < numOfReads; k++) {
			// detach first fragment in a list - append it last after iteration
			AlignedFragment* sequence = alignment.PopFirst();
			dashFunction(*sequence);
			dashFunction(consensus);
			consensus = getConsensus(alignment);
			getAlignment(*sequence, consensus, sequence->getLength() * epsilonPrecision);

			alignment.AddFragment(sequence);
			consensus = getConsensus(alignment);
			if (consensus.getScore() < minimalScore) {
				bestConsensus = consensus;
				minimalScore = consensus.getScore();
			}
		}

		if (bestConsensus.getScore() >= initialScore || iteration == numOfIterations) {
			shouldContinue = false;
		}

		std::cout << "After " << iteration << " iterations score is: " << bestConsensus.getScore() << "   previous score : " << initialScore;
		initialScore = bestConsensus.getScore();
		iteration++;
	}

	return bestConsensus;
}

void ReAligner::dashFunction(Consensus &consensus)
{
	consensus.removeDashesFrontAndBack();
}

void ReAligner::dashFunction(AlignedFragment & fragment)
{
	fragment.removeDashesFrontAndBack();
}

std::list<char>& ReAligner::getColumn(Alignment & layoutMap, int index)
{
	std::list<char> &column = *new std::list<char>;
	std::list<AlignedFragment*> &fragments = layoutMap.getAllFragments();
	for (std::list<AlignedFragment*>::const_iterator iter = fragments.begin(); iter != fragments.end(); ++iter) {
		int offset = (*iter)->getOffset();
		int length = (*iter)->getLength();
		if (offset <= index && offset + length > index) {
			char sym = (*iter)->getAt(index - offset);
			column.push_back(sym);
		}
	}
	return column;
}

int ReAligner::getNumberOfColumns(Alignment & layoutMap)
{
	int numOfColumns = 0;
	std::list<AlignedFragment*> &fragments = layoutMap.getAllFragments();
	for (std::list<AlignedFragment*>::const_iterator iter = fragments.begin(); iter != fragments.end(); ++iter) {
		int offset = (*iter)->getOffset();
		int length = (*iter)->getLength();
		numOfColumns = std::max(numOfColumns, offset + length);
	}
	return numOfColumns;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under 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)
//=======================================================================

#include <unordered_set>

#include "FunctionContext.hpp"
#include "likely.hpp"

#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/Utils.hpp"

using namespace eddic;

bool mtac::merge_basic_blocks(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    std::unordered_set<std::shared_ptr<mtac::BasicBlock>> usage;

    computeBlockUsage(function, usage);

    auto& blocks = function->getBasicBlocks();

    auto it = blocks.begin();

    //The ENTRY Basic block should not be merged
    ++it;

    while(it != blocks.end()){
        auto& block = *it;
        if(likely(!block->statements.empty())){
            auto& last = block->statements[block->statements.size() - 1];

            bool merge = false;

            if(boost::get<std::shared_ptr<mtac::Quadruple>>(&last)){
                merge = true;
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Call>>(&last)){
                merge = safe(*ptr);
            } else if(boost::get<std::shared_ptr<mtac::NoOp>>(&last)){
                merge = true;
            }

            auto next = it;
            ++next;

            if(merge && next != blocks.end() && (*next)->index != -2){
                //Only if the next block is not used because we will remove its label
                if(usage.find(*next) == usage.end()){
                    if(!(*next)->statements.empty()){
                        if(auto* ptr = boost::get<std::shared_ptr<mtac::Call>>(&(*(*next)->statements.begin()))){
                            if(!safe(*ptr)){
                                ++it;
                                continue;
                            }
                        }
                    }

                    block->statements.insert(block->statements.end(), (*next)->statements.begin(), (*next)->statements.end());

                    it = blocks.erase(next);
                    optimized = true;

                    --it;
                    continue;
                }
            }
        }

        ++it;
    }

    return optimized;
}

bool mtac::remove_dead_basic_blocks(std::shared_ptr<mtac::Function> function){
    std::unordered_set<std::shared_ptr<mtac::BasicBlock>> usage;

    auto& blocks = function->getBasicBlocks();

    unsigned int before = blocks.size();

    auto it = blocks.begin();
    auto end = blocks.end();

    while(it != end){
        auto& block = *it;

        usage.insert(block);

        if(likely(!block->statements.empty())){
            auto& last = block->statements[block->statements.size() - 1];

            if(auto* ptr = boost::get<std::shared_ptr<mtac::Goto>>(&last)){
                if(usage.find((*ptr)->block) == usage.end()){
                    it = std::find(blocks.begin(), blocks.end(), (*ptr)->block);
                    continue;
                }
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::IfFalse>>(&last)){
                usage.insert((*ptr)->block);
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::If>>(&last)){
                usage.insert((*ptr)->block);
            }
        }

        ++it;
    }

    //The ENTRY and EXIT blocks should not be removed
    usage.insert(blocks.front());
    usage.insert(blocks.back());

    it = blocks.begin();
    end = blocks.end();

    blocks.erase(
            std::remove_if(it, end,
                [&](std::shared_ptr<mtac::BasicBlock>& b){ return usage.find(b) == usage.end(); }),
            end);

    return blocks.size() < before;
}
<commit_msg>Improve basic block merging<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under 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)
//=======================================================================

#include <unordered_set>

#include "FunctionContext.hpp"
#include "likely.hpp"

#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/Utils.hpp"

using namespace eddic;

bool mtac::merge_basic_blocks(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    std::unordered_set<std::shared_ptr<mtac::BasicBlock>> usage;

    computeBlockUsage(function, usage);

    auto& blocks = function->getBasicBlocks();

    auto it = blocks.begin();

    //The ENTRY Basic block should not be merged
    ++it;

    while(it != blocks.end()){
        auto& block = *it;
        if(unlikely(block->statements.empty())){
            if(usage.find(*it) == usage.end()){
                it = blocks.erase(it);
                optimized = true;

                --it;
                continue;
            }
        } else {
            auto& last = block->statements[block->statements.size() - 1];

            bool merge = false;

            if(boost::get<std::shared_ptr<mtac::Quadruple>>(&last)){
                merge = true;
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Call>>(&last)){
                merge = safe(*ptr);
            } else if(boost::get<std::shared_ptr<mtac::NoOp>>(&last)){
                merge = true;
            }

            auto next = it;
            ++next;

            if(merge && next != blocks.end() && (*next)->index != -2){
                //Only if the next block is not used because we will remove its label
                if(usage.find(*next) == usage.end()){
                    if(!(*next)->statements.empty()){
                        if(auto* ptr = boost::get<std::shared_ptr<mtac::Call>>(&(*(*next)->statements.begin()))){
                            if(!safe(*ptr)){
                                ++it;
                                continue;
                            }
                        }
                    }

                    block->statements.insert(block->statements.end(), (*next)->statements.begin(), (*next)->statements.end());

                    it = blocks.erase(next);
                    optimized = true;

                    --it;
                    continue;
                }
            }
        }

        ++it;
    }

    return optimized;
}

bool mtac::remove_dead_basic_blocks(std::shared_ptr<mtac::Function> function){
    std::unordered_set<std::shared_ptr<mtac::BasicBlock>> usage;

    auto& blocks = function->getBasicBlocks();

    unsigned int before = blocks.size();

    auto it = blocks.begin();
    auto end = blocks.end();

    while(it != end){
        auto& block = *it;

        usage.insert(block);

        if(likely(!block->statements.empty())){
            auto& last = block->statements[block->statements.size() - 1];

            if(auto* ptr = boost::get<std::shared_ptr<mtac::Goto>>(&last)){
                if(usage.find((*ptr)->block) == usage.end()){
                    it = std::find(blocks.begin(), blocks.end(), (*ptr)->block);
                    continue;
                }
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::IfFalse>>(&last)){
                usage.insert((*ptr)->block);
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::If>>(&last)){
                usage.insert((*ptr)->block);
            }
        }

        ++it;
    }

    //The ENTRY and EXIT blocks should not be removed
    usage.insert(blocks.front());
    usage.insert(blocks.back());

    it = blocks.begin();
    end = blocks.end();

    blocks.erase(
            std::remove_if(it, end,
                [&](std::shared_ptr<mtac::BasicBlock>& b){ return usage.find(b) == usage.end(); }),
            end);

    return blocks.size() < before;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include <stdafx.h>
#include <limits.h>

#include <cursespp/Screen.h>
#include <cursespp/Colors.h>
#include <cursespp/TextInput.h>

using namespace cursespp;

inline static bool removeUtf8Char(std::string& value, size_t position) {
    /* optimize the normal case, at the end... */
    if (position >= value.size()) {
        std::string::iterator it = value.end();
        std::string::iterator start = value.begin();
        if (it != start) {
            utf8::prior(it, start);
            value = std::string(value.begin(), it);
            return true;
        }
    }
    else {
        size_t offset = u8offset(value, position - 1);
        if (offset != std::string::npos) {
            size_t end = u8offset(value, position);
            value.erase(offset, end - offset);
            return true;
        }
    }

    return false;
}

TextInput::TextInput(TextInput::Style style, IInput::InputMode inputMode)
: Window()
, bufferLength(0)
, position(0)
, style(style)
, inputMode(inputMode)
, enterEnabled(true)
, truncate(false) {
    this->SetFocusedContentColor(Color::TextFocused);
    if (style == StyleLine) {
        this->SetFrameVisible(false);
    }
}

TextInput::TextInput(IInput::InputMode inputMode)
: TextInput(TextInput::StyleBox, inputMode) {
}

TextInput::~TextInput() {
}

void TextInput::OnRedraw() {
    WINDOW* c = this->GetContent();
    werase(c);

    std::string trimmed;
    int contentWidth = GetContentWidth();
    int columns = u8cols(buffer);

    /* if the string is larger than our width, we gotta trim it for
    display purposes... */
    if (position > contentWidth) {
        trimmed = u8substr(this->buffer, position - contentWidth, INT_MAX);
    }
    else {
        trimmed = buffer;
    }

    if (!columns && hintText.size()) {
        /* draw the hint if we have one and there's no string yet */
        int64_t color = Color(Color::TextDisabled);
        wattron(c, color);
        wmove(c, 0, 0);
        checked_waddstr(c, u8substr(hintText, 0, contentWidth).c_str());
        wattroff(c, color);
    }
    else {
        /* mask the string if we're in password mode */
        if (inputMode == InputPassword) {
            trimmed = std::string(columns, '*');
        }

        /* if we're in "Line" mode and the string is short, pad the
        end with a bunch of underscores */
        if (style == StyleLine) {
            int remaining = contentWidth - columns;
            if (remaining > 0) {
                trimmed += std::string(remaining, '_');
            }
        }

        /* finally, draw the offset/trimmed, potentially masked, padded
        string to the output */
        checked_waddstr(c, trimmed.c_str());
    }
}

size_t TextInput::Length() {
    return this->bufferLength;
}

size_t TextInput::Position() {
    /* note we return the COLUMN offset, not the physical or logical
    character offset! */
    return u8cols(u8substr(this->buffer, 0, this->position));
}

bool TextInput::Write(const std::string& key) {
    /* one character at a time. if it's more than one character, we're
    dealing with an escape sequence and should not print it unless
    the input mode allows for modifiers */
    int len = u8len(key);
    if (len == 1 || (len > 1 && this->inputMode == InputRaw)) {
        if (this->inputMode == InputRaw) {
            auto& bl = this->rawBlacklist;
            if (std::find(bl.begin(), bl.end(), key) != bl.end()) {
                return false;
            }
            this->buffer = key;
            this->bufferLength = len;
            this->position = len;
        }
        else {
            if (truncate) {
                int cols = u8cols(this->buffer);
                if (cols >= this->GetWidth()) {
                    return false;
                }
            }

            size_t offset = u8offset(this->buffer, this->position);
            offset = (offset == std::string::npos) ? 0 : offset;
            this->buffer.insert(offset, key);
            this->bufferLength = u8len(buffer);
            this->position += len;
        }

        this->TextChanged(this, this->buffer);
        this->Redraw();
        return true;
    }

    return false;
}

void TextInput::SetTruncate(bool truncate) {
    if (this->truncate != truncate) {
        this->truncate = truncate;
    }
}

void TextInput::SetEnterEnabled(bool enabled) {
    this->enterEnabled = enabled;
}

void TextInput::SetRawKeyBlacklist(const std::vector<std::string>&& blacklist) {
    this->rawBlacklist = blacklist;
}

bool TextInput::KeyPress(const std::string& key) {
    if (this->inputMode == InputMode::InputRaw) {
        return false;
    }

    if (key == "M-KEY_BACKSPACE") {
        this->SetText("");
        return true;
    }
    else if (key == "KEY_BACKSPACE") {
        if (this->position > 0) {
            if (removeUtf8Char(this->buffer, this->position)) {
                --this->bufferLength;
                this->Redraw();
                this->position = std::max(0, this->position - 1);
                this->TextChanged(this, this->buffer);
            }
        }
        return true;
    }
    else if (key == "KEY_ENTER") {
        if (enterEnabled) {
            this->EnterPressed(this);
            return true;
        }
        else {
            return false;
        }
    }
    else if (key == "KEY_LEFT") {
        return this->OffsetPosition(-1);
    }
    else if (key == "KEY_RIGHT") {
        return this->OffsetPosition(1);
    }
    else if (key == "KEY_HOME") {
        this->position = 0;
        this->Redraw();
        return true;
    }
    else if (key == "KEY_END") {
        this->position = this->bufferLength;
        this->Redraw();
        return true;
    }
    else if (key == "KEY_DC") {
        if ((int) this->bufferLength > this->position) {
            removeUtf8Char(this->buffer, this->position + 1);
            this->bufferLength = u8len(buffer);
            this->Redraw();
            this->TextChanged(this, this->buffer);
            return true;
        }
    }

    return false;
}

bool TextInput::OffsetPosition(int delta) {
    int actual = this->position + delta;
    actual = std::max(0, std::min((int) this->bufferLength, actual));

    if (this->position != actual) {
        this->position = actual;
        this->Redraw();
        return true; /* moved */
    }

    return false; /* didn't move */
}

void TextInput::SetText(const std::string& value) {
    if (value != this->buffer) {
        this->buffer = value;
        this->bufferLength = u8len(buffer);
        this->position = this->bufferLength;
        this->TextChanged(this, this->buffer);
        this->Redraw();
    }
}

void TextInput::SetHint(const std::string& hint) {
    this->hintText = hint;
    this->Redraw();
}

bool TextInput::MouseEvent(const IMouseHandler::Event& event) {
    if (event.Button1Clicked()) {
        this->position = std::max(0, std::min((int)this->bufferLength, event.x));
        this->FocusInParent();
        return true;
    }
    return false;
}<commit_msg>Fixed default TextInput focused content color for non-inline-styled controls<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include <stdafx.h>
#include <limits.h>

#include <cursespp/Screen.h>
#include <cursespp/Colors.h>
#include <cursespp/TextInput.h>

using namespace cursespp;

inline static bool removeUtf8Char(std::string& value, size_t position) {
    /* optimize the normal case, at the end... */
    if (position >= value.size()) {
        std::string::iterator it = value.end();
        std::string::iterator start = value.begin();
        if (it != start) {
            utf8::prior(it, start);
            value = std::string(value.begin(), it);
            return true;
        }
    }
    else {
        size_t offset = u8offset(value, position - 1);
        if (offset != std::string::npos) {
            size_t end = u8offset(value, position);
            value.erase(offset, end - offset);
            return true;
        }
    }

    return false;
}

TextInput::TextInput(TextInput::Style style, IInput::InputMode inputMode)
: Window()
, bufferLength(0)
, position(0)
, style(style)
, inputMode(inputMode)
, enterEnabled(true)
, truncate(false) {
    if (style == StyleLine) {
        this->SetFrameVisible(false);
        this->SetFocusedContentColor(Color::TextFocused);
    }
}

TextInput::TextInput(IInput::InputMode inputMode)
: TextInput(TextInput::StyleBox, inputMode) {
}

TextInput::~TextInput() {
}

void TextInput::OnRedraw() {
    WINDOW* c = this->GetContent();
    werase(c);

    std::string trimmed;
    int contentWidth = GetContentWidth();
    int columns = u8cols(buffer);

    /* if the string is larger than our width, we gotta trim it for
    display purposes... */
    if (position > contentWidth) {
        trimmed = u8substr(this->buffer, position - contentWidth, INT_MAX);
    }
    else {
        trimmed = buffer;
    }

    if (!columns && hintText.size()) {
        /* draw the hint if we have one and there's no string yet */
        int64_t color = Color(Color::TextDisabled);
        wattron(c, color);
        wmove(c, 0, 0);
        checked_waddstr(c, u8substr(hintText, 0, contentWidth).c_str());
        wattroff(c, color);
    }
    else {
        /* mask the string if we're in password mode */
        if (inputMode == InputPassword) {
            trimmed = std::string(columns, '*');
        }

        /* if we're in "Line" mode and the string is short, pad the
        end with a bunch of underscores */
        if (style == StyleLine) {
            int remaining = contentWidth - columns;
            if (remaining > 0) {
                trimmed += std::string(remaining, '_');
            }
        }

        /* finally, draw the offset/trimmed, potentially masked, padded
        string to the output */
        checked_waddstr(c, trimmed.c_str());
    }
}

size_t TextInput::Length() {
    return this->bufferLength;
}

size_t TextInput::Position() {
    /* note we return the COLUMN offset, not the physical or logical
    character offset! */
    return u8cols(u8substr(this->buffer, 0, this->position));
}

bool TextInput::Write(const std::string& key) {
    /* one character at a time. if it's more than one character, we're
    dealing with an escape sequence and should not print it unless
    the input mode allows for modifiers */
    int len = u8len(key);
    if (len == 1 || (len > 1 && this->inputMode == InputRaw)) {
        if (this->inputMode == InputRaw) {
            auto& bl = this->rawBlacklist;
            if (std::find(bl.begin(), bl.end(), key) != bl.end()) {
                return false;
            }
            this->buffer = key;
            this->bufferLength = len;
            this->position = len;
        }
        else {
            if (truncate) {
                int cols = u8cols(this->buffer);
                if (cols >= this->GetWidth()) {
                    return false;
                }
            }

            size_t offset = u8offset(this->buffer, this->position);
            offset = (offset == std::string::npos) ? 0 : offset;
            this->buffer.insert(offset, key);
            this->bufferLength = u8len(buffer);
            this->position += len;
        }

        this->TextChanged(this, this->buffer);
        this->Redraw();
        return true;
    }

    return false;
}

void TextInput::SetTruncate(bool truncate) {
    if (this->truncate != truncate) {
        this->truncate = truncate;
    }
}

void TextInput::SetEnterEnabled(bool enabled) {
    this->enterEnabled = enabled;
}

void TextInput::SetRawKeyBlacklist(const std::vector<std::string>&& blacklist) {
    this->rawBlacklist = blacklist;
}

bool TextInput::KeyPress(const std::string& key) {
    if (this->inputMode == InputMode::InputRaw) {
        return false;
    }

    if (key == "M-KEY_BACKSPACE") {
        this->SetText("");
        return true;
    }
    else if (key == "KEY_BACKSPACE") {
        if (this->position > 0) {
            if (removeUtf8Char(this->buffer, this->position)) {
                --this->bufferLength;
                this->Redraw();
                this->position = std::max(0, this->position - 1);
                this->TextChanged(this, this->buffer);
            }
        }
        return true;
    }
    else if (key == "KEY_ENTER") {
        if (enterEnabled) {
            this->EnterPressed(this);
            return true;
        }
        else {
            return false;
        }
    }
    else if (key == "KEY_LEFT") {
        return this->OffsetPosition(-1);
    }
    else if (key == "KEY_RIGHT") {
        return this->OffsetPosition(1);
    }
    else if (key == "KEY_HOME") {
        this->position = 0;
        this->Redraw();
        return true;
    }
    else if (key == "KEY_END") {
        this->position = this->bufferLength;
        this->Redraw();
        return true;
    }
    else if (key == "KEY_DC") {
        if ((int) this->bufferLength > this->position) {
            removeUtf8Char(this->buffer, this->position + 1);
            this->bufferLength = u8len(buffer);
            this->Redraw();
            this->TextChanged(this, this->buffer);
            return true;
        }
    }

    return false;
}

bool TextInput::OffsetPosition(int delta) {
    int actual = this->position + delta;
    actual = std::max(0, std::min((int) this->bufferLength, actual));

    if (this->position != actual) {
        this->position = actual;
        this->Redraw();
        return true; /* moved */
    }

    return false; /* didn't move */
}

void TextInput::SetText(const std::string& value) {
    if (value != this->buffer) {
        this->buffer = value;
        this->bufferLength = u8len(buffer);
        this->position = this->bufferLength;
        this->TextChanged(this, this->buffer);
        this->Redraw();
    }
}

void TextInput::SetHint(const std::string& hint) {
    this->hintText = hint;
    this->Redraw();
}

bool TextInput::MouseEvent(const IMouseHandler::Event& event) {
    if (event.Button1Clicked()) {
        this->position = std::max(0, std::min((int)this->bufferLength, event.x));
        this->FocusInParent();
        return true;
    }
    return false;
}<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>

using namespace std;

#define MOD     1000000007

int main() {
    int n;
    scanf("%d", &n);

    vector<int> vec_m;
    vec_m.reserve(n);

    int m;
    for (size_t i = 0; i < n; i++) {
        scanf("%d", &m);
        vec_m.push_back(m);
    }

    return 0;
}
<commit_msg>60.00 points<commit_after>//
//  main.cpp
//  test
//
//  Created by 吴星煜 on 2018/4/7.
//  Copyright © 2018年 吴星煜. All rights reserved.
//

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>

using namespace std;

#define MOD     1000000007
#define MAX_N   15

unsigned long long cnt[MAX_N + 1][MAX_N + 1];

int main() {
    int n;
    scanf("%d", &n);

    vector<int> vec_m;
    vec_m.reserve(n);

    int m;
    for (size_t i = 0; i < n; i++) {
        scanf("%d", &m);
        vec_m.push_back(m);
    }

    for (int c = 1; c <= n; c ++) {
        for (int i = n - c; i >= 0; i --) {
            if (1 == c) {
                cnt[i][c] = 1;
            }
            else {
                if (0 < cnt[i + 1][c - 1] && vec_m[i] < vec_m[i + 1]) {
                    if (i + c >= n) {
                        cnt[i][c] = 1;
                    }
                    else {
                        unsigned long long tmp = c;
                        for (int j = 1, c1 = c; j <= c; j ++, c1 --) {
                            cnt[i][c] += cnt[i + c][j] * tmp;
                            cnt[i][c] %= MOD;
                            tmp *= c1 - 1;
                            tmp %= MOD;
                        }
                    }
                }
            }
        }
    }

    unsigned long long ret = 0;

    for (int i = 1; i <= n; i ++) {
        ret += cnt[0][i];
        ret %= MOD;
    }

    printf("%llu\n", ret);

    return 0;
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "lid_allocator.h"
#include <vespa/searchlib/query/queryterm.h>
#include <vespa/searchlib/common/bitvectoriterator.h>
#include <mutex>

#include <vespa/log/log.h>
LOG_SETUP(".proton.documentmetastore.lid_allocator");

using search::fef::TermFieldMatchDataArray;
using search::queryeval::Blueprint;
using search::queryeval::FieldSpecBaseList;
using search::queryeval::SearchIterator;
using search::queryeval::SimpleLeafBlueprint;
using vespalib::GenerationHolder;

namespace proton::documentmetastore {

LidAllocator::LidAllocator(uint32_t size,
                           uint32_t capacity,
                           GenerationHolder &genHolder)
    : _holdLids(),
      _freeLids(size, capacity, genHolder, true, false),
      _usedLids(size, capacity, genHolder, false, true),
      _pendingHoldLids(size, capacity, genHolder, false, false),
      _lidFreeListConstructed(false),
      _activeLids(size, capacity, genHolder, false, false),
      _numActiveLids(0u)
{

}

LidAllocator::~LidAllocator() {}

LidAllocator::DocId
LidAllocator::getFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    } else {
        _freeLids.clearBit(lid);
    }
    return lid;
}

LidAllocator::DocId
LidAllocator::peekFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    }
    return lid;
}

void
LidAllocator::ensureSpace(uint32_t newSize,
                          uint32_t newCapacity)
{
    _freeLids.resizeVector(newSize, newCapacity);
    _usedLids.resizeVector(newSize, newCapacity);
    _pendingHoldLids.resizeVector(newSize, newCapacity);
    _activeLids.resizeVector(newSize, newCapacity);
}

void
LidAllocator::unregisterLid(DocId lid)
{
    assert(!_pendingHoldLids.testBit(lid));
    if (isFreeListConstructed()) {
        _pendingHoldLids.setBit(lid);
    }
    _usedLids.clearBit(lid);
    if (_activeLids.testBit(lid)) {
        _activeLids.clearBit(lid);
        _numActiveLids = _activeLids.count();
    }
}

size_t
LidAllocator::getUsedLidsSize() const
{
    return _usedLids.byteSize();
}

void
LidAllocator::trimHoldLists(generation_t firstUsed)
{
    _holdLids.trimHoldLists(firstUsed, _freeLids);
}

void
LidAllocator::moveLidBegin(DocId fromLid, DocId toLid)
{
    (void) fromLid;
    assert(!_pendingHoldLids.testBit(fromLid));
    assert(!_pendingHoldLids.testBit(toLid));
    if (isFreeListConstructed()) {
        assert(!_freeLids.testBit(fromLid));
        assert(_freeLids.testBit(toLid));
        _freeLids.clearBit(toLid);
    }
}

void
LidAllocator::moveLidEnd(DocId fromLid, DocId toLid)
{
    if (isFreeListConstructed()) {
        // old lid must be scheduled for hold by caller
        _pendingHoldLids.setBit(fromLid);
    }
    _usedLids.setBit(toLid);
    _usedLids.clearBit(fromLid);
    if (_activeLids.testBit(fromLid)) {
        _activeLids.setBit(toLid);
        _activeLids.clearBit(fromLid);
    }
}

void
LidAllocator::holdLid(DocId lid,
                      DocId lidLimit,
                      generation_t currentGeneration)
{
    (void) lidLimit;
    assert(holdLidOK(lid, lidLimit));
    assert(isFreeListConstructed());
    assert(lid < _usedLids.size());
    assert(lid < _pendingHoldLids.size());
    assert(_pendingHoldLids.testBit(lid));
    _pendingHoldLids.clearBit(lid);
    _holdLids.add(lid, currentGeneration);
}

void
LidAllocator::holdLids(const std::vector<DocId> &lids,
                       DocId lidLimit,
                       generation_t currentGeneration)
{
    (void) lidLimit;
    for (const auto &lid : lids) {
        assert(lid > 0);
        assert(holdLidOK(lid, lidLimit));
        _pendingHoldLids.clearBit(lid);
        _holdLids.add(lid, currentGeneration);
    }
}

bool
LidAllocator::holdLidOK(DocId lid, DocId lidLimit) const
{
    if (_lidFreeListConstructed &&
        lid != 0 &&
        lid < lidLimit &&
        lid < _usedLids.size() &&
        lid < _pendingHoldLids.size() &&
        _pendingHoldLids.testBit(lid))
    {
        return true;
    }
    LOG(error,
        "LidAllocator::holdLidOK(%u, %u): "
        "_lidFreeListConstructed=%s, "
        "_usedLids.size()=%d, "
        "_pendingHoldLids.size()=%d, "
        "_pendingHoldLids bit=%s",
        lid, lidLimit,
        _lidFreeListConstructed ? "true" : "false",
        (int) _usedLids.size(),
        (int) _pendingHoldLids.size(),
        lid < _pendingHoldLids.size() ?
        (_pendingHoldLids.testBit(lid) ?
         "true" : "false" ) : "invalid"
        );
    return false;
}

void
LidAllocator::constructFreeList(DocId lidLimit)
{
    assert(!isFreeListConstructed());
    _holdLids.clear();
    for (uint32_t lid = 1; lid < lidLimit; ++lid) {
        if (!validLid(lid)) {
            _freeLids.setBit(lid);
        }
    }
}

namespace {

class WhiteListBlueprint : public SimpleLeafBlueprint
{
private:
    const search::GrowableBitVector &_activeLids;
    mutable std::mutex _lock;
    mutable std::vector<search::fef::TermFieldMatchData *> _matchDataVector;

    virtual SearchIterator::UP
    createLeafSearch(const TermFieldMatchDataArray &tfmda,
                     bool strict) const override
    {
        assert(tfmda.size() == 0);
        (void) tfmda;
        search::fef::TermFieldMatchData *tfmd =
            new search::fef::TermFieldMatchData;
        {
            std::lock_guard<std::mutex> lock(_lock);
            _matchDataVector.push_back(tfmd);
        }
        uint32_t docIdLimit = _activeLids.size();
        return search::BitVectorIterator::create(&_activeLids, docIdLimit, *tfmd, strict);
    }

public:
    WhiteListBlueprint(const search::GrowableBitVector &activeLids)
        : SimpleLeafBlueprint(FieldSpecBaseList()),
          _activeLids(activeLids),
          _matchDataVector()
    {
        setEstimate(HitEstimate(0, false));
    }

    ~WhiteListBlueprint() {
        for (auto matchData : _matchDataVector) {
            delete matchData;
        }
    }
};

}

Blueprint::UP
LidAllocator::createWhiteListBlueprint() const
{
    return std::make_unique<WhiteListBlueprint>(_activeLids.getBitVector());
}

void
LidAllocator::updateActiveLids(DocId lid, bool active)
{
    bool oldActive = _activeLids.testBit(lid);
    if (oldActive != active) {
        if (active) {
            _activeLids.setBit(lid);
        } else {
            _activeLids.clearBit(lid);
        }
        _numActiveLids = _activeLids.count();
    }
}

void
LidAllocator::clearDocs(DocId lidLow, DocId lidLimit)
{
    (void) lidLow;
    (void) lidLimit;
    assert(_usedLids.getNextTrueBit(lidLow) >= lidLimit);
}

void
LidAllocator::shrinkLidSpace(DocId committedDocIdLimit)
{
    ensureSpace(committedDocIdLimit, committedDocIdLimit);
}

uint32_t
LidAllocator::getNumUsedLids() const
{
    return _usedLids.count();
}

}
<commit_msg>Don't estimate 0 hits in whitelist.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "lid_allocator.h"
#include <vespa/searchlib/query/queryterm.h>
#include <vespa/searchlib/common/bitvectoriterator.h>
#include <mutex>

#include <vespa/log/log.h>
LOG_SETUP(".proton.documentmetastore.lid_allocator");

using search::fef::TermFieldMatchDataArray;
using search::queryeval::Blueprint;
using search::queryeval::FieldSpecBaseList;
using search::queryeval::SearchIterator;
using search::queryeval::SimpleLeafBlueprint;
using vespalib::GenerationHolder;

namespace proton::documentmetastore {

LidAllocator::LidAllocator(uint32_t size,
                           uint32_t capacity,
                           GenerationHolder &genHolder)
    : _holdLids(),
      _freeLids(size, capacity, genHolder, true, false),
      _usedLids(size, capacity, genHolder, false, true),
      _pendingHoldLids(size, capacity, genHolder, false, false),
      _lidFreeListConstructed(false),
      _activeLids(size, capacity, genHolder, false, false),
      _numActiveLids(0u)
{

}

LidAllocator::~LidAllocator() {}

LidAllocator::DocId
LidAllocator::getFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    } else {
        _freeLids.clearBit(lid);
    }
    return lid;
}

LidAllocator::DocId
LidAllocator::peekFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    }
    return lid;
}

void
LidAllocator::ensureSpace(uint32_t newSize,
                          uint32_t newCapacity)
{
    _freeLids.resizeVector(newSize, newCapacity);
    _usedLids.resizeVector(newSize, newCapacity);
    _pendingHoldLids.resizeVector(newSize, newCapacity);
    _activeLids.resizeVector(newSize, newCapacity);
}

void
LidAllocator::unregisterLid(DocId lid)
{
    assert(!_pendingHoldLids.testBit(lid));
    if (isFreeListConstructed()) {
        _pendingHoldLids.setBit(lid);
    }
    _usedLids.clearBit(lid);
    if (_activeLids.testBit(lid)) {
        _activeLids.clearBit(lid);
        _numActiveLids = _activeLids.count();
    }
}

size_t
LidAllocator::getUsedLidsSize() const
{
    return _usedLids.byteSize();
}

void
LidAllocator::trimHoldLists(generation_t firstUsed)
{
    _holdLids.trimHoldLists(firstUsed, _freeLids);
}

void
LidAllocator::moveLidBegin(DocId fromLid, DocId toLid)
{
    (void) fromLid;
    assert(!_pendingHoldLids.testBit(fromLid));
    assert(!_pendingHoldLids.testBit(toLid));
    if (isFreeListConstructed()) {
        assert(!_freeLids.testBit(fromLid));
        assert(_freeLids.testBit(toLid));
        _freeLids.clearBit(toLid);
    }
}

void
LidAllocator::moveLidEnd(DocId fromLid, DocId toLid)
{
    if (isFreeListConstructed()) {
        // old lid must be scheduled for hold by caller
        _pendingHoldLids.setBit(fromLid);
    }
    _usedLids.setBit(toLid);
    _usedLids.clearBit(fromLid);
    if (_activeLids.testBit(fromLid)) {
        _activeLids.setBit(toLid);
        _activeLids.clearBit(fromLid);
    }
}

void
LidAllocator::holdLid(DocId lid,
                      DocId lidLimit,
                      generation_t currentGeneration)
{
    (void) lidLimit;
    assert(holdLidOK(lid, lidLimit));
    assert(isFreeListConstructed());
    assert(lid < _usedLids.size());
    assert(lid < _pendingHoldLids.size());
    assert(_pendingHoldLids.testBit(lid));
    _pendingHoldLids.clearBit(lid);
    _holdLids.add(lid, currentGeneration);
}

void
LidAllocator::holdLids(const std::vector<DocId> &lids,
                       DocId lidLimit,
                       generation_t currentGeneration)
{
    (void) lidLimit;
    for (const auto &lid : lids) {
        assert(lid > 0);
        assert(holdLidOK(lid, lidLimit));
        _pendingHoldLids.clearBit(lid);
        _holdLids.add(lid, currentGeneration);
    }
}

bool
LidAllocator::holdLidOK(DocId lid, DocId lidLimit) const
{
    if (_lidFreeListConstructed &&
        lid != 0 &&
        lid < lidLimit &&
        lid < _usedLids.size() &&
        lid < _pendingHoldLids.size() &&
        _pendingHoldLids.testBit(lid))
    {
        return true;
    }
    LOG(error,
        "LidAllocator::holdLidOK(%u, %u): "
        "_lidFreeListConstructed=%s, "
        "_usedLids.size()=%d, "
        "_pendingHoldLids.size()=%d, "
        "_pendingHoldLids bit=%s",
        lid, lidLimit,
        _lidFreeListConstructed ? "true" : "false",
        (int) _usedLids.size(),
        (int) _pendingHoldLids.size(),
        lid < _pendingHoldLids.size() ?
        (_pendingHoldLids.testBit(lid) ?
         "true" : "false" ) : "invalid"
        );
    return false;
}

void
LidAllocator::constructFreeList(DocId lidLimit)
{
    assert(!isFreeListConstructed());
    _holdLids.clear();
    for (uint32_t lid = 1; lid < lidLimit; ++lid) {
        if (!validLid(lid)) {
            _freeLids.setBit(lid);
        }
    }
}

namespace {

class WhiteListBlueprint : public SimpleLeafBlueprint
{
private:
    const search::GrowableBitVector &_activeLids;
    mutable std::mutex _lock;
    mutable std::vector<search::fef::TermFieldMatchData *> _matchDataVector;

    virtual SearchIterator::UP
    createLeafSearch(const TermFieldMatchDataArray &tfmda,
                     bool strict) const override
    {
        assert(tfmda.size() == 0);
        (void) tfmda;
        search::fef::TermFieldMatchData *tfmd =
            new search::fef::TermFieldMatchData;
        {
            std::lock_guard<std::mutex> lock(_lock);
            _matchDataVector.push_back(tfmd);
        }
        uint32_t docIdLimit = _activeLids.size();
        return search::BitVectorIterator::create(&_activeLids, docIdLimit, *tfmd, strict);
    }

public:
    WhiteListBlueprint(const search::GrowableBitVector &activeLids)
        : SimpleLeafBlueprint(FieldSpecBaseList()),
          _activeLids(activeLids),
          _matchDataVector()
    {
        setEstimate(HitEstimate(_activeLids.size(), false));
    }

    ~WhiteListBlueprint() {
        for (auto matchData : _matchDataVector) {
            delete matchData;
        }
    }
};

}

Blueprint::UP
LidAllocator::createWhiteListBlueprint() const
{
    return std::make_unique<WhiteListBlueprint>(_activeLids.getBitVector());
}

void
LidAllocator::updateActiveLids(DocId lid, bool active)
{
    bool oldActive = _activeLids.testBit(lid);
    if (oldActive != active) {
        if (active) {
            _activeLids.setBit(lid);
        } else {
            _activeLids.clearBit(lid);
        }
        _numActiveLids = _activeLids.count();
    }
}

void
LidAllocator::clearDocs(DocId lidLow, DocId lidLimit)
{
    (void) lidLow;
    (void) lidLimit;
    assert(_usedLids.getNextTrueBit(lidLow) >= lidLimit);
}

void
LidAllocator::shrinkLidSpace(DocId committedDocIdLimit)
{
    ensureSpace(committedDocIdLimit, committedDocIdLimit);
}

uint32_t
LidAllocator::getNumUsedLids() const
{
    return _usedLids.count();
}

}
<|endoftext|>


<commit_before>#ifndef _SDD_DD_SUM_HH_
#define _SDD_DD_SUM_HH_

/// @file  sum.hh
/// @brief Contain all stuff to implement the union operation.

#include <unordered_map>
#include <vector>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/context_fwd.hh"
#include "sdd/dd/definition.hh"
#include "sdd/dd/nary.hh"
#include "sdd/dd/operations_fwd.hh"
#include "sdd/dd/square_union.hh"
#include "sdd/internal/util/hash.hh"

namespace sdd {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief The union operation in the cache.
template <typename C>
struct _LIBSDD_ATTRIBUTE_PACKED sum_op
  : nary_base<C, sum_op<C>>
{
  typedef nary_base<C, sum_op<C>> base_type;

  template <typename... Args>
  sum_op(Args&&... args)
    : base_type(std::forward<Args>(args)...)
  {
  }

  /// @brief Get the textual representation of the union operator.
  ///
  /// Called by top to export a textual description.
  static
  char
  symbol()
  noexcept
  {
    return '+';
  }

  /// @brief Perform the union algorithm.
  ///
  /// It's a so-called 'n-ary' union in the sense that we don't create intermediary SDD.
  /// Also, a lot of tests permit to break loops as soon as possible.
  template <enum node_tag tag>
  SDD<C>
  work()
  const
  {
    typedef typename node_for_tag<C, tag>::type node_type;
    typedef typename node_type::valuation_type valuation_type;

    auto operands_cit = base_type::begin();
    const auto operands_end = base_type::end();

    // Get the first operand as a node, we need it to initialize the algorithm.
    const node_type& head = internal::mem::variant_cast<node_type>((*operands_cit)->data());

    // Type of the list of successors for a valuation, to be merged with the union operation
    // right before calling the square union.
    typedef sum_builder<C, SDD<C>> sum_builder_type;

    /// TODO Use Boost.Intrusive to save on memory allocations?
    // List all the successors for each valuation in the final alpha.
    std::unordered_map<valuation_type, sum_builder_type> res(head.size());

    // Needed to temporarily store arcs erased from res and arcs from the alpha visited in
    // the loop (B).
    std::vector<std::pair<valuation_type, sum_builder_type>> save;
    save.reserve(head.size());

    // Used in test (F).
    std::vector<std::pair<valuation_type, sum_builder_type>> remainder;
    remainder.reserve(head.size());

    // Initialize res with the alpha of the first operand.
    for (auto& arc : head)
    {
      sum_builder_type succs;
      succs.add(arc.successor());
      res.emplace(arc.valuation(), std::move(succs));
    }

    // (A).
    for (++operands_cit; operands_cit != operands_end; ++operands_cit)
    {
      const auto res_end = res.end();

      const node_type& node = internal::mem::variant_cast<node_type>((*operands_cit)->data());
      const auto alpha_end = node.end();

      // (B). For each arc of the current operand.
      for (auto alpha_cit = node.begin(); alpha_cit != alpha_end; ++alpha_cit)
      {
        // The current valuation may be modified, we need a copy.
        valuation_type current_val = alpha_cit->valuation();
        const SDD<C> current_succ = alpha_cit->successor();

        // Initialize the start of the next search.
        auto res_cit = res.begin();

        // (C). While the current valuation is not empty, test it against arcs in res.
        while (not current_val.empty() and res_cit != res_end)
        {
          const valuation_type& res_val = res_cit->first;
          sum_builder_type& res_succs = res_cit->second;

          // (D).
          if (current_val == res_val) // Same valuations.
          {
            save.emplace_back(res_val, std::move(res_succs));
            save.back().second.add(current_succ);
            const auto to_erase = res_cit;
            ++res_cit;
            res.erase(to_erase);
            // Avoid useless insertion or temporary variables.
            goto equality;
          }

          intersection_builder<C, valuation_type> inter_builder;
          inter_builder.add(current_val);
          inter_builder.add(res_val);
          const valuation_type inter = intersection(base_type::cxt_, std::move(inter_builder));

          // (E). The current valuation and the current arc from res have a common part.
          if (not inter.empty())
          {
            save.emplace_back(inter, res_succs);
            save.back().second.add(current_succ);

            // (F).
            valuation_type diff = difference(base_type::cxt_, res_val, inter);
            if (not diff.empty())
            {
              // (res_val - inter) can't be in intersection, but we need to keep it
              // for the next arcs of the current alpha. So we put in a temporary storage.
              // It will be added back in res when we have finished with the current valuation.
              remainder.emplace_back(std::move(diff), std::move(res_succs));
            }

            // We won't need the current arc of res for the current val, we already have the
            // common part. Now, the current valuation has to be tested against the next arcs
            // of res.
            const auto to_erase = res_cit;
            ++res_cit;
            res.erase(to_erase);

            // (G). The current valuation is completely included in the current arc of res.
            if (current_val == inter)
            {
              // We can move to the next arc of the current operand.
              break;
            }

            // Continue with what remains of val. if val is empy, the loop will stop at the
            // next iteration.
            current_val = difference(base_type::cxt_, current_val, inter);
          }
          else // (H). Empty intersection, lookup for next possible common parts.
          {
            ++res_cit;
          }
        } // While we're not at the end of res and val is not empty.

        // (I). For val or a part of val (it could have been modified during the previous
        // loop), we didn't find an intersection with any arc of res.
        if (not current_val.empty())
        {
          sum_builder_type succs;
          succs.add(current_succ);
          save.emplace_back(std::move(current_val), std::move(succs));
        }

        // Reinject all parts that were removed in (F).
        for (auto& rem : remainder)
        {
          res.emplace(std::move(rem.first), std::move(rem.second));
        }
        remainder.clear();

      // Both arcs had the same valuation: we just go to the next arc of the current operand.
      equality:;

      } // For each arc of the current operand.

      // Reinject all parts that were removed from res (all parts that have a non-empty
      // intersection with the current alpha) and all parts of the current alpha that have an
      // empty intersection with all the parts of res.
      res.insert(save.begin(), save.end());

      // We still need save.
      save.clear();
    } // End of iteration on operands.

    square_union<C, valuation_type> su;
    su.reserve(res.size());
    for (auto& arc : res)
    {
      // construct an operand for the square union: (successors union) --> valuation
      su.add(sum(base_type::cxt_, std::move(arc.second)), arc.first);
    }

    return SDD<C>(head.variable(), su(base_type::cxt_));
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Add an arc to the operands of the sum operation.
///
/// This implementation is meant to be used as a policy by nary_builder which doesn't know how
/// to add an arc.
template <typename C, typename Valuation>
struct _LIBSDD_ATTRIBUTE_PACKED sum_builder_impl
{
  void
  add(boost::container::flat_set<Valuation>& set, Valuation&& operand)
  {
    if (not operand.empty())
    {
      set.insert(std::move(operand));
    }
  }

  void
  add(boost::container::flat_set<Valuation>& set, const Valuation& operand)
  {
    if (not operand.empty())
    {
      set.insert(operand);
    }
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief   The sum operation of a set of SDD.
/// @related SDD
template <typename C>
inline
SDD<C>
sum(context<C>& cxt, sum_builder<C, SDD<C>>&& builder)
{
  if (builder.empty())
  {
    return zero<C>();
  }
  else if (builder.size() == 1)
  {
    return *builder.begin();
  }
  return cxt.sum_cache()(sum_op<C>(cxt, builder));
}

/*-------------------------------------------------------------------------------------------*/

/// @brief   The sum operation of a set of values.
/// @details A wrapper around the implementation of sum provided by Values.
template <typename C, typename Values>
inline
Values
sum(context<C>&, sum_builder<C, Values>&& builder)
{
  if (builder.empty())
  {
    return Values();
  }
  else if (builder.size() == 1)
  {
    return *builder.begin();
  }
  else
  {
    auto cit = builder.begin();
    const auto end = builder.end();
    Values result = *cit;
    for (++cit; cit != end; ++cit)
    {
      typename C::Values tmp = sum(result, *cit);
      using std::swap;
      swap(tmp, result);
    }
    return result;
  }
}

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief   Perform the union of two SDD.
/// @related SDD
template <typename C>
inline
SDD<C>
operator+(const SDD<C>& lhs, const SDD<C>& rhs)
{
  return sum(initial_context<C>(), {lhs, rhs});
}

/// @brief   Perform the union of two SDD.
/// @related SDD
template <typename C>
inline
SDD<C>&
operator+=(SDD<C>& lhs, const SDD<C>& rhs)
{
  SDD<C> tmp = sum(initial_context<C>(), {lhs, rhs});
  using std::swap;
  swap(tmp, lhs);
  return lhs;
}

/// @brief   Perform the union of an iterable container of SDD.
/// @related SDD
template <typename C, typename InputIterator>
SDD<C>
inline
sum(InputIterator begin, InputIterator end)
{
  sum_builder<C, SDD<C>> builder;
  for (; begin != end; ++begin)
  {
    builder.add(*begin);
  }
  return sum(initial_context<C>(), std::move(builder));
}

/// @brief   Perform the union of an initializer list of SDD.
/// @related SDD
template <typename C>
SDD<C>
inline
sum(std::initializer_list<SDD<C>> operands)
{
  return sum<C>(std::begin(operands), std::end(operands));
}

/*-------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @brief Hash specialization for sdd::dd::sum_op
template <typename C>
struct hash<sdd::sum_op<C>>
{
  std::size_t
  operator()(const sdd::sum_op<C>& sum)
  const noexcept
  {
    std::size_t seed = 0;
    for (const auto& operand : sum)
    {
      sdd::internal::util::hash_combine(seed, operand);
    }
    return seed;
  }
};

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_DD_SUM_HH_
<commit_msg>Fix SDD sum.<commit_after>#ifndef _SDD_DD_SUM_HH_
#define _SDD_DD_SUM_HH_

/// @file  sum.hh
/// @brief Contain all stuff to implement the union operation.

#include <unordered_map>
#include <vector>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/context_fwd.hh"
#include "sdd/dd/definition.hh"
#include "sdd/dd/nary.hh"
#include "sdd/dd/operations_fwd.hh"
#include "sdd/dd/square_union.hh"
#include "sdd/internal/util/hash.hh"

namespace sdd {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief The union operation in the cache.
template <typename C>
struct _LIBSDD_ATTRIBUTE_PACKED sum_op
  : nary_base<C, sum_op<C>>
{
  typedef nary_base<C, sum_op<C>> base_type;

  template <typename... Args>
  sum_op(Args&&... args)
    : base_type(std::forward<Args>(args)...)
  {
  }

  /// @brief Get the textual representation of the union operator.
  ///
  /// Called by top to export a textual description.
  static
  char
  symbol()
  noexcept
  {
    return '+';
  }

  /// @brief Perform the union algorithm.
  ///
  /// It's a so-called 'n-ary' union in the sense that we don't create intermediary SDD.
  /// Also, a lot of tests permit to break loops as soon as possible.
  template <enum node_tag tag>
  SDD<C>
  work()
  const
  {
    typedef typename node_for_tag<C, tag>::type node_type;
    typedef typename node_type::valuation_type valuation_type;

    auto operands_cit = base_type::begin();
    const auto operands_end = base_type::end();

    // Get the first operand as a node, we need it to initialize the algorithm.
    const node_type& head = internal::mem::variant_cast<node_type>((*operands_cit)->data());

    // Type of the list of successors for a valuation, to be merged with the union operation
    // right before calling the square union.
    typedef sum_builder<C, SDD<C>> sum_builder_type;

    /// TODO Use Boost.Intrusive to save on memory allocations?
    // List all the successors for each valuation in the final alpha.
    std::unordered_map<valuation_type, sum_builder_type> res(head.size());

    // Needed to temporarily store arcs erased from res and arcs from the alpha visited in
    // the loop (B).
    std::vector<std::pair<valuation_type, sum_builder_type>> save;
    save.reserve(head.size());

    // Used in test (F).
    std::vector<std::pair<valuation_type, sum_builder_type>> remainder;
    remainder.reserve(head.size());

    // Initialize res with the alpha of the first operand.
    for (auto& arc : head)
    {
      sum_builder_type succs;
      succs.add(arc.successor());
      res.emplace(arc.valuation(), std::move(succs));
    }

    // (A).
    for (++operands_cit; operands_cit != operands_end; ++operands_cit)
    {
      const auto res_end = res.end();

      const node_type& node = internal::mem::variant_cast<node_type>((*operands_cit)->data());
      const auto alpha_end = node.end();

      // (B). For each arc of the current operand.
      for (auto alpha_cit = node.begin(); alpha_cit != alpha_end; ++alpha_cit)
      {
        // The current valuation may be modified, we need a copy.
        valuation_type current_val = alpha_cit->valuation();
        const SDD<C> current_succ = alpha_cit->successor();

        // Initialize the start of the next search.
        auto res_cit = res.begin();

        // (C). While the current valuation is not empty, test it against arcs in res.
        while (not current_val.empty() and res_cit != res_end)
        {
          const valuation_type& res_val = res_cit->first;
          sum_builder_type& res_succs = res_cit->second;

          // (D).
          if (current_val == res_val) // Same valuations.
          {
            save.emplace_back(res_val, std::move(res_succs));
            save.back().second.add(current_succ);
            const auto to_erase = res_cit;
            ++res_cit;
            res.erase(to_erase);
            // Avoid useless insertion or temporary variables.
            goto equality;
          }

          intersection_builder<C, valuation_type> inter_builder;
          inter_builder.add(current_val);
          inter_builder.add(res_val);
          const valuation_type inter = intersection(base_type::cxt_, std::move(inter_builder));

          // (E). The current valuation and the current arc from res have a common part.
          if (not inter.empty())
          {
            save.emplace_back(inter, res_succs);
            save.back().second.add(current_succ);

            // (F).
            valuation_type diff = difference(base_type::cxt_, res_val, inter);
            if (not diff.empty())
            {
              // (res_val - inter) can't be in intersection, but we need to keep it
              // for the next arcs of the current alpha. So we put in a temporary storage.
              // It will be added back in res when we have finished with the current valuation.
              remainder.emplace_back(std::move(diff), std::move(res_succs));
            }

            // We won't need the current arc of res for the current val, we already have the
            // common part. Now, the current valuation has to be tested against the next arcs
            // of res.
            const auto to_erase = res_cit;
            ++res_cit;
            res.erase(to_erase);

            // (G). The current valuation is completely included in the current arc of res.
            if (current_val == inter)
            {
              // We can move to the next arc of the current operand.
              break;
            }

            // Continue with what remains of val. if val is empy, the loop will stop at the
            // next iteration.
            current_val = difference(base_type::cxt_, current_val, inter);
          }
          else // (H). Empty intersection, lookup for next possible common parts.
          {
            ++res_cit;
          }
        } // While we're not at the end of res and val is not empty.

        // (I). For val or a part of val (it could have been modified during the previous
        // loop), we didn't find an intersection with any arc of res.
        if (not current_val.empty())
        {
          sum_builder_type succs;
          succs.add(current_succ);
          save.emplace_back(std::move(current_val), std::move(succs));
        }

        // Both arcs had the same valuation.
        equality:;

        // Reinject all parts that were removed in (F).
        for (auto& rem : remainder)
        {
          res.emplace(std::move(rem.first), std::move(rem.second));
        }
        remainder.clear();

      } // For each arc of the current operand.

      // Reinject all parts that were removed from res (all parts that have a non-empty
      // intersection with the current alpha) and all parts of the current alpha that have an
      // empty intersection with all the parts of res.
      res.insert(save.begin(), save.end());

      // We still need save.
      save.clear();
    } // End of iteration on operands.

    square_union<C, valuation_type> su;
    su.reserve(res.size());
    for (auto& arc : res)
    {
      // construct an operand for the square union: (successors union) --> valuation
      su.add(sum(base_type::cxt_, std::move(arc.second)), arc.first);
    }

    return SDD<C>(head.variable(), su(base_type::cxt_));
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Add an arc to the operands of the sum operation.
///
/// This implementation is meant to be used as a policy by nary_builder which doesn't know how
/// to add an arc.
template <typename C, typename Valuation>
struct _LIBSDD_ATTRIBUTE_PACKED sum_builder_impl
{
  void
  add(boost::container::flat_set<Valuation>& set, Valuation&& operand)
  {
    if (not operand.empty())
    {
      set.insert(std::move(operand));
    }
  }

  void
  add(boost::container::flat_set<Valuation>& set, const Valuation& operand)
  {
    if (not operand.empty())
    {
      set.insert(operand);
    }
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief   The sum operation of a set of SDD.
/// @related SDD
template <typename C>
inline
SDD<C>
sum(context<C>& cxt, sum_builder<C, SDD<C>>&& builder)
{
  if (builder.empty())
  {
    return zero<C>();
  }
  else if (builder.size() == 1)
  {
    return *builder.begin();
  }
  return cxt.sum_cache()(sum_op<C>(cxt, builder));
}

/*-------------------------------------------------------------------------------------------*/

/// @brief   The sum operation of a set of values.
/// @details A wrapper around the implementation of sum provided by Values.
template <typename C, typename Values>
inline
Values
sum(context<C>&, sum_builder<C, Values>&& builder)
{
  if (builder.empty())
  {
    return Values();
  }
  else if (builder.size() == 1)
  {
    return *builder.begin();
  }
  else
  {
    auto cit = builder.begin();
    const auto end = builder.end();
    Values result = *cit;
    for (++cit; cit != end; ++cit)
    {
      typename C::Values tmp = sum(result, *cit);
      using std::swap;
      swap(tmp, result);
    }
    return result;
  }
}

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief   Perform the union of two SDD.
/// @related SDD
template <typename C>
inline
SDD<C>
operator+(const SDD<C>& lhs, const SDD<C>& rhs)
{
  return sum(initial_context<C>(), {lhs, rhs});
}

/// @brief   Perform the union of two SDD.
/// @related SDD
template <typename C>
inline
SDD<C>&
operator+=(SDD<C>& lhs, const SDD<C>& rhs)
{
  SDD<C> tmp = sum(initial_context<C>(), {lhs, rhs});
  using std::swap;
  swap(tmp, lhs);
  return lhs;
}

/// @brief   Perform the union of an iterable container of SDD.
/// @related SDD
template <typename C, typename InputIterator>
SDD<C>
inline
sum(InputIterator begin, InputIterator end)
{
  sum_builder<C, SDD<C>> builder;
  for (; begin != end; ++begin)
  {
    builder.add(*begin);
  }
  return sum(initial_context<C>(), std::move(builder));
}

/// @brief   Perform the union of an initializer list of SDD.
/// @related SDD
template <typename C>
SDD<C>
inline
sum(std::initializer_list<SDD<C>> operands)
{
  return sum<C>(std::begin(operands), std::end(operands));
}

/*-------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @brief Hash specialization for sdd::dd::sum_op
template <typename C>
struct hash<sdd::sum_op<C>>
{
  std::size_t
  operator()(const sdd::sum_op<C>& sum)
  const noexcept
  {
    std::size_t seed = 0;
    for (const auto& operand : sum)
    {
      sdd::internal::util::hash_combine(seed, operand);
    }
    return seed;
  }
};

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_DD_SUM_HH_
<|endoftext|>