Slow performance using STL in NEH algorithm - c++

I've got problem with NEH algorithm. I implemented it but it's veeeery slow and I can't figure out what the problem is. Could You verify what I did wrong, what causes bad performance? Here's my code:
#include <iostream>
#include <map>
#include <sstream>
#include <limits>
#include <vector>
#include <fstream>
#include <list>
#include <algorithm>
#include <numeric>
#include <queue>
#include <memory>
template <typename T>
class Matrix
{
public:
Matrix(unsigned int rowsNum, unsigned int columnsNum) :m_rows(rowsNum), m_columns(columnsNum){ resize(rowsNum, columnsNum); };
T& operator()(unsigned int r, unsigned int c) { return m_data[r*columns() + c]; }
const T& operator()(unsigned int r, unsigned int c) const { return m_data[r*columns() + c]; }
unsigned int rows() const { return m_rows; }
unsigned int columns() const { return m_columns; }
Matrix<T> operator+(const Matrix<T>& matrix) const;
private:
void resize(unsigned int rowsNum, unsigned int colsNum);
std::unique_ptr<T[]> m_data;
unsigned int m_rows;
unsigned int m_columns;
};
template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix& matrix) const
{
}
template <typename T>
void Matrix<T>::resize(unsigned int rowsNum, unsigned int colsNum)
{
m_rows = rowsNum;
m_columns = colsNum;
m_data.reset(new T[rowsNum*colsNum]);
}
class Task
{
public:
Task(unsigned int ordNum = 0) :m_ordNum(ordNum) { }
unsigned int readFromFile(std::istream& is);
unsigned int totalTasksTime() const;
unsigned int ordNum() const { return m_ordNum; }
unsigned int machinesNum() const { return m_params.size(); }
unsigned int machineTaskTime(unsigned int machineNum) const { return m_params[machineNum - 1]; }
protected:
std::vector<unsigned int> m_params;
unsigned int m_ordNum;
unsigned int m_totalTasksTime;
};
unsigned int Task::totalTasksTime() const
{
return m_totalTasksTime;
}
unsigned int Task::readFromFile(std::istream& is)
{
std::string line;
while (is.peek() == '\n') // omija puste linie
is.get();
std::getline(is, line);
m_params.clear();
std::istringstream istr(line);
unsigned int i = 1;
while (istr)
{
int taskNum, taskTime;
istr >> taskNum >> taskTime;
if (istr)
{
if (i == m_params.size() + 1)
m_params.push_back(taskTime);
else
throw "Zly numer indesku maszyny - musza być po kolei";
i++;
}
}
m_totalTasksTime = std::accumulate(m_params.begin(), m_params.end(), 0);
return m_params.size();
}
class Instance
{
public:
Instance() { }
Instance(const std::string& name) :m_name(name) { }
void readFromFile(std::istream& is);
const std::string& name() const { return m_name; }
void name(std::string& newName) { m_name = newName; }
void neh(std::list<unsigned int>& permutation, unsigned int &totalTime) const;
const Task* getTask(unsigned int taskNum) const { return &m_tasks[taskNum]; }
private:
unsigned int calculateTotalTime(const std::list<unsigned int>& permutationList, unsigned int bestTimeFound) const;
std::vector<Task> m_tasks;
std::string m_name;
};
typedef std::map<unsigned int, unsigned int> MapIterator;
typedef std::vector<Task>::const_iterator TaskVecIterator;
bool compareTasksPtrBySumTime(const Task* t1, const Task* t2)
{
unsigned int t1TotalTime = t1->totalTasksTime(), t2TotalTime = t2->totalTasksTime();
bool w1 = t1TotalTime < t2TotalTime, w2 = t1TotalTime == t2TotalTime && t1->ordNum() > t2->ordNum();
return w1 || w2;
}
void Instance::neh(std::list<unsigned int>& permutation, unsigned int &totalTime) const
{
// sortowanie zadań po całkowitym czasie wykonania
std::list<const Task*> sortedTaskList;
for (unsigned int i = 0; i < m_tasks.size(); i++)
sortedTaskList.push_back(&m_tasks[i]);
sortedTaskList.sort(compareTasksPtrBySumTime);
while (!sortedTaskList.empty()) //
{
const Task* taskPtr = sortedTaskList.back(); sortedTaskList.pop_back();
unsigned int taskNum = taskPtr->ordNum();
std::list<unsigned int>::iterator bestPosition = permutation.begin();
unsigned int bestTotalTime = std::numeric_limits<unsigned int>::max();
permutation.push_front(taskNum);
for (std::list<unsigned int>::iterator it = permutation.begin(); // szukanie najlepszej pozycji
it != permutation.end(); it++)
{
unsigned int currentTotalTime = calculateTotalTime(permutation, bestTotalTime);
if (bestTotalTime > currentTotalTime)
{
bestTotalTime = currentTotalTime;
bestPosition = it;
}
auto nextIt = it; nextIt++;
if (nextIt != permutation.end())
std::swap(*it, *nextIt);
}
totalTime = bestTotalTime;
permutation.insert(bestPosition, taskNum);
permutation.pop_back();
}
std::cout << "Ukonczono:" << name() << std::endl;
}
unsigned int Instance::calculateTotalTime(const std::list<unsigned int>& permutationList, unsigned int bestTimeFound) const
{
unsigned int rows = m_tasks[*permutationList.begin() - 1].machinesNum() + 1, columns = permutationList.size() + 1;
Matrix<unsigned int> matrix(rows, columns);
unsigned int totalTime = 0;
for (unsigned int c = 0; c < columns; c++)
matrix(0, c) = 0;
for (unsigned int r = 0; r < rows; r++)
matrix(r, 0) = 0;
std::list<unsigned int>::const_iterator it = permutationList.begin();
for (unsigned int c = 1; c < columns; c++)
{
unsigned int taskNum = *it;
for (unsigned int r = 1; r < rows; r++)
(matrix(r, c) = std::max(matrix(r, c - 1), matrix(r - 1, c)) + m_tasks[taskNum - 1].machineTaskTime(r));// >bestTimeFound;
// return std::numeric_limits<unsigned int>::max();
it++;
}
return matrix(rows - 1, columns - 1);
}
void Instance::readFromFile(std::istream& is)
{
int taskNum, machineNum;
is >> taskNum >> machineNum;
for (int i = 0; i < taskNum; i++)
{
Task task(i + 1);
task.readFromFile(is);
if (is)
m_tasks.push_back(task);
}
}
class InstanceVector
{
public:
void readFromFile(std::istream& is);
void neh(std::list< std::list<unsigned int> >& result) const;
void neh(std::ostream& os) const;
private:
std::vector<Instance> m_instances;
};
void InstanceVector::readFromFile(std::istream& is)
{
while (is)
{
std::string name;
is >> name;
Instance instance(name);
instance.readFromFile(is);
std::list<unsigned int> l;
unsigned int totalTime;
if (is)
m_instances.push_back(instance);
}
}
void InstanceVector::neh(std::list< std::list<unsigned int> >& results) const
{
std::vector<Instance>::const_iterator it;
for (it = m_instances.begin(); it != m_instances.end(); it++)
{
std::list<unsigned int> resultInstance;
unsigned int totalTimeInstance;
it->neh(resultInstance, totalTimeInstance);
results.push_back(resultInstance);
}
}
void InstanceVector::neh(std::ostream& os) const
{
std::list< std::list<unsigned int> > results;
for (std::vector<Instance>::const_iterator it = m_instances.begin();
it != m_instances.end(); it++)
{
std::list<unsigned int> resultInstance;
unsigned int totalTimeInstance;
it->neh(resultInstance, totalTimeInstance);
results.push_back(std::move(resultInstance));
}
for (std::list< std::list<unsigned int> >::const_iterator it = results.begin();
it != results.end(); it++)
{
for (std::list<unsigned int>::const_iterator itPermutation = it->begin(); itPermutation != it->end(); itPermutation++)
os << *itPermutation << " ";
os << std::endl;
}
}
int main(int argc, char* argv[])
{
InstanceVector instanceVec;
std::ifstream input("bench_fs.txt");
if (input.is_open())
instanceVec.readFromFile(input);
std::ofstream output("output.txt");
instanceVec.neh(output);
std::cin.get();
}

