<commit_before>#include "header/Solution.hpp"

using namespace std;
using namespace pcp;
using namespace boost;

Solution::Solution() {
	this->g = new Graph(0);
	this->colorsUsed = 0;
	this->partitionMap = get(vertex_index1_t(), *this->g);
	this->idMap = get(vertex_index2_t(), *this->g);
}

Solution::Solution(Solution *toCopy) {
	this->partNodes = NULL;
	this->g = new Graph(0);
	this->numParts = toCopy->numParts;
	this->partition = new int[this->numParts];
	this->representatives = new int[this->numParts];

	for (int i = 0; i < this->numParts; i++) {
		this->partition[i] = toCopy->partition[i];
		this->representatives[i] = toCopy->representatives[i];
	}
	this->colorsUsed = toCopy->colorsUsed;
	copy_graph(*toCopy->g, *this->g);
	this->partitionMap = get(vertex_index1_t(), *this->g);
	this->idMap = get(vertex_index2_t(), *this->g);
}

Solution::~Solution() {
	delete g;
	delete[] partition;
	delete[] representatives;
}

int Solution::getPartition(Vertex v) {
	return get(this->partitionMap, v);
}

int Solution::getOriginalId(Vertex v) {
	return get(this->idMap, v);
}

int Solution::getPartitionColor(Vertex v) {
	return partition[getPartition(v)];
}

void Solution::setPartitionColor(Vertex v, int color) {
	partition[getPartition(v)] = color;
}

bool Solution::isPartitionColored(Vertex v) {
	return getPartitionColor(v) != -1;
}

int Solution::getColorDegree(Vertex node) {
	int colored = 0;
	AdjIter i, end;

	for (tie(i, end) = adjacent_vertices(node, *this->g); i != end; i++)
		if (this->isPartitionColored(*i))
			colored++;

	return colored;
}

int Solution::minPossibleColor(Vertex node) {
	bool* colors = new bool[this->numParts];
	fill(colors, colors + this->numParts, false);
	AdjIter i, end;

	for (tie(i, end) = adjacent_vertices(node, *this->g); i != end; i++)
		if (this->isPartitionColored(*i))
			colors[this->partition[this->getPartition(*i)]] = true;

	for (int i = 0; i < this->numParts; i++) {
		if (!colors[i]) {
			delete[] colors;
			return i;
		}
	}

	return -1;
}

Solution* Solution::fromPcpStream(istream& in) {
	Solution *s = new Solution();

	int vertices, edges, partitions;
	cin >> vertices >> edges >> partitions;

	if (DEBUG_LEVEL > 3) {
		cout << "Reading " << vertices << " vertices, " << edges << " edges and ";
		cout << partitions << " partitons ..." << endl;
	}

	/// Initialize the solution to the read parameters
	s->partition = new int[partitions];
	s->representatives = new int[partitions];
	s->partNodes = new vector<Vertex>[partitions];
	s->numParts = partitions;
	s->colorsUsed = partitions;

	/// Initialize the property maps for partition and vertexID
	VertexID_Map vertex_id = get(vertex_index2_t(), *s->g);
	VertexPart_Map vertex_part = get(vertex_index1_t(), *s->g);

	/// Read partition info and store it into the property map, do the same
	/// for the "original" vertexID, so they can be compared on all graph
	int i, part;
	for (i = 0; i < vertices; i++) {
		cin >> part;
		Vertex v = add_vertex(*s->g);
		put(vertex_part, v, part);
		put(vertex_id, v, i);
		s->partNodes[part].push_back(v);

		if (DEBUG_LEVEL > 3)
			cout << "Added vertex " << i << " to partition " << part << "." << endl;
	}

	/// Read the input for edges between to vertices and add them to the
	/// solution graph
	for (i = 0; i < edges; i++) {
		int source, target;
		cin >> source >> target;

		if (DEBUG_LEVEL > 3) {
			cout << "Added edge (" << source << "|" << target << ")." << endl;
		}
		add_edge(source, target, *s->g);
	}

	if (DEBUG_LEVEL > 3)
		cout << "Parsing input finished successfully!" << endl;

	return s;
}

Solution* Solution::fromColStream(istream& in) {
	Solution *s = new Solution;

	char buffer[PARSE_BUFFERSIZE];

	/// Ignore all lines until first encounter of the p line
	while (in.get() != 'p')
		in.ignore(numeric_limits<streamsize>::max(), '\n');

	in.get();
	in.getline(buffer, PARSE_BUFFERSIZE, ' ');

	if (strcmp(buffer, "edge") != 0) {
		cerr << "This parser is unable to read files using a FORMAT other than 'edge' ('" << buffer << "' specified)" << endl;
		return NULL;
	}

	int vertices, edges;
	cin >> vertices >> edges;

	if (DEBUG_LEVEL > 3)
		cout << "Reading " << edges << " edges ..." << endl;

	if (in.get() != '\n') {
		cerr << "Malformed p-line detected (not terminated by newline)!" << endl;
		return NULL;
	}

	/// Initialize the property maps for partition and vertexID
	VertexID_Map vertex_id = get(vertex_index2_t(), *s->g);
	VertexPart_Map vertex_part = get(vertex_index1_t(), *s->g);

	int i;
	for (i = 0; i < vertices; i++) {
		Vertex v = add_vertex(*s->g);
		put(vertex_part, v, i);
		put(vertex_id, v + 1, i);

		if (DEBUG_LEVEL > 3)
			cout << "Added vertex " << i << "." << endl;
	}

	i = 0;
	while (i++ < edges) {
		if (in.get() != 'e') {
			cerr << "This parser is not capable of handling other information than edge definitions after the p-line." << endl;
			return NULL;
		}

		int source, target;
		cin >> source >> target;

		if (!(source <= vertices && target <= vertices)) {
			cerr << "Invalid edge (" << source << "|" << target << ") read." << endl;
			return NULL;
		}

		if (DEBUG_LEVEL > 3)
			cout << "Added edge (" << source << "|" << target << ")." << endl;

		add_edge(source - 1, target - 1, *s->g);

		if (in.get() != '\n') {
			cerr << "Malformed edge definition read (edge line " << (i + 1) << " not terminated by newline)!" << endl;
			return NULL;
		}
	}

	if (DEBUG_LEVEL > 3)
		cout << "Reading input successfully finished!" << endl;

	s->partition = new int[vertices];
	s->representatives = new int[vertices];
	s->numParts = vertices;
	s->colorsUsed = vertices;

	return s;
}

Solution* Solution::fromColBStream(istream& in) {
	Solution *s = new Solution;
	char buffer[PARSE_BUFFERSIZE];

	int length;
	cin >> length;

	while (cin.get() != 'p')
		cin.ignore(numeric_limits<streamsize>::max(), '\n');

	cin.get();
	cin.getline(buffer, PARSE_BUFFERSIZE, ' ');

	if (strcmp(buffer, "edge") != 0) {
		cerr << "This parser is unable to read files using a FORMAT other than 'edge' ('" << buffer << "' specified)" << endl;
		return NULL;
	}

	int vertices, edges, i, j;
	cin >> vertices >> edges;
	char bitmap[vertices][vertices / 8];

	VertexID_Map vertex_id = get(vertex_index2_t(), *s->g);
	VertexPart_Map vertex_part = get(vertex_index1_t(), *s->g);

	for (i = 0; i < vertices; i++) {
		Vertex v = add_vertex(*s->g);
		put(vertex_part, v, i);
		put(vertex_id, v + 1, i);

		//if (DEBUG_LEVEL > 3)
			//cout << "Added vertex " << i << endl;

		cin.read(bitmap[i], (i + 8) / 8);

		cout << bitmap[i];
	}

	for (i = 0; i < vertices; i++)
		for (j = 0; j <= i; j++)
				if ((bitmap[i][j >> 3] & (1 << (7 - (j & 7)))) != 0) {
					cout << "Added edge (" << i << "|" << j << ")." << endl;
					add_edge(i, j, *s->g);
				}
	return s;
}

void Solution::print(ostream& out) {
	vector<string> partitions(this->numParts);

	pair<VertexIter, VertexIter> vp;
	for (vp = vertices(*this->g); vp.first != vp.second; ++vp.first) {
		partitions[this->getPartition(*vp.first)] += "\t\t" + lexical_cast<string>(this->getOriginalId(*vp.first)) + ";\n";
 	}

 	out << "graph pcp {" << endl;
 	out << "\tnode [shape = circle]" << endl;
 	out << "\tstyle = rounded" << endl;

 	int counter = 0;
 	for (vector<string>::iterator i = partitions.begin(); i < partitions.end(); i++) {
 		out << "\tsubgraph cluster" << counter << " {" << endl;
 		out << *i << endl;
 		out << "\t\tcolor = " << graphvizColors[partition[counter]] << endl;
 		out << "\t\tlabel = " << counter++ << endl;
 		out << "\t}" << endl;
 	}

 	graph_traits<Graph>::edge_iterator i, end;
	for (tie(i, end) = edges(*this->g); i != end; i++)
		out << "\t" << lexical_cast<string>(getOriginalId(source(*i, *this->g))) << " -- " << lexical_cast<string>(getOriginalId(target(*i, *this->g))) << ";" << endl;

 	out << "}" << endl;
}
<commit_msg>Added partNodes initialization to .col and .col.b parser<commit_after>#include "header/Solution.hpp"

using namespace std;
using namespace pcp;
using namespace boost;

Solution::Solution() {
	this->g = new Graph(0);
	this->colorsUsed = 0;
	this->partitionMap = get(vertex_index1_t(), *this->g);
	this->idMap = get(vertex_index2_t(), *this->g);
}

Solution::Solution(Solution *toCopy) {
	this->partNodes = NULL;
	this->g = new Graph(0);
	this->numParts = toCopy->numParts;
	this->partition = new int[this->numParts];
	this->representatives = new int[this->numParts];

	for (int i = 0; i < this->numParts; i++) {
		this->partition[i] = toCopy->partition[i];
		this->representatives[i] = toCopy->representatives[i];
	}
	this->colorsUsed = toCopy->colorsUsed;
	copy_graph(*toCopy->g, *this->g);
	this->partitionMap = get(vertex_index1_t(), *this->g);
	this->idMap = get(vertex_index2_t(), *this->g);
}

Solution::~Solution() {
	delete g;
	delete[] partition;
	delete[] representatives;
}

int Solution::getPartition(Vertex v) {
	return get(this->partitionMap, v);
}

int Solution::getOriginalId(Vertex v) {
	return get(this->idMap, v);
}

int Solution::getPartitionColor(Vertex v) {
	return partition[getPartition(v)];
}

void Solution::setPartitionColor(Vertex v, int color) {
	partition[getPartition(v)] = color;
}

bool Solution::isPartitionColored(Vertex v) {
	return getPartitionColor(v) != -1;
}

int Solution::getColorDegree(Vertex node) {
	int colored = 0;
	AdjIter i, end;

	for (tie(i, end) = adjacent_vertices(node, *this->g); i != end; i++)
		if (this->isPartitionColored(*i))
			colored++;

	return colored;
}

int Solution::minPossibleColor(Vertex node) {
	bool* colors = new bool[this->numParts];
	fill(colors, colors + this->numParts, false);
	AdjIter i, end;

	for (tie(i, end) = adjacent_vertices(node, *this->g); i != end; i++)
		if (this->isPartitionColored(*i))
			colors[this->partition[this->getPartition(*i)]] = true;

	for (int i = 0; i < this->numParts; i++) {
		if (!colors[i]) {
			delete[] colors;
			return i;
		}
	}

	return -1;
}

Solution* Solution::fromPcpStream(istream& in) {
	Solution *s = new Solution();

	int vertices, edges, partitions;
	cin >> vertices >> edges >> partitions;

	if (DEBUG_LEVEL > 3) {
		cout << "Reading " << vertices << " vertices, " << edges << " edges and ";
		cout << partitions << " partitons ..." << endl;
	}

	/// Initialize the solution to the read parameters
	s->partition = new int[partitions];
	s->representatives = new int[partitions];
	s->partNodes = new vector<Vertex>[partitions];
	s->numParts = partitions;
	s->colorsUsed = partitions;

	/// Initialize the property maps for partition and vertexID
	VertexID_Map vertex_id = get(vertex_index2_t(), *s->g);
	VertexPart_Map vertex_part = get(vertex_index1_t(), *s->g);

	/// Read partition info and store it into the property map, do the same
	/// for the "original" vertexID, so they can be compared on all graph
	int i, part;
	for (i = 0; i < vertices; i++) {
		cin >> part;
		Vertex v = add_vertex(*s->g);
		put(vertex_part, v, part);
		put(vertex_id, v, i);
		s->partNodes[part].push_back(v);

		if (DEBUG_LEVEL > 3)
			cout << "Added vertex " << i << " to partition " << part << "." << endl;
	}

	/// Read the input for edges between to vertices and add them to the
	/// solution graph
	for (i = 0; i < edges; i++) {
		int source, target;
		cin >> source >> target;

		if (DEBUG_LEVEL > 3) {
			cout << "Added edge (" << source << "|" << target << ")." << endl;
		}
		add_edge(source, target, *s->g);
	}

	if (DEBUG_LEVEL > 3)
		cout << "Parsing input finished successfully!" << endl;

	return s;
}

Solution* Solution::fromColStream(istream& in) {
	Solution *s = new Solution;

	char buffer[PARSE_BUFFERSIZE];

	/// Ignore all lines until first encounter of the p line
	while (in.get() != 'p')
		in.ignore(numeric_limits<streamsize>::max(), '\n');

	in.get();
	in.getline(buffer, PARSE_BUFFERSIZE, ' ');

	if (strcmp(buffer, "edge") != 0) {
		cerr << "This parser is unable to read files using a FORMAT other than 'edge' ('" << buffer << "' specified)" << endl;
		return NULL;
	}

	int vertices, edges;
	cin >> vertices >> edges;

	if (DEBUG_LEVEL > 3)
		cout << "Reading " << edges << " edges ..." << endl;

	if (in.get() != '\n') {
		cerr << "Malformed p-line detected (not terminated by newline)!" << endl;
		return NULL;
	}

	/// Initialize the property maps for partition and vertexID
	VertexID_Map vertex_id = get(vertex_index2_t(), *s->g);
	VertexPart_Map vertex_part = get(vertex_index1_t(), *s->g);

	s->partNodes = new vector<Vertex>[vertices];

	int i;
	for (i = 0; i < vertices; i++) {
		Vertex v = add_vertex(*s->g);
		put(vertex_part, v, i);
		put(vertex_id, v + 1, i);
		s->partNodes[i].push_back(v);
	}

	i = 0;
	while (i++ < edges) {
		if (in.get() != 'e') {
			cerr << "This parser is not capable of handling other information than edge definitions after the p-line." << endl;
			return NULL;
		}

		int source, target;
		cin >> source >> target;

		if (!(source <= vertices && target <= vertices)) {
			cerr << "Invalid edge (" << source << "|" << target << ") read." << endl;
			return NULL;
		}

		if (DEBUG_LEVEL > 3)
			cout << "Added edge (" << source << "|" << target << ")." << endl;

		add_edge(source - 1, target - 1, *s->g);

		if (in.get() != '\n') {
			cerr << "Malformed edge definition read (edge line " << (i + 1) << " not terminated by newline)!" << endl;
			return NULL;
		}
	}

	if (DEBUG_LEVEL > 3)
		cout << "Reading input successfully finished!" << endl;

	s->partition = new int[vertices];
	s->representatives = new int[vertices];
	s->numParts = vertices;
	s->colorsUsed = vertices;

	return s;
}

Solution* Solution::fromColBStream(istream& in) {
	Solution *s = new Solution;
	char buffer[PARSE_BUFFERSIZE];

	int length;
	cin >> length;

	while (cin.get() != 'p')
		cin.ignore(numeric_limits<streamsize>::max(), '\n');

	cin.get();
	cin.getline(buffer, PARSE_BUFFERSIZE, ' ');

	if (strcmp(buffer, "edge") != 0) {
		cerr << "This parser is unable to read files using a FORMAT other than 'edge' ('" << buffer << "' specified)" << endl;
		return NULL;
	}

	int vertices, edges, i, j;
	cin >> vertices >> edges;
	char bitmap[vertices][vertices / 8];

	VertexID_Map vertex_id = get(vertex_index2_t(), *s->g);
	VertexPart_Map vertex_part = get(vertex_index1_t(), *s->g);

	s->partNodes = new vector<Vertex>[vertices];

	for (i = 0; i < vertices; i++) {
		Vertex v = add_vertex(*s->g);
		put(vertex_part, v, i);
		put(vertex_id, v + 1, i);
		s->partNodes[i].push_back(v);

		cin.read(bitmap[i], (i + 8) / 8);
		cout << bitmap[i];
	}

	for (i = 0; i < vertices; i++)
		for (j = 0; j <= i; j++)
				if ((bitmap[i][j >> 3] & (1 << (7 - (j & 7)))) != 0) {
					cout << "Added edge (" << i << "|" << j << ")." << endl;
					add_edge(i, j, *s->g);
				}
	return s;
}