The time taken by your program dependent both on the code and the data. Without the data we can only guess at why your program is taking more time than you expected. I will hazard some guesses as to where time is being lost but first I will strongly encourage you to try measuring how your program is spending its time. On Linux you can use perf to measure where your program is spending its time but there are plenty of tools to chose from. This will help in two ways. First, the following guesses may be completely wrong. Second, you will know how to find the performance problems in your next program.
In the absence of any hard information my gut is wary of two elements of your program.
You are storing your permutation as a std::list and I suspect that traversal and modification of this list is taking more time than you are saving by having an efficient push_front(). Try switching to std::vector. You can avoid push_front() by doing a push_back() and reversing the direction you move the new task through the permutation and keeping a best permutation rather than best position.
Inside calculateTotalTime() the matrix object is allocating and deallocating memory each time. This is potentially adding up to a significant amount of time. You could pass the matrix as an argument to calculateTotalTime() and store the matrix object at a level where it will be allocated/deallocated far less frequently. You probably need to do as #PaulMcKenzie suggests and use std::vector in your matrix class, rather than unique_ptr, so that you can reserve capacity ahead of time.
Hope that helps.

Related

Problems with implementing 2D array template in C++

I tried to create a template for a generic 2D array, which would allow me to create arrays of different data types and fill them with random values. My current code seemingly creates three objects, but fills them with the same random values, and the double type massive does not even have double values. I think the problem is somewhere in the constructor and with the pointers, but I am not sure how to fix this.
My class:
template <typename T>
class MATRIX
{
private:
T** M;
int m = 8;
int n = 12;
public:
MATRIX(T matr[8][12]);
void fill();
};
Constructor:
template <typename T>
MATRIX<T>::MATRIX(T matr[8][12]){
M = (T**) new T*[m];
for (int i = 0; i < m; i++)
M[i] = (T*)new T[n];
}
Method:
template <typename T>
void MATRIX<T>::fill(){
T randomNumber;
srand((unsigned) time(0));
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
randomNumber = (rand() % (122 + 1 - 65)) + 65;
M[i][j] = randomNumber;} } }
Main:
int main() {
int intMatr[8][12];
MATRIX<int>a(intMatr);
a.fill();
double doubleMatr[8][12];
MATRIX<double>b(doubleMatr);
b.fill();
char charMatr[8][12];
MATRIX<char>c(charMatr);
c.fill();
return 0; }
Not really a direct answer to your question, howeverr try not to use new/delete if you don't have to as is shown in this example (note the array2d_t class is something I wrote earlier and reused for this example so it can do a bit more then needed)
I also show how to use c++'s random generators to create characters for your matrix.
#pragma once
#include <vector>
#include <iostream>
#include <random>
#include <utility>
#include <string>
#include <stdexcept>
//---------------------------------------------------------------------------------------------------------------------
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
struct array2d_t
{
constexpr array2d_t() :
m_values{}
{
}
constexpr explicit array2d_t(const type_t(&values)[rows_v][cols_v])
{
// constexpr compatible initialization
for (auto row = 0; row < rows_v; ++row)
{
for (auto col = 0; col < cols_v; ++col)
{
m_values[row][col] = values[row][col];
}
}
}
~array2d_t() = default;
// return a row
constexpr auto operator[](const std::size_t row)
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return row_t(&m_values[row][0]);
}
// return a const row
constexpr auto operator[](const std::size_t row) const
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return const_row_t(&m_values[row][0]);
}
// return iterator to the first row (so array can be used in range based for loop)
constexpr auto begin()
{
return std::begin(m_values);
}
// return iterator to the last row (so array can be used in range based for loop)
constexpr auto end()
{
return std::end(m_values);
}
constexpr std::size_t rows() const
{
return rows_v;
}
constexpr std::size_t columns() const
{
return cols_v;
}
private:
//-----------------------------------------------------------------------------------------------------------------
/// row helper
struct row_t
{
constexpr row_t(type_t* row) :
m_row{ row }
{
}
constexpr type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
type_t* m_row;
};
//-----------------------------------------------------------------------------------------------------------------
// row helper for const
struct const_row_t
{
constexpr const_row_t(const type_t* row) :
m_row{ row }
{
}
constexpr const type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
const type_t* m_row;
};
type_t m_values[rows_v][cols_v];
};
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
std::ostream& operator<<(std::ostream& os, array2d_t<type_t,rows_v,cols_v>& arr)
{
for (const auto& row : arr)
{
bool comma = false;
for (const auto& value : row)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
std::cout << "\n";
return os;
}
//---------------------------------------------------------------------------------------------------------------------
class MATRIX :
public array2d_t<char, 8, 12>
{
public:
void fill()
{
// initialize a vector of valid character for random to pick from
// static ensures this is only done on first call to function
static std::vector<char> valid_chars = []
{
std::vector<char> chars;
chars.reserve(52);
for (char c = 'A'; c < 'Z'; ++c) chars.push_back(c);
for (char c = 'a'; c < 'z'; ++c) chars.push_back(c);
return chars;
}();
// this is how to setup random number generation in C++
static std::random_device rd{};
static std::default_random_engine random{ rd() };
static std::uniform_int_distribution<std::size_t> distribution(0, valid_chars.size() - 1);
for (auto& row : *this)
{
for (auto& value : row)
{
value = valid_chars[distribution(random)];
}
}
}
};
//---------------------------------------------------------------------------------------------------------------------
int main()
{
MATRIX m;
m.fill();
std::cout << m;
return 0;
}

std::cout stopping the program

I was trying to fix a bug, and I am extremely confused, it seems that whenever I use std::cout the program will freeze. I have absolutely no idea why this is happening, and if any of you I know why I would love to know.
here is my source code for reference (the std::cout is at the bottom in the main function):
#include <iostream>
#include <vector>
#include <unordered_map>
#include <exception>
#include <string>
#include <fstream>
/*
template<
typename T
>
std::ostream& operator<< (std::ostream& stream, std::vector<T> vec)
{
for (int i = 0; i < vec.size() - 1; ++i)
{
stream << vec[i] << " ";
}
stream << vec.back();
return stream;
}
*/
class gate
{
public:
std::unordered_map<std::string, int> m_inputs;
std::unordered_map<std::string, int> m_outputs;
virtual std::vector<bool> calculate(const std::vector<bool>& inputs) = 0;
gate(const std::unordered_map<std::string, int>& inputs, const std::unordered_map<std::string, int>& outputs) :
m_inputs(inputs),
m_outputs(outputs)
{}
};
class elementary_gate : public gate
{
private:
std::unordered_map<std::vector<bool>, std::vector<bool>> m_truth_table;
public:
elementary_gate(const std::unordered_map<std::vector<bool>, std::vector<bool>>& truth_table,
const std::unordered_map<std::string, int>& inputs,
const std::unordered_map<std::string, int>& outputs
) :
gate(inputs, outputs),
m_truth_table(truth_table)
{}
std::vector<bool> calculate(const std::vector<bool>& inputs) override
{
return m_truth_table[inputs];
}
};
class gate_reference
{
private:
gate* m_gate;
std::vector<int> m_input_connection_ids;
std::vector<int> m_output_connection_ids;
public:
gate_reference(gate* gate_ref, const std::vector<int>& input_connection_ids, const std::vector<int>& output_connection_ids) :
m_gate(gate_ref),
m_input_connection_ids(input_connection_ids),
m_output_connection_ids(output_connection_ids)
{}
std::vector<bool> calculate(const std::vector<bool>& inputs)
{
return m_gate->calculate(inputs);
}
std::vector<int> get_input_connection_ids()
{
return m_input_connection_ids;
}
void set_output_connection_ids(const std::vector<bool>& output_vector, std::vector<bool>& connection_values)
{
for (int i = 0; i < output_vector.size(); ++i)
{
connection_values[m_output_connection_ids[i]] = output_vector[i];
}
}
};
class compound_gate : public gate
{
private:
std::vector<gate_reference> m_gates;
std::vector<int> m_output_connection_ids;
int connection_count;
int input_count;
public:
std::vector<bool> calculate(const std::vector<bool>& inputs) override
{
if (inputs.size() != input_count)
{
throw std::length_error("incorrect input size for logic gate");
}
std::vector<bool> connection_values(connection_count);
for (int i = 0; i < input_count; ++i)
{
connection_values[i] = inputs[i];
}
for (gate_reference gate_ref : m_gates)
{
std::vector<int> input_ids = gate_ref.get_input_connection_ids();
std::vector<bool> input_vector = construct_io_vector(input_ids, connection_values);
std::vector<bool> output_vector = gate_ref.calculate(input_vector);
gate_ref.set_output_connection_ids(output_vector, connection_values);
}
return construct_io_vector(m_output_connection_ids, connection_values);
}
private:
std::vector<bool> construct_io_vector(const std::vector<int>& connection_ids, const std::vector<bool>& connection_values)
{
std::vector<bool> input_vector;
for (int connection_id : connection_ids)
{
input_vector.push_back(connection_values[connection_id]);
}
return input_vector;
}
};
std::vector<bool> get_vector_from_int(int num, int pad_length)
{
std::vector<bool> bool_vec;
while (num)
{
if (num % 2)
{
bool_vec.push_back(true);
}
else
{
bool_vec.push_back(false);
}
num >>= 1;
}
while (bool_vec.size() < pad_length)
{
bool_vec.push_back(false);
}
std::reverse(bool_vec.begin(), bool_vec.end());
return bool_vec;
}
class gates
{
public:
static std::unordered_map<std::string, elementary_gate*> gate_list;
};
std::unordered_map<std::string, elementary_gate*> gates::gate_list;
gate* load_elementary_gate(const std::string& filename)
{
std::ifstream file(filename);
std::string gate_name = filename.substr(0, filename.find('.'));
int input_count;
file >> input_count;
std::unordered_map<std::string, int> inputs;
for (int i = 0; i < input_count; ++i)
{
std::string input_name;
file >> input_name;
inputs.insert(std::make_pair(input_name, i));
}
int output_count;
file >> output_count;
std::unordered_map<std::string, int> outputs;
for (int i = 0; i < output_count; ++i)
{
std::string output_name;
file >> output_name;
outputs.insert(std::make_pair(output_name, i));
}
int table_rows = 1 << input_count;
std::unordered_map<std::vector<bool>, std::vector<bool>> truth_table;
for (int i = 0; i < table_rows; ++i)
{
std::vector<bool> input_vector = get_vector_from_int(i, input_count);
std::vector<bool> output_vector(output_count);
for (int i = 0; i < output_count; ++i)
{
int val;
file >> val;
output_vector[i] = val;
}
truth_table.insert(std::make_pair(input_vector, output_vector));
}
elementary_gate* gate = new elementary_gate(truth_table, inputs, outputs);
gates::gate_list.insert(std::make_pair(gate_name, gate));
return gate;
}
gate* extract_gate_type(std::string& raw_gate)
{
std::string gate_name = raw_gate.substr(0, raw_gate.find('('));
raw_gate = raw_gate.substr(raw_gate.find('(') + 1, raw_gate.size() - raw_gate.find('(')- 2);
return gates::gate_list[gate_name];
}
std::vector<std::string> split_string(std::string str, char delim)
{
std::vector<std::string> split;
bool new_str = true;
for (char c : str)
{
if (new_str)
{
split.emplace_back("");
}
if (c == delim)
{
new_str = true;
}
else
{
if (c != ' ')
{
new_str = false;
split.back() += c;
}
}
}
return split;
}
gate* load_circuit(const std::string& filename)
{
std::ifstream file(filename);
std::string gate_name = filename.substr(0, filename.find('.'));
int input_count;
file >> input_count;
std::unordered_map<std::string, int> inputs;
for (int i = 0; i < input_count; ++i)
{
std::string input_name;
file >> input_name;
inputs.insert(std::make_pair(input_name, i));
}
int output_count;
file >> output_count;
std::unordered_map<std::string, int> outputs;
for (int i = 0; i < output_count; ++i)
{
std::string output_name;
file >> output_name;
outputs.insert(std::make_pair(output_name, i));
}
std::vector<gate*> gates;
std::vector<std::string> sub_gates_raw;
while (!file.eof())
{
std::string gate_str;
char c = ' ';
while (c != ')')
{
file >> c;
gate_str += c;
}
std::cout << gate_str.size() << std::endl;
if (gate_str.size() < 1)
{
continue;
}
gates.push_back(extract_gate_type(gate_str));
sub_gates_raw.push_back(gate_str);
}
std::vector<std::vector<std::string>> io_split;
for (std::string str : sub_gates_raw)
{
io_split.push_back(split_string(str, ','));
}
std::vector<std::vector<std::pair<std::string, std::string>>> gate_io_split;
for (std::vector<std::string> gate_strs : io_split)
{
std::vector<std::pair<std::string, std::string>> gate_strs_lr_split;
for (std::string io_str : gate_strs)
{
std::vector<std::string> gate_str_lr_split = split_string(io_str, '=');
gate_strs_lr_split.push_back(std::make_pair(gate_str_lr_split[0], gate_str_lr_split[1]));
}
gate_io_split.push_back(gate_strs_lr_split);
}
std::unordered_map<std::string, int> connection_list;
for (std::vector<std::pair<std::string, std::string>> gate_strs : gate_io_split)
{
for (std::pair<std::string, std::string> connection : gate_strs)
{
connection_list.insert(std::make_pair(connection.first, connection_list.size() - 1));
}
}
for (std::pair<std::string, int> input : inputs)
{
inputs.insert_or_assign(input.first, connection_list[input.first]);
}
for (std::pair<std::string, int> output : outputs)
{
outputs.insert_or_assign(output.first, connection_list[output.first]);
}
std::vector<std::vector<std::pair<int, int>>> gates_connection_indexes;
std::vector<std::vector<bool>> is_input;
for (int i = 0; i < gate_io_split.size(); ++i)
{
std::vector<std::pair<std::string, std::string>> gate_connection_indexes_str = gate_io_split[i];
std::vector<std::pair<int, int>> gate_connection_indexes;
std::vector<bool> gate_connections;
for (std::pair<std::string, std::string> gate_connection_index_str : gate_connection_indexes_str)
{
gate_connections.push_back(gates[i]->m_inputs.count(gate_connection_index_str.first));
std::pair<int, int> connnection_indexes = std::make_pair(connection_list[gate_connection_index_str.first], connection_list[gate_connection_index_str.second]);
gate_connection_indexes.push_back(connnection_indexes);
}
is_input.push_back(gate_connections);
gates_connection_indexes.push_back(gate_connection_indexes);
}
std::vector<gate_reference> gate_references;
for (int i = 0; i < gates_connection_indexes.size(); ++i)
{
}
return nullptr;
}
int main(void)
{
std::cout << "hello";
//load_elementary_gate("nand.gate");
//load_circuit("not.circuit");
//load_circuit("or.circuit");
return 0;
}

Different return and coordinate types in nanoflann radius search

I'm trying to use nanoflann in a project and am looking at the vector-of-vector and radius search examples.
I can't find a way to perform a radius search with a different data type than the coordinate type. For example, my coordinates are vectors of uint8_t; I am trying to input a radius of type uint32_t with little success.
I see in the source that the metric_L2 struct (which I am using for distance) uses the L2_Adaptor with two template parameters. L2_Adaptor itself takes three parameters, with the third defaulted to the first, which seems to be the problem if I am understanding the code correctly. However, trying to force use of the third always results in 0 matches in the radius search.
Is there a way to do this?
Edit: In the same code below, everything works. However, if I change the search_radius (and ret_matches) to uint32_t, the radiusSearch method doesn't work.
#include <iostream>
#include <Eigen/Dense>
#include <nanoflann.hpp>
typedef Eigen::Matrix<uint8_t, Eigen::Dynamic, 1> coord_t;
using namespace nanoflann;
struct Point
{
coord_t address;
Point() {}
Point(uint8_t coordinates) : address(coord_t::Random(coordinates)) {}
};
struct Container
{
std::vector<Point> points;
Container(uint8_t coordinates, uint32_t l)
: points(l)
{
for(auto& each_location: points)
{
each_location = Point(coordinates);
}
}
};
struct ContainerAdaptor
{
typedef ContainerAdaptor self_t;
typedef nanoflann::metric_L2::traits<uint8_t, self_t>::distance_t metric_t;
typedef KDTreeSingleIndexAdaptor<metric_t, self_t, -1, size_t> index_t;
index_t *index;
const Container &container;
ContainerAdaptor(const int dimensions, const Container &container, const int leaf_max_size = 10)
: container(container)
{
assert(container.points.size() != 0 && container.points[0].address.rows() != 0);
const size_t dims = container.points[0].address.rows();
index = new index_t(dims, *this, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size));
index->buildIndex();
}
~ContainerAdaptor()
{
delete index;
}
inline void query(const uint8_t *query_point, const size_t num_closest, size_t *out_indices, uint32_t *out_distances_sq, const int ignoreThis = 10) const
{
nanoflann::KNNResultSet<uint32_t, size_t, size_t> resultSet(num_closest);
resultSet.init(out_indices, out_distances_sq);
index->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
}
const self_t& derived() const
{
return *this;
}
self_t& derived()
{
return *this;
}
inline size_t kdtree_get_point_count() const
{
return container.points.size();
}
inline size_t kdtree_distance(const uint8_t *p1, const size_t idx_p2, size_t size) const
{
size_t s = 0;
for (size_t i = 0; i < size; i++)
{
const uint8_t d = p1[i] - container.points[idx_p2].address[i];
s += d * d;
}
return s;
}
inline coord_t::Scalar kdtree_get_pt(const size_t idx, int dim) const
{
return container.points[idx].address[dim];
}
template <class BBOX>
bool kdtree_get_bbox(BBOX & bb) const
{
for(size_t i = 0; i < bb.size(); i++)
{
bb[i].low = 0;
bb[i].high = UINT8_MAX;
}
return true;
}
};
void container_demo(const size_t points, const size_t coordinates)
{
Container s(coordinates, points);
coord_t query_pt(coord_t::Random(coordinates));
typedef ContainerAdaptor my_kd_tree_t;
my_kd_tree_t mat_index(coordinates, s, 25);
mat_index.index->buildIndex();
const uint8_t search_radius = static_cast<uint8_t>(100);
std::vector<std::pair<size_t, uint8_t>> ret_matches;
nanoflann::SearchParams params;
const size_t nMatches = mat_index.index->radiusSearch(query_pt.data(), search_radius, ret_matches, params);
for (size_t i = 0; i < nMatches; i++)
{
std::cout << "idx[" << i << "]=" << +ret_matches[i].first << " dist[" << i << "]=" << +ret_matches[i].second << std::endl;
}
std::cout << std::endl;
std::cout << "radiusSearch(): radius=" << +search_radius << " -> " << +nMatches << " matches" << std::endl;
}
int main()
{
container_demo(1e6, 32);
return 0;
}
More info: so it seems that the distance type, which the third parameter of the L2_Adaptor, must be a signed type. Changing the metric_t typedef to the following solves the problem if search_radius and ret_matches are also changed to int64_t.
typedef L2_Adaptor<uint8_t, self_t, int64_t> metric_t;

boost bimap with unordered_set_of and custom types

I want to create a bidirectional map between custom classes using bimap, this is what I do (class A and B are simplifications, they don't store just integers):
class A
{
private:
int value1;
int value2;
public:
int get_value1() const { return this->value1;}
int get_value2() const { return this->value2;}
A(int value1, int value2): value1(value1), value2(value2) {};
};
struct AHash
{
size_t operator()(const A& a) const {
size_t seed = 0;
hash_combine(seed, a.get_value1());
hash_combine(seed, a.get_value2());
return seed;
}
};
struct AComp
{
bool operator()(const A& lhs, const A& rhs) const {
return lhs.get_value1() == rhs.get_value1() &&
lhs.get_value2() == rhs.get_value2();
}
};
Class B same as A, then I created the map:
typedef bimap<
unordered_set_of<A, AHash, AComp>,
unordered_set_of<B, BHash, BComp>
> CustomMap;
CustomMap my_map;
It compiles but crashes without a meaningful log.
Any clue about what I'm doing wrong?
BTW: I'm using c++03
I suspect you have undefined behaviour elsewhere (e.g. memory management, or the actual types A and B). Here's my own self-contained test based on your sample with a lot of random insertions and lookups:
Live On Coliru
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <iostream>
#include <boost/random.hpp> // for test
#include <boost/range/empty.hpp>
#include <boost/range/iterator_range.hpp>
template <typename>
class Obj
{
private:
int value1;
int value2;
boost::tuple<int const&, int const&> key() const { return boost::tie(value1, value2); }
public:
int get_value1() const { return this->value1;}
int get_value2() const { return this->value2;}
Obj(int value1, int value2): value1(value1), value2(value2) {};
struct Hash {
size_t operator()(const Obj& a) const {
size_t seed = 0;
boost::hash_combine(seed, a.get_value1());
boost::hash_combine(seed, a.get_value2());
return seed;
}
};
struct Equality {
bool operator()(const Obj& lhs, const Obj& rhs) const {
return lhs.key() == rhs.key();
}
};
};
typedef Obj<struct TagA> A;
typedef Obj<struct TagB> B;
int myrandom() {
static boost::mt19937 prng(42);
static boost::uniform_int<> dist(0, 1000);
return dist(prng);
}
int main() {
typedef boost::bimaps::bimap<
boost::bimaps::unordered_set_of<A, A::Hash, A::Equality>,
boost::bimaps::unordered_set_of<B, B::Hash, B::Equality>
> CustomMap;
CustomMap map;
int dupes = 0;
for (int i=0; i < 10000; ++i)
{
A a(myrandom(), myrandom());
B b(myrandom(), myrandom());
if (!map.insert(CustomMap::value_type(a, b)).second)
++dupes;
}
std::cout << dupes << " duplicate insertions were skipped\n";
int left_hits = 0;
for (int i=0; i <= 10000; ++i)
if (!boost::empty(boost::make_iterator_range(map.left.equal_range(A(i,i)))))
++left_hits;
int right_hits = 0;
for (int i=0; i <= 10000; ++i)
if (!boost::empty(boost::make_iterator_range(map.right.equal_range(B(i,i)))))
++right_hits;
std::cout << "Random hits (left, right): (" << left_hits << ", " << right_hits << ")\n";
}
Prints (for the given seed and random implementation):
112 duplicate insertions were skipped
Random hits (left, right): (11, 7)
It runs clean under valgrind even in optimized builds.

how to call a templetized vector of records

I'm having a problem getting the syntax right so if someone can help,please?
I have a timing function which take a function and its arguments as a parameters, but I'm not sure how should the call look like.
#include <iostream>
#include <iterator>
#include <random>
#include <vector>
#include<list>
#include<deque>
#include <algorithm>
#include <chrono>
#include <functional>
#include <sstream>
using namespace std;
using namespace std::chrono;
int global_SortType = 1;
template<class F, class A, typename T>
void times(F func, A arg, int n, T typeval) // call func(arg,n)
{
auto t1 = system_clock::now();
func(arg, n, typeval);
auto t2 = system_clock::now();
auto dms = duration_cast<milliseconds>(t2-t1);
cout << "f(x) took " << dms.count() << " milliseconds\n";
}
template<class T>
bool Greater(const T& v1, const T& v2)
{
return false;
}
bool Greater(const int& v1, const int& v2)
{
return v1 > v2;
}
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
}
template <class T>
struct GreaterThan: public std::binary_function<T, T, bool > {
bool operator () ( const T &ival, const T &newval ) const {
return Greater(ival, newval);
}
};
string random_gen(string& s)
{
string Result; // string which will contain the result
ostringstream convert; // stream used for the conversion
convert << rand();
return convert.str();
}
int random_gen(int& i){
default_random_engine re { std::random_device()() };
uniform_int_distribution<int> dist;
auto r= bind(dist,re);
int x =r();
return x;
}
template<class T>
void print(T& val)
{
}
void print(int& val)
{
cout << val << " ";
}
void print(string& val)
{
cout << val.c_str() << " ";
}
struct Record
{
int v;
string s;
Record(){}
Record(int iv, string ss): v(iv), s(ss)
{
}
};
Record random_gen(Record& r)
{
string stemp;
int i = 0;
return Record(random_gen(i), random_gen(stemp));
}
void print(Record& r)
{
cout<<"int="<<r.v<<" string=";
print(r.s);
}
bool Greater(const Record& r1, const Record& r2)
{
return global_SortType == 1 ? Greater(r1.v, r2.v) : Greater(r1.s, r2.s);
}
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::const_iterator it;
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::const_iterator it=seq.begin();
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
int main()
{
int n=1000;
vector<int> v;
times(build_cont<std::vector<int>, int>, v, n, 0); // works
vector<string> sv;
string stemp = "";
times(build_cont<std::vector<string>, string>, sv, n, stemp); // works
global_SortType = 1;
vector<Record> rv;
Record rtemp(0, "sfds");
global_SortType = 2;
vector<Record> rsv;
Record rstemp(0, "sfds");
//This one desn't work and I'm not sure of the right syntax
times(build_cont<std::vector<Record>,Record>, sv, n, stemp);
return 0;
}
I'm getting this error
Non-const lvalue reference to type 'vector>' cannot bind to a value of unrelated type 'vector, allocator>>'
and it points to line
func(arg, n, typeval);
Inside this function:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
You are using const_iterators rather than iterators to perform insertions and removals. You should change the definition of that function as follows:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::iterator it;
// ^^^^^^^^
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::iterator it=seq.begin();
// ^^^^^^^^
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
Also, you forgot to #include the <cstring> standard header, which contains the definition for the strcmp() function. You are using that function inside your Greater() function:
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
// ^^^^^^
// You need to #include <cstring> before calling this function
}
Moreover, you're invoking function times() with the wrong arguments (sv and stemp):
//This one desn't work and I'm not sure of the right sytax
times(build_cont<std::vector<Record>,Record>, rsv, n, rstemp);
// ^^^ ^^^^^^