void Solution::print(ostream& out) {
	vector<string> partitions(this->numParts);

	pair<VertexIter, VertexIter> vp;
	for (vp = vertices(*this->g); vp.first != vp.second; ++vp.first) {
		partitions[this->getPartition(*vp.first)] += "\t\t" + lexical_cast<string>(this->getOriginalId(*vp.first)) + ";\n";
 	}

 	out << "graph pcp {" << endl;
 	out << "\tnode [shape = circle]" << endl;
 	out << "\tstyle = rounded" << endl;

 	int counter = 0;
 	for (vector<string>::iterator i = partitions.begin(); i < partitions.end(); i++) {
 		out << "\tsubgraph cluster" << counter << " {" << endl;
 		out << *i << endl;
 		out << "\t\tcolor = " << graphvizColors[partition[counter]] << endl;
 		out << "\t\tlabel = " << counter++ << endl;
 		out << "\t}" << endl;
 	}

 	graph_traits<Graph>::edge_iterator i, end;
	for (tie(i, end) = edges(*this->g); i != end; i++)
		out << "\t" << lexical_cast<string>(getOriginalId(source(*i, *this->g))) << " -- " << lexical_cast<string>(getOriginalId(target(*i, *this->g))) << ";" << endl;

 	out << "}" << endl;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File: NekMatrix.hpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Generic Matrix
//
///////////////////////////////////////////////////////////////////////////////

#ifndef NEKTAR_LIB_UTILITIES_NEK_MATRIX_HPP
#define NEKTAR_LIB_UTILITIES_NEK_MATRIX_HPP

#include <loki/Factory.h>
#include <loki/Singleton.h>
#include <loki/Typelist.h>

#include <boost/shared_ptr.hpp>
#include <boost/call_traits.hpp>
#include <boost/concept_check.hpp>

#include <LibUtilities/NekMemoryManager.hpp>

namespace Nektar
{
    namespace LibUtilities
    {

        enum NekMatrixForm
        {
            eFull,
            eZero,
            eDiagonal,
            eSquareSymmetric,
            eSquareSymmetricPositiveDefinite,
            eSymmetricPositiveDefiniteBanded,
            eSquareGeneral,
            eSquareGeneralBanded
        };

        class OutOfBoundsError
        {
        };

        // Used to force the NekMatrix factory to register.
        template<typename MatrixType>
        class NekMatrixFunctionRegistration
        {
            public:
                void constraints()
                {
                    MatrixType* m;
                    m->RegisterCreateFuncs();
                }
        };

        /// NekMatrix Class
        /// \param width the width of the matrix.  Setting this to 0 allows for dynamically sized matrices.
        /// \param height The height of the matrix.  Setting this to 0 allows for dynamically size matrices.
        ///
        /// Some design decisions about the class.
        /// Only one factory object.  All impl objects need to implement the
        /// Initialize methods.  I could have made many constructors for the
        /// impl object constructors, but then I would have had a lot of messy
        /// Factory objects to created, one for each constructor.
        template<typename DataType, unsigned int NumRows = 0, unsigned int NumColumns = 0, unsigned int space = 0>
        class NekMatrix
        {

            public:
                NekMatrix(NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, NumRows, NumColumns))
                {
                    m_impl->Initialize();
                }

                NekMatrix(unsigned int rows, unsigned int columns, NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, rows, columns))
                {
                    m_impl->Initialize();
                }

                explicit NekMatrix(const DataType* const ptr, NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, NumRows, NumColumns))
                {
                    m_impl->Initialize(ptr);
                }

                NekMatrix(const DataType* const ptr, unsigned int rows, unsigned int columns,
                          NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, rows, columns))
                {
                    m_impl->Initialize(ptr);
                }

                NekMatrix(typename boost::call_traits<DataType>::param_type d, NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, NumRows, NumColumns))
                {
                    m_impl->Initialize(d);
                }

                NekMatrix(typename boost::call_traits<DataType>::param_type d,
                          unsigned int rows, unsigned int columns, NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, rows, columns))
                {
                    m_impl->Initialize(d);
                }

                unsigned int rows() const { return m_impl->rows(); }
                unsigned int columns() const { return m_impl->columns(); }

                typename boost::call_traits<DataType>::reference operator()
                        (unsigned int rowNumber, unsigned int colNumber)
                {
                    if( rowNumber >= rows() || colNumber >= columns() )
                    {
                        throw OutOfBoundsError();
                    }

                    return (*m_impl)(rowNumber, colNumber);
                }

                typename boost::call_traits<DataType>::const_reference operator()
                        (unsigned int rowNumber, unsigned int colNumber) const
                {
                    assert(fullRegistered);
                    if( rowNumber >= rows() || colNumber >= columns() )
                    {
                        throw OutOfBoundsError();
                    }

                    return (*m_impl)(rowNumber, colNumber);
                }

                bool RegisterCreateFuncs()
                {
                    return fullRegistered;
                }

                typedef NekMatrix<DataType, NumRows, NumColumns, space> MyType;
                BOOST_CLASS_REQUIRE(MyType, LibUtilities, NekMatrixFunctionRegistration);

                NekMatrix<DataType, NumRows, NumColumns, space> operator+=(const NekMatrix<DataType, NumRows, NumColumns, space>& rhs)
                {
                    for(unsigned int i = 0; i < rows(); ++i)
                    {
                        for(unsigned int j = 0; j < columns(); ++j)
                        {
                            (*this)(i,j) += rhs(i,j);
                        }
                    }

                    return *this;
                }

            private:
                // The implementation classes prevent the need for enumerated types
                // and large nested switch statements.
                class NekMatrixImpl
                {
                    public:
                        NekMatrixImpl(unsigned int rows, unsigned int columns) :
                            m_rows(rows),
                            m_columns(columns)
                        {
                        }

                        NekMatrixImpl(const NekMatrixImpl& rhs) :
                            m_rows(rhs.m_rows),
                            m_columns(rhs.m_columns)
                        {
                        }

                        virtual ~NekMatrixImpl()
                        {
                        };

                        NekMatrixImpl& operator=(const NekMatrixImpl& rhs)
                        {
                            m_rows = rhs.m_rows;
                            m_columns = rhs.m_columns;
                            return *this;
                        }

                        virtual void Initialize() = 0;
                        virtual void Initialize(const DataType* const p) = 0;
                        virtual void Initialize(typename boost::call_traits<DataType>::param_type d) = 0;

                        unsigned int rows() const { return m_rows; }
                        unsigned int columns() const { return m_columns; }

                        virtual typename boost::call_traits<DataType>::reference operator()
                                (unsigned int rowNumber, unsigned int colNumber) = 0;

                        virtual typename boost::call_traits<DataType>::const_reference operator()
                                (unsigned int rowNumber, unsigned int colNumber) const = 0;

                    protected:

                    private:
                        unsigned int m_rows;
                        unsigned int m_columns;
                };

                // Factory to generate implementations based upon the MatrixForm.
                typedef Loki::SingletonHolder< Loki::Factory<NekMatrixImpl, NekMatrixForm,
                    Loki::TL::MakeTypelist<unsigned int, unsigned int>::Result > >
                    NekMatrixImplFactory;

                class NekFullMatrixImpl : public NekMatrixImpl
                {
                    public:
                        NekFullMatrixImpl(unsigned int rows, unsigned int columns) :
                            NekMatrixImpl(rows, columns),
                            m_data()
                        {
                        }

                        NekFullMatrixImpl(const NekFullMatrixImpl& rhs) :
                            NekMatrixImpl(rhs),
                            m_data()
                        {
                            CreateSharedArray();
                            std::copy(rhs.begin(), rhs.end(), begin());
                        }

                        NekFullMatrixImpl& operator=(const NekFullMatrixImpl& rhs)
                        {
                            if( this != &rhs )
                            {
                                NekMatrixImpl::operator=(rhs);
                                CreateSharedArray();
                                std::copy(rhs.begin(), rhs.end(), begin());
                            }

                            return *this;
                        }

                        virtual ~NekFullMatrixImpl() {}

                        virtual void Initialize()
                        {
                            CreateSharedArray();

                            // Don't do anything else, it is up to the user
                            // to initialize.
                        }

                        virtual void Initialize(const DataType* const p)
                        {
                            CreateSharedArray();
                            std::copy(p, p+(rows()*columns()), begin());
                        }

                        virtual void Initialize(typename boost::call_traits<DataType>::param_type d)
                        {
                            CreateSharedArray();
                            std::fill(begin(), end(), d);
                        }

                        DataType* begin()
                        {
                            return &m_data[0];
                        }

                        DataType* end()
                        {
                            return &m_data[rows()*columns()];
                        }

                        typename boost::call_traits<DataType>::reference operator()
                            (unsigned int rowNumber, unsigned int colNumber)
                        {
                            return m_data[rowNumber*columns() + colNumber];
                        }

                        typename boost::call_traits<DataType>::const_reference operator()
                                (unsigned int rowNumber, unsigned int colNumber) const
                        {
                            return m_data[rowNumber*columns() + colNumber];
                        }

                        static const MemoryManager::MemoryPoolEnabler MemoryPoolEnabled = MemoryManager::eEnabled;

                    protected:
                        void CreateSharedArray()
                        {
                            //m_data = MemoryManager::AllocateSharedArray<DataType>(rows()*columns());
                            //m_data = new DataType[rows()*columns()];
                            m_data = boost::shared_array<DataType>(new DataType[rows()*columns()]);
                        }

                    private:
                        NekFullMatrixImpl();
                        boost::shared_array<DataType> m_data;
                        //DataType* m_data;
                };

                static NekFullMatrixImpl* createFullMatrix(unsigned int rows, unsigned int cols)
                {
                    //return MemoryManager::Allocate<NekFullMatrixImpl>(rows, cols);
                    return new NekFullMatrixImpl(rows, cols);
                }

                static const bool fullRegistered;

                NekMatrixForm m_form;
                boost::shared_ptr<NekMatrixImpl> m_impl;
        };

        template<typename DataType, unsigned int width, unsigned int height, unsigned int space>
        const bool NekMatrix<DataType, width, height, space>::fullRegistered =
                NekMatrix<DataType, width, height, space>::NekMatrixImplFactory::
                Instance().Register(eFull, NekMatrix<DataType, width, height, space>::createFullMatrix);

        template<typename DataType, unsigned int NumRows, unsigned int NumColumns, unsigned int space>
        NekMatrix<DataType, NumRows, NumColumns, space> operator+(
                const NekMatrix<DataType, NumRows, NumColumns, space>& lhs,
                const NekMatrix<DataType, NumRows, NumColumns, space>& rhs)
        {
            NekMatrix<DataType, NumRows, NumColumns, space> result(lhs);
            result += rhs;
            return result;
        }
    }
}

#endif //NEKTAR_LIB_UTILITIES_NEK_MATRIX_HPP

/**
    $Log: NekMatrix.hpp,v $
    Revision 1.3  2006/05/15 04:13:36  bnelson
    no message

    Revision 1.2  2006/05/14 21:32:03  bnelson
    *** empty log message ***

    Revision 1.1  2006/05/04 18:57:43  kirby
    *** empty log message ***

    Revision 1.1  2006/04/11 02:00:43  bnelson
    Initial Revision

**/

<commit_msg>Removed the ability to specify the rows and columns in the template parameter list.  If this behavior is desired we'll need to create a fixed size array class.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File: NekMatrix.hpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Generic Matrix
//
///////////////////////////////////////////////////////////////////////////////

#ifndef NEKTAR_LIB_UTILITIES_NEK_MATRIX_HPP
#define NEKTAR_LIB_UTILITIES_NEK_MATRIX_HPP

#include <loki/Factory.h>
#include <loki/Singleton.h>
#include <loki/Typelist.h>

#include <boost/shared_ptr.hpp>
#include <boost/call_traits.hpp>
#include <boost/concept_check.hpp>

#include <LibUtilities/NekMemoryManager.hpp>
#include <LibUtilities/ErrorUtil.hpp>

namespace Nektar
{
    namespace LibUtilities
    {

        enum NekMatrixForm
        {
            eFull//,
//             eZero,
//             eDiagonal,
//             eSquareSymmetric,
//             eSquareSymmetricPositiveDefinite,
//             eSymmetricPositiveDefiniteBanded,
//             eSquareGeneral,
//             eSquareGeneralBanded
        };

        class OutOfBoundsError
        {
        };

        // Used to force the NekMatrix factory to register.
        template<typename MatrixType>
        class NekMatrixFunctionRegistration
        {
            public:
                void constraints()
                {
                    MatrixType* m;
                    m->RegisterCreateFuncs();
                }
        };

        /// NekMatrix Class
        /// \param width the width of the matrix.  Setting this to 0 allows for dynamically sized matrices.
        /// \param height The height of the matrix.  Setting this to 0 allows for dynamically size matrices.
        ///
        /// Some design decisions about the class.
        /// Only one factory object.  All impl objects need to implement the
        /// Initialize methods.  I could have made many constructors for the
        /// impl object constructors, but then I would have had a lot of messy
        /// Factory objects to created, one for each constructor.
        template<typename DataType, unsigned int space = 0>
        class NekMatrix
        {

            public:
                NekMatrix(unsigned int rows, unsigned int columns, NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, rows, columns))
                {
                    m_impl->Initialize();
                }

                NekMatrix(const DataType* const ptr, unsigned int rows, unsigned int columns,
                          NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, rows, columns))
                {
                    m_impl->Initialize(ptr);
                }

                NekMatrix(typename boost::call_traits<DataType>::param_type d,
                          unsigned int rows, unsigned int columns, NekMatrixForm form = eFull) :
                    m_form(form),
                    m_impl(NekMatrixImplFactory::Instance().CreateObject(form, rows, columns))
                {
                    m_impl->Initialize(d);
                }

                unsigned int rows() const { return m_impl->rows(); }
                unsigned int columns() const { return m_impl->columns(); }

                typename boost::call_traits<DataType>::reference operator()
                        (unsigned int rowNumber, unsigned int colNumber)
                {
                    if( rowNumber >= rows() || colNumber >= columns() )
                    {
                        throw OutOfBoundsError();
                    }

                    return (*m_impl)(rowNumber, colNumber);
                }

                typename boost::call_traits<DataType>::const_reference operator()
                        (unsigned int rowNumber, unsigned int colNumber) const
                {
                    assert(fullRegistered);
                    if( rowNumber >= rows() || colNumber >= columns() )
                    {
                        throw OutOfBoundsError();
                    }

                    return (*m_impl)(rowNumber, colNumber);
                }

                bool RegisterCreateFuncs()
                {
                    return fullRegistered;
                }

                typedef NekMatrix<DataType, space> MyType;
                BOOST_CLASS_REQUIRE(MyType, LibUtilities, NekMatrixFunctionRegistration);

                NekMatrix<DataType, space> operator+=(const NekMatrix<DataType, space>& rhs)
                {
                    ASSERTL0(rows() == rhs.rows() && columns() == rhs.columns(), "Matrix dimensions must agree in operator+");
                    for(unsigned int i = 0; i < rows(); ++i)
                    {
                        for(unsigned int j = 0; j < columns(); ++j)
                        {
                            (*this)(i,j) += rhs(i,j);
                        }
                    }

                    return *this;
                }

            private:
                // The implementation classes prevent the need for enumerated types
                // and large nested switch statements.
                class NekMatrixImpl
                {
                    public:
                        NekMatrixImpl(unsigned int rows, unsigned int columns) :
                            m_rows(rows),
                            m_columns(columns)
                        {
                        }

                        NekMatrixImpl(const NekMatrixImpl& rhs) :
                            m_rows(rhs.m_rows),
                            m_columns(rhs.m_columns)
                        {
                        }

                        virtual ~NekMatrixImpl()
                        {
                        };

                        NekMatrixImpl& operator=(const NekMatrixImpl& rhs)
                        {
                            m_rows = rhs.m_rows;
                            m_columns = rhs.m_columns;
                            return *this;
                        }

                        virtual void Initialize() = 0;
                        virtual void Initialize(const DataType* const p) = 0;
                        virtual void Initialize(typename boost::call_traits<DataType>::param_type d) = 0;

                        unsigned int rows() const { return m_rows; }
                        unsigned int columns() const { return m_columns; }

                        virtual typename boost::call_traits<DataType>::reference operator()
                                (unsigned int rowNumber, unsigned int colNumber) = 0;

                        virtual typename boost::call_traits<DataType>::const_reference operator()
                                (unsigned int rowNumber, unsigned int colNumber) const = 0;

                    protected:

                    private:
                        unsigned int m_rows;
                        unsigned int m_columns;
                };

                // Factory to generate implementations based upon the MatrixForm.
                typedef Loki::SingletonHolder< Loki::Factory<NekMatrixImpl, NekMatrixForm,
                    Loki::TL::MakeTypelist<unsigned int, unsigned int>::Result > >
                    NekMatrixImplFactory;

                class NekFullMatrixImpl : public NekMatrixImpl
                {
                    public:
                        NekFullMatrixImpl(unsigned int rows, unsigned int columns) :
                            NekMatrixImpl(rows, columns),
                            m_data()
                        {
                        }

                        NekFullMatrixImpl(const NekFullMatrixImpl& rhs) :
                            NekMatrixImpl(rhs),
                            m_data()
                        {
                            CreateSharedArray();
                            std::copy(rhs.begin(), rhs.end(), begin());
                        }

                        NekFullMatrixImpl& operator=(const NekFullMatrixImpl& rhs)
                        {
                            if( this != &rhs )
                            {
                                NekMatrixImpl::operator=(rhs);
                                CreateSharedArray();
                                std::copy(rhs.begin(), rhs.end(), begin());
                            }

                            return *this;
                        }

                        virtual ~NekFullMatrixImpl() {}

                        virtual void Initialize()
                        {
                            CreateSharedArray();

                            // Don't do anything else, it is up to the user
                            // to initialize.
                        }

                        virtual void Initialize(const DataType* const p)
                        {
                            CreateSharedArray();
                            std::copy(p, p+(rows()*columns()), begin());
                        }

                        virtual void Initialize(typename boost::call_traits<DataType>::param_type d)
                        {
                            CreateSharedArray();
                            std::fill(begin(), end(), d);
                        }

                        DataType* begin()
                        {
                            return &m_data[0];
                        }

                        DataType* end()
                        {
                            return &m_data[rows()*columns()];
                        }

                        typename boost::call_traits<DataType>::reference operator()
                            (unsigned int rowNumber, unsigned int colNumber)
                        {
                            return m_data[rowNumber*columns() + colNumber];
                        }

                        typename boost::call_traits<DataType>::const_reference operator()
                                (unsigned int rowNumber, unsigned int colNumber) const
                        {
                            return m_data[rowNumber*columns() + colNumber];
                        }

                        static const MemoryManager::MemoryPoolEnabler MemoryPoolEnabled = MemoryManager::eEnabled;

                    protected:
                        void CreateSharedArray()
                        {
                            m_data = MemoryManager::AllocateSharedArray<DataType>(rows()*columns());
                            //m_data = new DataType[rows()*columns()];
                            //m_data = boost::shared_array<DataType>(new DataType[rows()*columns()]);
                        }

                    private:
                        NekFullMatrixImpl();
                        boost::shared_array<DataType> m_data;
                        //DataType* m_data;
                };

                static NekFullMatrixImpl* createFullMatrix(unsigned int rows, unsigned int cols)
                {
                    //NekFullMatrixImpl* result = MemoryManager::Allocate<NekFullMatrixImpl>(rows, cols);
                    NekFullMatrixImpl* result = new NekFullMatrixImpl(rows, cols);
                    return result;
                }

                static const bool fullRegistered;

                NekMatrixForm m_form;

                // Change back to the shared pointer after finishing the
                // NekFactory.
                //boost::shared_ptr<NekMatrixImpl> m_impl;
                NekMatrixImpl* m_impl;
        };

        template<typename DataType, unsigned int space>
        const bool NekMatrix<DataType, space>::fullRegistered =
                NekMatrix<DataType, space>::NekMatrixImplFactory::
                Instance().Register(eFull, NekMatrix<DataType, space>::createFullMatrix);

        template<typename DataType, unsigned int space>
        NekMatrix<DataType, space> operator+(
                const NekMatrix<DataType, space>& lhs,
                const NekMatrix<DataType, space>& rhs)
        {
            NekMatrix<DataType, space> result(lhs);
            result += rhs;
            return result;
        }

        template<typename DataType, unsigned int space>
        NekMatrix<DataType, space> operator*(
            const NekMatrix<DataType, space>& lhs,
            const NekMatrix<DataType, space>& rhs)
        {
            ASSERTL0(lhs.columns() == rhs.rows(), "Invalid matrix dimensions in operator*");

            NekMatrix<DataType, space> result(lhs.rows(), rhs.columns());

            for(unsigned int i = 0; i < result.rows(); ++i)
            {
                for(unsigned int j = 0; j < result.columns(); ++j)
                {
                    DataType t = DataType(0);

                    // Set the result(i,j) element.
                    for(unsigned int k = 0; k < lhs.columns(); ++k)
                    {
                        t += lhs(i,k)*rhs(k,j);
                    }
                    result(i,j) = t;
                }
            }

            return result;
        }

    }
}

#endif //NEKTAR_LIB_UTILITIES_NEK_MATRIX_HPP

/**
    $Log: NekMatrix.hpp,v $
    Revision 1.4  2006/05/15 05:06:55  bnelson
    Removed use of MemoryManager pending review of some memory problems.

    Revision 1.3  2006/05/15 04:13:36  bnelson
    no message

    Revision 1.2  2006/05/14 21:32:03  bnelson
    *** empty log message ***

    Revision 1.1  2006/05/04 18:57:43  kirby
    *** empty log message ***

    Revision 1.1  2006/04/11 02:00:43  bnelson
    Initial Revision

**/

<|endoftext|>


<commit_before>#include "interp.hh"
#include "util.hh"

#include <algorithm>
#include <iostream>
using namespace std;

BlockInterpreter::BlockInterpreter(Block *block) : block(block), arguments(block->arguments.size()) {
	transform (	block->arguments.begin(),
			block->arguments.end(),
			arguments.begin(),
			&Interpreter::get);
}

maybe<Value> BlockInterpreter::next(Scope s) {
	/// @todo this could (and should) be way cleaner
	//
	if (block->arguments.size() == 0) {
		// When there are no arguments, the block is considered to
		// output a single value.

		if (last.isDefined() && s != last.get())
			return maybe<Value>();
		else if (last.isDefined())
			return lastVal;

		// We've never run before
		last = maybe<Scope>(s);
		lastVal = maybe<Value>(functions[block->fname](block->params, {}));
		return lastVal;
	}

	if (last.isDefined() && s == last.get())
		return lastVal;

	last = maybe<Scope>(s);
	// There is at least one argument - evaluate the sources. The scope
	// will be the same as it was for us.
	vector < maybe <Value> > maybeargs(arguments.size());
	transform(arguments.begin(), arguments.end(), maybeargs.begin(),
			( [s] (Interpreter *i) -> maybe<Value> { return i->next(s); }));

	// The 'defined' state of all arguments must match.
	vector <bool> defined(arguments.size());
	transform(maybeargs.begin(), maybeargs.end(), defined.begin(),
			( [] (maybe <Value> m) -> bool { return m.isDefined(); }));
	bool def = defined[0];
	for (size_t i=1; i<defined.size(); i++)
		if (defined[i] != def) throw new TypeMismatchError();

	if (!def) return maybe<Value>();

	vector <Value> args(arguments.size());
	transform(maybeargs.begin(), maybeargs.end(), args.begin(),
			( [] (maybe <Value> m) -> Value { return m.get(); }));
	lastVal = maybe<Value>(functions[block->fname](block->params, args));
	return lastVal;
}

<commit_msg>Some cleanup<commit_after>#include "interp.hh"
#include "util.hh"

#include <algorithm>
#include <iostream>
using namespace std;

BlockInterpreter::BlockInterpreter(Block *block) : block(block), arguments(block->arguments.size()) {
	transform (	block->arguments.begin(),
			block->arguments.end(),
			arguments.begin(),
			&Interpreter::get);
}

maybe<Value> BlockInterpreter::next(Scope s) {
	/// @todo this could (and should) be way cleaner

	if (block->arguments.size() == 0) {
		// When there are no arguments, the block is considered to
		// output a single value.

		// If the scope has advanced, we're empty. Otherwise, if
		// there's a previous value, use it.
		if (last.isDefined() && s != last.get())
			return maybe<Value>();
		else if (last.isDefined())
			return lastVal;

		// We've never run before
		last = maybe<Scope>(s);
		lastVal = maybe<Value>(functions[block->fname](block->params, {}));
		return lastVal;
	}

	// If we were called before with the same scope, use that value.
	if (last.isDefined() && s == last.get())
		return lastVal;

	last = maybe<Scope>(s);
	// There is at least one argument - evaluate the sources. The scope
	// will be the same as it was for us.
	vector < maybe <Value> > maybeargs(arguments.size());
	transform(arguments.begin(), arguments.end(), maybeargs.begin(),
			( [s] (Interpreter *i) -> maybe<Value> { return i->next(s); }));

	// The 'defined' state of all arguments must match.
	vector <bool> defined(arguments.size());
	transform(maybeargs.begin(), maybeargs.end(), defined.begin(),
			( [] (maybe <Value> m) -> bool { return m.isDefined(); }));
	bool def = defined[0];
	for (size_t i=1; i<defined.size(); i++)
		if (defined[i] != def) throw new TypeMismatchError();

	if (!def) // The sources are done, so we are too.
		return maybe<Value>();

	// All values available - call the function.
	vector <Value> args(arguments.size());
	transform(maybeargs.begin(), maybeargs.end(), args.begin(),
			( [] (maybe <Value> m) -> Value { return m.get(); }));
	lastVal = maybe<Value>(functions[block->fname](block->params, args));
	return lastVal;
}

<|endoftext|>


<commit_before>/*
 *  qisplit.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <getopt.h>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>

#include "Util.h"
#include "Types.h"

#include "itkRescaleIntensityImageFilter.h"
#include "itkOtsuThresholdImageFilter.h"
#include "itkConnectedComponentImageFilter.h"
#include "itkLabelShapeKeepNObjectsImageFilter.h"
#include "itkRelabelComponentImageFilter.h"
#include "itkLabelStatisticsImageFilter.h"
#include "itkLabelStatisticsOpeningImageFilter.h"
#include "itkExtractImageFilter.h"
#include "itkImageMomentsCalculator.h"
#include "itkEuler3DTransform.h"
#include "itkTransformFileWriter.h"
#include "itkResampleImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"

using namespace std;

int main(int argc, char **argv) {
	bool verbose = false;
	int indexptr = 0, c;
	int keep = numeric_limits<int>::max(), size_threshold = -1, inwards = false, output_images = false;
	QI::ImageF::Pointer reference = ITK_NULLPTR;
	const string usage {
	"Usage is: qisplit input_file.nii [options]\n\
	\n\
	Options:\n\
		--help, -h    : Print this message\n\
		--verbose, -v : Print more information\n\
		--keep, -k N  : Keep N largest objects\n\
        --size, -s N  : Only keep objects with >N voxels\n\
		--ref, -r     : Specify a reference image for CoG\n\
		--oimgs       : Output images\n\
		--inwards     : Subjects were scanned facing 'inwards'\n"
	};

	const struct option long_options[] =
	{
		{"help", no_argument, 0, 'h'},
		{"verbose", no_argument, 0, 'v'},
		{"keep", required_argument, 0, 'k'},
        {"size", required_argument, 0, 's'},
		{"ref", required_argument, 0, 'r'},
		{"oimgs", no_argument, &output_images, true},
		{"inwards", no_argument, &inwards, true},
		{0, 0, 0, 0}
	};
	const char* short_options = "hvr:k:s:";

	while ((c = getopt_long(argc, argv, short_options, long_options, &indexptr)) != -1) {
		switch (c) {
		case 'v': verbose = true; break;
		case 'h':
			cout << usage << endl;
			return EXIT_SUCCESS;
		case 'r': {
			auto refFile = QI::ReadImageF::New();
			refFile->SetFileName(optarg);
			refFile->Update();
			reference = refFile->GetOutput();
			reference->DisconnectPipeline();
		} break;
		case 'k': keep = atoi(optarg); break;
        case 's': size_threshold = atoi(optarg); break;
		case 0: // longopts flag
			break;
		case '?': // getopt will print an error message
			return EXIT_FAILURE;
		default:
			cout << "Unhandled option " << string(1, c) << endl;
			return EXIT_FAILURE;
		}
	}

	if ((argc - optind) != 1) {
		cout << usage << endl;
		throw(runtime_error("Wrong number of input arguments."));
	}

	auto input = QI::ReadImageF::New();
	string fname(argv[optind++]);
	input->SetFileName(fname);
	string prefix = QI::StripExt(fname);

	typedef unsigned int TLabel;
	typedef itk::Image<TLabel, 3> TLabelImage;
	/*typedef itk::BinaryThresholdImageFilter<QI::ImageF, TLabelImage> TThreshFilter;
	auto threshold = TThreshFilter::New();
	threshold->SetInput(input->GetOutput());
	threshold->SetLowerThreshold(atof(argv[optind++]));
	threshold->SetUpperThreshold(numeric_limits<float>::infinity());
	threshold->SetInsideValue(1);
	threshold->SetOutsideValue(0);*/
    // Use an Otsu Threshold filter to generate the mask
    if (verbose) cout << "Generating Otsu mask" << endl;
    auto otsuFilter = itk::OtsuThresholdImageFilter<QI::ImageF, TLabelImage>::New();
    otsuFilter->SetInput(input->GetOutput());
    otsuFilter->SetOutsideValue(1);
    otsuFilter->SetInsideValue(0);
    otsuFilter->Update();

	auto CC = itk::ConnectedComponentImageFilter<TLabelImage, TLabelImage>::New();
	CC->SetInput(otsuFilter->GetOutput());

    typedef itk::RelabelComponentImageFilter<TLabelImage, TLabelImage> TRelabel;
    auto relabel = TRelabel::New();
    relabel->SetInput(CC->GetOutput());
    relabel->Update();
    // Relabel sorts on size by default, so now work out how many make the size threshold
    auto label_sizes = relabel->GetSizeOfObjectsInPixels();
    if (keep > label_sizes.size())
        keep = label_sizes.size();
    for (int i = 0; i < keep; i++) {
        cout << "Object " << i << " size " << label_sizes[i] << endl;
        if (label_sizes[i] < size_threshold) {
            keep = i;
            break;
        }
    }
    if (keep == 0) {
        cerr << "Found 0 objects to keep. Exiting." << endl;
        return EXIT_FAILURE;
    }
    if (verbose) cout << "Found " << keep << " objects to keep." << endl;

	typedef itk::LabelShapeKeepNObjectsImageFilter<TLabelImage> TKeepN;
	auto keepN = TKeepN::New();
	keepN->SetInput(relabel->GetOutput());
	keepN->SetBackgroundValue(0);
	keepN->SetNumberOfObjects(keep);
	keepN->SetAttribute(TKeepN::LabelObjectType::NUMBER_OF_PIXELS);

	if (verbose) cout << "Writing label image." << endl;
	auto output = itk::ImageFileWriter<TLabelImage>::New();
	output->SetInput(keepN->GetOutput());
	output->SetFileName(prefix + "_labels.nii");
	output->Update();

	typedef itk::LabelStatisticsImageFilter<QI::ImageF, TLabelImage> TLabelStats;
	auto labelStats = TLabelStats::New();
	labelStats->SetInput(input->GetOutput());
	labelStats->SetLabelInput(keepN->GetOutput());
	labelStats->Update();

	typedef itk::ImageMomentsCalculator<QI::ImageF> TMoments;
	TMoments::VectorType refCoG; refCoG.Fill(0);
	if (reference) {
		auto refMoments = TMoments::New();
		refMoments->SetImage(reference);
		refMoments->Compute();
		refCoG = refMoments->GetCenterOfGravity();
		if (verbose) cout << "Reference CoG is: " << refCoG << endl;
	}

    // Set these up to use in the loop
    typedef itk::ResampleImageFilter<TLabelImage, TLabelImage, double> TLabelResampler;
    typedef itk::NearestNeighborInterpolateImageFunction<TLabelImage, double> TLabelInterp;
    auto ilabels = TLabelInterp::New();
    ilabels->SetInputImage(keepN->GetOutput());
    auto rlabels = TLabelResampler::New();
    rlabels->SetInput(keepN->GetOutput());
    rlabels->SetInterpolator(ilabels);
    rlabels->SetDefaultPixelValue(0.);
    rlabels->SetOutputParametersFromImage(relabel->GetOutput());

    typedef itk::ResampleImageFilter<QI::ImageF, QI::ImageF, double> TResampleF;
    typedef itk::LinearInterpolateImageFunction<QI::ImageF, double> TLinearInterpF;
    auto interp = TLinearInterpF::New();
    interp->SetInputImage(input->GetOutput());
    auto rimage = TResampleF::New();
    rimage->SetInput(input->GetOutput());
    rimage->SetInterpolator(interp);
    rimage->SetDefaultPixelValue(0.);
    rimage->SetOutputParametersFromImage(input->GetOutput());

	for (auto i = 1; i <= keep; i++) {
		TLabelImage::RegionType region = labelStats->GetRegion(i);
		typedef itk::ExtractImageFilter<QI::ImageF, QI::ImageF> TExtractF;
		auto extract = TExtractF::New();
		extract->SetInput(input->GetOutput());
		extract->SetExtractionRegion(region);
		extract->SetDirectionCollapseToSubmatrix();
		extract->Update();

		auto moments = TMoments::New();
		moments->SetImage(extract->GetOutput());
		moments->Compute();
		TMoments::VectorType CoG = moments->GetCenterOfGravity();
		if (verbose) cout << "Writing object " << i << " CoG is " << CoG << endl;
		float rotateAngle = atan2(CoG[1], CoG[0]);
		if (inwards)
			rotateAngle = (M_PI / 2.) - rotateAngle;
		else
			rotateAngle = (M_PI * 3./2.) - rotateAngle;
		if (verbose) cout << "Rotation angle is " << (rotateAngle*180./M_PI) << " degrees" << endl;

		typedef itk::Euler3DTransform<double> TRigid;
		auto tfm = TRigid::New();
		tfm->SetIdentity();
		tfm->SetOffset(CoG - refCoG);
		//tfm->SetCenter(CoG); // Want to leave this at 0 due to how ITK transforms work
		tfm->SetRotation(0, 0, -rotateAngle);

		stringstream suffix; suffix << "_" << setfill('0') << setw(2) << i;
		if (output_images) {
            rlabels->SetTransform(tfm.GetPointer());
            rimage->SetTransform(tfm.GetPointer());

            auto rstats = TLabelStats::New();
			rstats->SetInput(rimage->GetOutput());
			rstats->SetLabelInput(rlabels->GetOutput());
			rstats->Update();

            auto rextract = itk::ExtractImageFilter<QI::ImageF, QI::ImageF>::New();
            rextract->SetInput(rimage->GetOutput());
            rextract->SetExtractionRegion(rstats->GetRegion(i));
            rextract->SetDirectionCollapseToSubmatrix();
            rextract->Update();

            fname = prefix + suffix.str() + ".nii";
            if (verbose) cout << "Writing output file " << fname << endl;
            auto routput = itk::ImageFileWriter<QI::ImageF>::New();
            routput->SetInput(rextract->GetOutput());
            routput->SetFileName(fname);
            routput->Update();
		}

		fname = prefix + suffix.str() + ".tfm";
		if (verbose) cout << "Writing transform file " << fname << endl;
  		auto tfmWriter = itk::TransformFileWriterTemplate<double>::New();
  		tfmWriter->SetInput(tfm);
  		tfmWriter->SetFileName(fname);
  		tfmWriter->Update();
	}
	return EXIT_SUCCESS;
}

<commit_msg>Changed to using a LabelMapMask filter to remove crud around images.<commit_after>/*
 *  qisplit.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <getopt.h>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>

#include "Util.h"
#include "Types.h"

#include "itkRescaleIntensityImageFilter.h"
#include "itkOtsuThresholdImageFilter.h"
#include "itkConnectedComponentImageFilter.h"
#include "itkLabelShapeKeepNObjectsImageFilter.h"
#include "itkRelabelComponentImageFilter.h"
#include "itkLabelStatisticsImageFilter.h"
#include "itkLabelImageToLabelMapFilter.h"
#include "itkLabelMapMaskImageFilter.h"
#include "itkExtractImageFilter.h"
#include "itkImageMomentsCalculator.h"
#include "itkEuler3DTransform.h"
#include "itkTransformFileWriter.h"
#include "itkResampleImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"

using namespace std;

int main(int argc, char **argv) {
	bool verbose = false;
	int indexptr = 0, c;
	int keep = numeric_limits<int>::max(), size_threshold = -1, inwards = false, output_images = false;
	QI::ImageF::Pointer reference = ITK_NULLPTR;
	const string usage {
	"Usage is: qisplit input_file.nii [options]\n\
	\n\
	Options:\n\
		--help, -h    : Print this message\n\
		--verbose, -v : Print more information\n\
		--keep, -k N  : Keep N largest objects\n\
        --size, -s N  : Only keep objects with >N voxels\n\
		--ref, -r     : Specify a reference image for CoG\n\
		--oimgs       : Output images\n\
		--inwards     : Subjects were scanned facing 'inwards'\n"
	};

	const struct option long_options[] =
	{
		{"help", no_argument, 0, 'h'},
		{"verbose", no_argument, 0, 'v'},
		{"keep", required_argument, 0, 'k'},
        {"size", required_argument, 0, 's'},
		{"ref", required_argument, 0, 'r'},
		{"oimgs", no_argument, &output_images, true},
		{"inwards", no_argument, &inwards, true},
		{0, 0, 0, 0}
	};
	const char* short_options = "hvr:k:s:";

	while ((c = getopt_long(argc, argv, short_options, long_options, &indexptr)) != -1) {
		switch (c) {
		case 'v': verbose = true; break;
		case 'h':
			cout << usage << endl;
			return EXIT_SUCCESS;
		case 'r': {
			auto refFile = QI::ReadImageF::New();
			refFile->SetFileName(optarg);
			refFile->Update();
			reference = refFile->GetOutput();
			reference->DisconnectPipeline();
		} break;
		case 'k': keep = atoi(optarg); break;
        case 's': size_threshold = atoi(optarg); break;
		case 0: // longopts flag
			break;
		case '?': // getopt will print an error message
			return EXIT_FAILURE;
		default:
			cout << "Unhandled option " << string(1, c) << endl;
			return EXIT_FAILURE;
		}
	}

	if ((argc - optind) != 1) {
		cout << usage << endl;
		throw(runtime_error("Wrong number of input arguments."));
	}

	auto input = QI::ReadImageF::New();
	string fname(argv[optind++]);
	input->SetFileName(fname);
	string prefix = QI::StripExt(fname);

	typedef unsigned int TLabel;
	typedef itk::Image<TLabel, 3> TLabelImage;
	/*typedef itk::BinaryThresholdImageFilter<QI::ImageF, TLabelImage> TThreshFilter;
	auto threshold = TThreshFilter::New();
	threshold->SetInput(input->GetOutput());
	threshold->SetLowerThreshold(atof(argv[optind++]));
	threshold->SetUpperThreshold(numeric_limits<float>::infinity());
	threshold->SetInsideValue(1);
	threshold->SetOutsideValue(0);*/
    // Use an Otsu Threshold filter to generate the mask
    if (verbose) cout << "Generating Otsu mask" << endl;
    auto otsuFilter = itk::OtsuThresholdImageFilter<QI::ImageF, TLabelImage>::New();
    otsuFilter->SetInput(input->GetOutput());
    otsuFilter->SetOutsideValue(1);
    otsuFilter->SetInsideValue(0);
    otsuFilter->Update();

	auto CC = itk::ConnectedComponentImageFilter<TLabelImage, TLabelImage>::New();
	CC->SetInput(otsuFilter->GetOutput());

    typedef itk::RelabelComponentImageFilter<TLabelImage, TLabelImage> TRelabel;
    auto relabel = TRelabel::New();
    relabel->SetInput(CC->GetOutput());
    relabel->Update();
    // Relabel sorts on size by default, so now work out how many make the size threshold
    auto label_sizes = relabel->GetSizeOfObjectsInPixels();
    if (keep > label_sizes.size())
        keep = label_sizes.size();
    for (int i = 0; i < keep; i++) {
        cout << "Object " << i << " size " << label_sizes[i] << endl;
        if (label_sizes[i] < size_threshold) {
            keep = i;
            break;
        }
    }
    if (keep == 0) {
        cerr << "Found 0 objects to keep. Exiting." << endl;
        return EXIT_FAILURE;
    }
    if (verbose) cout << "Found " << keep << " objects to keep." << endl;

	typedef itk::LabelShapeKeepNObjectsImageFilter<TLabelImage> TKeepN;
	auto keepN = TKeepN::New();
	keepN->SetInput(relabel->GetOutput());
	keepN->SetBackgroundValue(0);
	keepN->SetNumberOfObjects(keep);
	keepN->SetAttribute(TKeepN::LabelObjectType::NUMBER_OF_PIXELS);

	if (verbose) cout << "Writing label image." << endl;
	auto output = itk::ImageFileWriter<TLabelImage>::New();
	output->SetInput(keepN->GetOutput());
	output->SetFileName(prefix + "_labels.nii");
	output->Update();

	typedef itk::LabelStatisticsImageFilter<QI::ImageF, TLabelImage> TLabelStats;
	auto labelStats = TLabelStats::New();
	labelStats->SetInput(input->GetOutput());
	labelStats->SetLabelInput(keepN->GetOutput());
	labelStats->Update();

	typedef itk::ImageMomentsCalculator<QI::ImageF> TMoments;
	TMoments::VectorType refCoG; refCoG.Fill(0);
	if (reference) {
		auto refMoments = TMoments::New();
		refMoments->SetImage(reference);
		refMoments->Compute();
		refCoG = refMoments->GetCenterOfGravity();
		if (verbose) cout << "Reference CoG is: " << refCoG << endl;
	}

    // Set these up to use in the loop
    typedef itk::ResampleImageFilter<TLabelImage, TLabelImage, double> TLabelResampler;
    typedef itk::NearestNeighborInterpolateImageFunction<TLabelImage, double> TLabelInterp;
    auto ilabels = TLabelInterp::New();
    ilabels->SetInputImage(keepN->GetOutput());
    auto rlabels = TLabelResampler::New();
    rlabels->SetInput(keepN->GetOutput());
    rlabels->SetInterpolator(ilabels);
    rlabels->SetDefaultPixelValue(0.);
    rlabels->SetOutputParametersFromImage(relabel->GetOutput());

    typedef itk::ResampleImageFilter<QI::ImageF, QI::ImageF, double> TResampleF;
    typedef itk::LinearInterpolateImageFunction<QI::ImageF, double> TLinearInterpF;
    auto interp = TLinearInterpF::New();
    interp->SetInputImage(input->GetOutput());
    auto rimage = TResampleF::New();
    rimage->SetInput(input->GetOutput());
    rimage->SetInterpolator(interp);
    rimage->SetDefaultPixelValue(0.);
    rimage->SetOutputParametersFromImage(input->GetOutput());

	for (auto i = 1; i <= keep; i++) {
		TLabelImage::RegionType region = labelStats->GetRegion(i);
		typedef itk::ExtractImageFilter<QI::ImageF, QI::ImageF> TExtractF;
		auto extract = TExtractF::New();
		extract->SetInput(input->GetOutput());
		extract->SetExtractionRegion(region);
		extract->SetDirectionCollapseToSubmatrix();
		extract->Update();

		auto moments = TMoments::New();
		moments->SetImage(extract->GetOutput());
		moments->Compute();
		TMoments::VectorType CoG = moments->GetCenterOfGravity();
		if (verbose) cout << "Writing object " << i << " CoG is " << CoG << endl;
		float rotateAngle = atan2(CoG[1], CoG[0]);
		if (inwards)
			rotateAngle = (M_PI / 2.) - rotateAngle;
		else
			rotateAngle = (M_PI * 3./2.) - rotateAngle;
		if (verbose) cout << "Rotation angle is " << (rotateAngle*180./M_PI) << " degrees" << endl;

		typedef itk::Euler3DTransform<double> TRigid;
		auto tfm = TRigid::New();
		tfm->SetIdentity();
		tfm->SetOffset(CoG - refCoG);
		//tfm->SetCenter(CoG); // Want to leave this at 0 due to how ITK transforms work
		tfm->SetRotation(0, 0, -rotateAngle);

		stringstream suffix; suffix << "_" << setfill('0') << setw(2) << i;
		if (output_images) {
            rlabels->SetTransform(tfm.GetPointer());
            rimage->SetTransform(tfm.GetPointer());

            rlabels->Update();
            rimage->Update();

              // convert the label image into a LabelMap
            typedef itk::LabelMap<itk::LabelObject<TLabel, 3>> TLabelMap;
            auto convert = itk::LabelImageToLabelMapFilter<TLabelImage, TLabelMap> ::New();
            convert->SetInput(rlabels->GetOutput());

            auto masker = itk::LabelMapMaskImageFilter<TLabelMap, QI::ImageF>::New();
            masker->SetInput(convert->GetOutput());
            masker->SetFeatureImage(rimage->GetOutput());
            masker->SetLabel(i);
            masker->SetBackgroundValue(0.);
            masker->SetNegated(false); // Mask outside the mask
            masker->SetCrop(true);

            fname = prefix + suffix.str() + ".nii";
            if (verbose) cout << "Writing output file " << fname << endl;
            auto routput = itk::ImageFileWriter<QI::ImageF>::New();
            routput->SetInput(masker->GetOutput());
            routput->SetFileName(fname);
            routput->Update();
		}

		fname = prefix + suffix.str() + ".tfm";
		if (verbose) cout << "Writing transform file " << fname << endl;
  		auto tfmWriter = itk::TransformFileWriterTemplate<double>::New();
  		tfmWriter->SetInput(tfm);
  		tfmWriter->SetFileName(fname);
  		tfmWriter->Update();
	}
	return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>/*
    SWARM

    Copyright (C) 2012-2021 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"

struct bucket
{
  uint64_t hash;
  unsigned int seqno_first;
  unsigned int seqno_last;
  uint64_t mass;
  unsigned int size;
  unsigned int singletons;
};

auto derep_compare(const void * a, const void * b) -> int;

auto derep_compare(const void * a, const void * b) -> int
{
  const auto * x = static_cast<const struct bucket *>(a);
  const auto * y = static_cast<const struct bucket *>(b);
  int status {0};

  /* highest abundance first, otherwise keep order */

  if (x->mass < y->mass) {
    status = +1;
  }
  else if (x->mass > y->mass) {
    status = -1;
  }
  else {
    if (x->seqno_first < y->seqno_first) {
      status = -1;
    }
    else if (x->seqno_first > y->seqno_first) {
      status = +1;
    }
    else {
      status = 0;
    }
  }

  return status;
}

void dereplicate(struct Parameters const & p)
{
  /* adjust size of hash table for 2/3 fill rate */
  constexpr unsigned int hashfillpct {70};
  constexpr unsigned int one_hundred_pct {100};
  uint64_t dbsequencecount = db_getsequencecount();
  uint64_t hashtablesize {1};
  // db seqs > 70% hash table size (avoid division to keep working with ints)
  while (one_hundred_pct * dbsequencecount > hashfillpct * hashtablesize) {
    hashtablesize <<= 1;
  }
  uint64_t derep_hash_mask = hashtablesize - 1;

  auto * hashtable =
    static_cast<struct bucket *>(xmalloc(sizeof(bucket) * hashtablesize));

  memset(hashtable, 0, sizeof(bucket) * hashtablesize);

  uint64_t swarmcount = 0;
  uint64_t maxmass = 0;
  unsigned int maxsize = 0;

  /* alloc and init table of links to other sequences in cluster */
  auto * nextseqtab = static_cast<unsigned int *>
    (xmalloc(sizeof(unsigned int) * dbsequencecount));
  memset(nextseqtab, 0, sizeof(unsigned int) * dbsequencecount);

  progress_init("Dereplicating:    ", dbsequencecount);

  for(auto i = 0U; i < dbsequencecount; i++)
    {
      unsigned int seqlen = db_getsequencelen(i);
      char * seq = db_getsequence(i);

      /*
        Find free bucket or bucket for identical sequence.
        Make sure sequences are exactly identical
        in case of any hash collision.
        With 64-bit hashes, there is about 50% chance of a
        collision when the number of sequences is about 5e9.
      */

      uint64_t hash = zobrist_hash(reinterpret_cast<unsigned char *>(seq),
                                   seqlen);

      uint64_t j = hash & derep_hash_mask;
      struct bucket * bp = hashtable + j;

      while (((bp->mass) != 0U) &&
             ((bp->hash != hash) ||
              (seqlen != db_getsequencelen(bp->seqno_first)) ||
              (memcmp(seq,
                      db_getsequence(bp->seqno_first),
                      nt_bytelength(seqlen)) != 0)))
        {
          bp++;
          j++;
          if (bp >= hashtable + hashtablesize)
            {
              bp = hashtable;
              j = 0;
            }
        }

      uint64_t ab = db_getabundance(i);

      if ((bp->mass) != 0U)
        {
          /* at least one identical sequence already */
          nextseqtab[bp->seqno_last] = i;
        }
      else
        {
          /* no identical sequences yet, start a new cluster */
          swarmcount++;
          bp->hash = hash;
          bp->seqno_first = i;
          bp->size = 0;
          bp->singletons = 0;
        }

      bp->size++;
      bp->seqno_last = i;
      bp->mass += ab;

      if (ab == 1) {
        bp->singletons++;
      }

      if (bp->mass > maxmass) {
        maxmass = bp->mass;
      }

      if (bp->size > maxsize) {
        maxsize = bp->size;
      }

      progress_update(i);
    }
  progress_done();

  progress_init("Sorting:          ", 1);
  qsort(hashtable, hashtablesize, sizeof(bucket), derep_compare);
  progress_done();

  /* dump swarms */

  progress_init("Writing swarms:   ", swarmcount);

  if (opt_mothur) {
    fprintf(outfile, "swarm_%" PRId64 "\t%" PRIu64, p.opt_differences, swarmcount);
  }

  for(auto i = 0U; i < swarmcount; i++)
    {
      unsigned int seed = hashtable[i].seqno_first;
      if (opt_mothur) {
        fputc('\t', outfile);
      }
      fprint_id(outfile, seed);
      unsigned int a = nextseqtab[seed];

      while (a != 0U)
        {
          if (opt_mothur) {
            fputc(',', outfile);
          }
          else {
            fputc(sepchar, outfile);
          }
          fprint_id(outfile, a);
          a = nextseqtab[a];
        }

      if (!opt_mothur) {
        fputc('\n', outfile);
      }

      progress_update(i+1);
    }

  if (opt_mothur) {
    fputc('\n', outfile);
  }

  progress_done();

  /* dump seeds in fasta format with sum of abundances */

  if (! opt_seeds.empty())
    {
      progress_init("Writing seeds:    ", swarmcount);
      for(auto i = 0U; i < swarmcount; i++)
        {
          unsigned int seed = hashtable[i].seqno_first;
          fprintf(fp_seeds, ">");
          fprint_id_with_new_abundance(fp_seeds, seed, hashtable[i].mass);
          fprintf(fp_seeds, "\n");
          db_fprintseq(fp_seeds, seed, 0);
          progress_update(i+1);
        }
      progress_done();
    }

  /* output swarm in uclust format */

  if (uclustfile != nullptr)
    {
      progress_init("Writing UCLUST:   ", swarmcount);

      for(auto swarmid = 0U; swarmid < swarmcount; swarmid++)
        {
          struct bucket * bp = hashtable + swarmid;

          unsigned int seed = bp->seqno_first;

          fprintf(uclustfile, "C\t%u\t%u\t*\t*\t*\t*\t*\t",
                  swarmid,
                  bp->size);
          fprint_id(uclustfile, seed);
          fprintf(uclustfile, "\t*\n");

          fprintf(uclustfile, "S\t%u\t%u\t*\t*\t*\t*\t*\t",
                  swarmid,
                  db_getsequencelen(seed));
          fprint_id(uclustfile, seed);
          fprintf(uclustfile, "\t*\n");

          unsigned int a = nextseqtab[seed];

          while (a != 0U)
            {
              fprintf(uclustfile,
                      "H\t%u\t%u\t%.1f\t+\t0\t0\t%s\t",
                      swarmid,
                      db_getsequencelen(a),
                      100.0,
                      "=");
              fprint_id(uclustfile, a);
              fprintf(uclustfile, "\t");
              fprint_id(uclustfile, seed);
              fprintf(uclustfile, "\n");
              a = nextseqtab[a];
            }

          progress_update(swarmid+1);
        }
      progress_done();
    }

  /* output internal structure to file */

  if (! p.opt_internal_structure.empty())
    {
      progress_init("Writing structure:", swarmcount);

      for(uint64_t i = 0; i < swarmcount; i++)
        {
          struct bucket * sp = hashtable + i;
          uint64_t seed = sp->seqno_first;
          unsigned int a = nextseqtab[seed];
          while (a != 0U)
            {
              fprint_id_noabundance(internal_structure_file, seed);
              fprintf(internal_structure_file, "\t");
              fprint_id_noabundance(internal_structure_file, a);
              fprintf(internal_structure_file, "\t%d\t%" PRIu64 "\t%d\n", 0, i+1, 0);
              a = nextseqtab[a];
            }
          progress_update(i);
        }
      progress_done();
    }

  /* output statistics to file */

  if (statsfile != nullptr)
    {
      progress_init("Writing stats:    ", swarmcount);
      for(auto i = 0ULL; i < swarmcount; i++)
        {
          struct bucket * sp = hashtable + i;
          fprintf(statsfile, "%u\t%" PRIu64 "\t", sp->size, sp->mass);
          fprint_id_noabundance(statsfile, sp->seqno_first);
          fprintf(statsfile, "\t%" PRIu64 "\t%u\t%u\t%u\n",
                  db_getabundance(sp->seqno_first),
                  sp->singletons, 0U, 0U);
          progress_update(i);
        }
      progress_done();
    }

  fprintf(logfile, "\n");
  fprintf(logfile, "Number of swarms:  %" PRIu64 "\n", swarmcount);
  fprintf(logfile, "Largest swarm:     %u\n", maxsize);
  fprintf(logfile, "Heaviest swarm:    %" PRIu64 "\n", maxmass);

  xfree(nextseqtab);
  xfree(hashtable);
}
<commit_msg>compute hashtable size in a function, make variables const<commit_after>/*
    SWARM

    Copyright (C) 2012-2021 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"

struct bucket
{
  uint64_t hash;
  unsigned int seqno_first;
  unsigned int seqno_last;
  uint64_t mass;
  unsigned int size;
  unsigned int singletons;
};

auto derep_compare(const void * a, const void * b) -> int;

auto derep_compare(const void * a, const void * b) -> int
{
  const auto * x = static_cast<const struct bucket *>(a);
  const auto * y = static_cast<const struct bucket *>(b);
  int status {0};

  /* highest abundance first, otherwise keep order */

  if (x->mass < y->mass) {
    status = +1;
  }
  else if (x->mass > y->mass) {
    status = -1;
  }
  else {
    if (x->seqno_first < y->seqno_first) {
      status = -1;
    }
    else if (x->seqno_first > y->seqno_first) {
      status = +1;
    }
    else {
      status = 0;
    }
  }

  return status;
}

auto compute_hashtable_size(const uint64_t sequence_count) -> uint64_t {
  /* adjust size of hash table for 2/3 fill rate */
  constexpr unsigned int hashfillpct {70};
  constexpr unsigned int one_hundred_pct {100};
  uint64_t hashtablesize {1};
  // db seqs > 70% hash table size (avoid division to keep working with ints)
  while (one_hundred_pct * sequence_count > hashfillpct * hashtablesize) {
    hashtablesize <<= 1;
  }
  return hashtablesize;
}

void dereplicate(struct Parameters const & p)
{
  const uint64_t dbsequencecount = db_getsequencecount();
  const uint64_t hashtablesize {compute_hashtable_size(dbsequencecount)};
  const uint64_t derep_hash_mask = hashtablesize - 1;

  auto * hashtable =
    static_cast<struct bucket *>(xmalloc(sizeof(bucket) * hashtablesize));

  memset(hashtable, 0, sizeof(bucket) * hashtablesize);

  uint64_t swarmcount = 0;
  uint64_t maxmass = 0;
  unsigned int maxsize = 0;

  /* alloc and init table of links to other sequences in cluster */
  auto * nextseqtab = static_cast<unsigned int *>
    (xmalloc(sizeof(unsigned int) * dbsequencecount));
  memset(nextseqtab, 0, sizeof(unsigned int) * dbsequencecount);

  progress_init("Dereplicating:    ", dbsequencecount);

  for(auto i = 0U; i < dbsequencecount; i++)
    {
      unsigned int seqlen = db_getsequencelen(i);
      char * seq = db_getsequence(i);

      /*
        Find free bucket or bucket for identical sequence.
        Make sure sequences are exactly identical
        in case of any hash collision.
        With 64-bit hashes, there is about 50% chance of a
        collision when the number of sequences is about 5e9.
      */

      uint64_t hash = zobrist_hash(reinterpret_cast<unsigned char *>(seq),
                                   seqlen);

      uint64_t j = hash & derep_hash_mask;
      struct bucket * bp = hashtable + j;

      while (((bp->mass) != 0U) &&
             ((bp->hash != hash) ||
              (seqlen != db_getsequencelen(bp->seqno_first)) ||
              (memcmp(seq,
                      db_getsequence(bp->seqno_first),
                      nt_bytelength(seqlen)) != 0)))
        {
          bp++;
          j++;
          if (bp >= hashtable + hashtablesize)
            {
              bp = hashtable;
              j = 0;
            }
        }

      uint64_t ab = db_getabundance(i);

      if ((bp->mass) != 0U)
        {
          /* at least one identical sequence already */
          nextseqtab[bp->seqno_last] = i;
        }
      else
        {
          /* no identical sequences yet, start a new cluster */
          swarmcount++;
          bp->hash = hash;
          bp->seqno_first = i;
          bp->size = 0;
          bp->singletons = 0;
        }

      bp->size++;
      bp->seqno_last = i;
      bp->mass += ab;

      if (ab == 1) {
        bp->singletons++;
      }

      if (bp->mass > maxmass) {
        maxmass = bp->mass;
      }

      if (bp->size > maxsize) {
        maxsize = bp->size;
      }

      progress_update(i);
    }
  progress_done();

  progress_init("Sorting:          ", 1);
  qsort(hashtable, hashtablesize, sizeof(bucket), derep_compare);
  progress_done();

  /* dump swarms */

  progress_init("Writing swarms:   ", swarmcount);

  if (opt_mothur) {
    fprintf(outfile, "swarm_%" PRId64 "\t%" PRIu64, p.opt_differences, swarmcount);
  }

  for(auto i = 0U; i < swarmcount; i++)
    {
      unsigned int seed = hashtable[i].seqno_first;
      if (opt_mothur) {
        fputc('\t', outfile);
      }
      fprint_id(outfile, seed);
      unsigned int a = nextseqtab[seed];

      while (a != 0U)
        {
          if (opt_mothur) {
            fputc(',', outfile);
          }
          else {
            fputc(sepchar, outfile);
          }
          fprint_id(outfile, a);
          a = nextseqtab[a];
        }

      if (!opt_mothur) {
        fputc('\n', outfile);
      }

      progress_update(i+1);
    }

  if (opt_mothur) {
    fputc('\n', outfile);
  }

  progress_done();

  /* dump seeds in fasta format with sum of abundances */

  if (! opt_seeds.empty())
    {
      progress_init("Writing seeds:    ", swarmcount);
      for(auto i = 0U; i < swarmcount; i++)
        {
          unsigned int seed = hashtable[i].seqno_first;
          fprintf(fp_seeds, ">");
          fprint_id_with_new_abundance(fp_seeds, seed, hashtable[i].mass);
          fprintf(fp_seeds, "\n");
          db_fprintseq(fp_seeds, seed, 0);
          progress_update(i+1);
        }
      progress_done();
    }

  /* output swarm in uclust format */

  if (uclustfile != nullptr)
    {
      progress_init("Writing UCLUST:   ", swarmcount);

      for(auto swarmid = 0U; swarmid < swarmcount; swarmid++)
        {
          struct bucket * bp = hashtable + swarmid;

          unsigned int seed = bp->seqno_first;

          fprintf(uclustfile, "C\t%u\t%u\t*\t*\t*\t*\t*\t",
                  swarmid,
                  bp->size);
          fprint_id(uclustfile, seed);
          fprintf(uclustfile, "\t*\n");

          fprintf(uclustfile, "S\t%u\t%u\t*\t*\t*\t*\t*\t",
                  swarmid,
                  db_getsequencelen(seed));
          fprint_id(uclustfile, seed);
          fprintf(uclustfile, "\t*\n");

          unsigned int a = nextseqtab[seed];

          while (a != 0U)
            {
              fprintf(uclustfile,
                      "H\t%u\t%u\t%.1f\t+\t0\t0\t%s\t",
                      swarmid,
                      db_getsequencelen(a),
                      100.0,
                      "=");
              fprint_id(uclustfile, a);
              fprintf(uclustfile, "\t");
              fprint_id(uclustfile, seed);
              fprintf(uclustfile, "\n");
              a = nextseqtab[a];
            }

          progress_update(swarmid+1);
        }
      progress_done();
    }

  /* output internal structure to file */

  if (! p.opt_internal_structure.empty())
    {
      progress_init("Writing structure:", swarmcount);

      for(uint64_t i = 0; i < swarmcount; i++)
        {
          struct bucket * sp = hashtable + i;
          uint64_t seed = sp->seqno_first;
          unsigned int a = nextseqtab[seed];
          while (a != 0U)
            {
              fprint_id_noabundance(internal_structure_file, seed);
              fprintf(internal_structure_file, "\t");
              fprint_id_noabundance(internal_structure_file, a);
              fprintf(internal_structure_file, "\t%d\t%" PRIu64 "\t%d\n", 0, i+1, 0);
              a = nextseqtab[a];
            }
          progress_update(i);
        }
      progress_done();
    }

  /* output statistics to file */

  if (statsfile != nullptr)
    {
      progress_init("Writing stats:    ", swarmcount);
      for(auto i = 0ULL; i < swarmcount; i++)
        {
          struct bucket * sp = hashtable + i;
          fprintf(statsfile, "%u\t%" PRIu64 "\t", sp->size, sp->mass);
          fprint_id_noabundance(statsfile, sp->seqno_first);
          fprintf(statsfile, "\t%" PRIu64 "\t%u\t%u\t%u\n",
                  db_getabundance(sp->seqno_first),
                  sp->singletons, 0U, 0U);
          progress_update(i);
        }
      progress_done();
    }

  fprintf(logfile, "\n");
  fprintf(logfile, "Number of swarms:  %" PRIu64 "\n", swarmcount);
  fprintf(logfile, "Largest swarm:     %u\n", maxsize);
  fprintf(logfile, "Heaviest swarm:    %" PRIu64 "\n", maxmass);

  xfree(nextseqtab);
  xfree(hashtable);
}
<|endoftext|>