Recursive Breath First Search works on first execution but not following executions - c++

The solution presented at CodeReview works fine on CentOS 7.1. I have tried to port it to Windows 7, Visual Studio 2012. With minor edits to allow for the parts of C++11 that VS 2012 doesn't support the code compiles, and the first execution of the loop works correctly. The rest of the execution of test cases fail, growing progressively more incorrect with each execution.
The code for this problem can be found on github.
finished computation at 0 /* problem here not included in question */
elapsed time: 0.202012 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 5 Resulting Paths
There were 323 attempted paths
The average path length is 4.8
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
I believe the problem is in one of the files listed below. I've been debugging this for 2 days, I can use some help.
CRKnightMoves_Cpp2.cpp
/*
* KnightMoves.cpp
*
* Author: pacmaninbw
*/
#include "stdafx.h"
#include <iostream>
#include <stdexcept>
#include <chrono>
#include <ctime>
#include <algorithm>
#include <functional>
#include <vector>
#include "KnightMoves.h"
#include "KnightMovesImplementation.h"
#include "KMBoardDimensionConstants.h"
double Average(std::vector<double> TestTimes)
{
double AverageTestTime = 0.0;
double SumOfTestTimes = 0.0;
int CountOfTestTimes = 0;
for (auto TestTimesIter : TestTimes)
{
SumOfTestTimes += TestTimesIter;
CountOfTestTimes++;
}
if (CountOfTestTimes) { // Prevent division by zero.
AverageTestTime = SumOfTestTimes / static_cast<double>(CountOfTestTimes);
}
return AverageTestTime;
}
void OutputOverAllStatistics(std::vector<double> TestTimes)
{
if (TestTimes.size() < 1) {
std::cout << "No test times to run statistics on!" << std::endl;
return;
}
std::cout << std::endl << "Overall Results" << std::endl;
std::cout << "The average execution time is " << Average(TestTimes) << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin() + TestTimes.size()/2, TestTimes.end());
std::cout << "The median execution time is " << TestTimes[TestTimes.size()/2] << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin()+1, TestTimes.end(), std::greater<double>());
std::cout << "The longest execution time is " << TestTimes[0] << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin()+1, TestTimes.end(), std::less<double>());
std::cout << "The shortest execution time is " << TestTimes[0] << " seconds" << std::endl;
}
double ExecutionLoop(KMBaseData UserInputData)
{
KnightMovesImplementation *KnightPathFinder = new KnightMovesImplementation(UserInputData);
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
KMOutputData OutputData = KnightPathFinder->CalculatePaths();
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
double ElapsedTimeForOutPut = elapsed_seconds.count();
char ctimebuffer[1024];
std::cout << "finished computation at " << ctime_s(ctimebuffer, 1024, &end_time) << "\n"
<< "elapsed time: " << ElapsedTimeForOutPut << " Seconds\n" << "\n" << "\n";
// Don't include output of results in elapsed time calculation
OutputData.DontShowPathData();
// OutputData.ShowPathData();
OutputData.ShowResults();
delete KnightPathFinder;
return ElapsedTimeForOutPut;
}
int LetUserEnterTestCaseNumber(std::vector<KMBaseData> &TestData)
{
int i = 1;
int Choice = -1;
std::cout << "Select the number of the test case you want to run.\n";
std::cout << "Test Case #" << "\tStart Name" << "\tTarget Name" << "\tBoard Size" << "\tSlicing Method" << "\n";
for (auto TestCase: TestData) {
std::cout << i << "\t" << TestCase.m_StartName << "\t" << TestCase.m_TargetName << "\t" << TestCase.m_DimensionOneSide << "\t";
switch (TestCase.m_LimitationsOnMoves)
{
default :
throw std::runtime_error("LetUserEnterTestCaseNumber : Unknown type of Path Limitation.");
case DenyByPreviousLocation :
std::cout << "Can't return to previous location";
break;
case DenyByPreviousRowOrColumn:
std::cout << "Can't return to previous row or column";
break;
}
std::cout << "\n";
i++;
}
std::cout << i << "\tAll of the above except for 13 and 14\n";
std::cout << ++i <<"\tAll of the above (Go get lunch)\n";
std::cin >> Choice;
if (Choice == 15)
{
std::vector<KMBaseData> TempTests;
for (auto TestCase: TestData)
{
if ((TestCase.m_DimensionOneSide != MaximumBoardDimension) && (TestCase.m_LimitationsOnMoves != DenyByPreviousLocation))
{
TempTests.push_back(TestCase);
}
}
TestData = TempTests;
}
return Choice;
}
void InitTestData(std::vector<KMBaseData> &TestData)
{
KMBaseData TestCases[] = {
{1,3,"A3",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,1,"A1",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,8,"A8",8,1,"H1", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{2,3,"B3",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{2,3,"B3",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{3,1,"C1",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{3,1,"A3",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,3,"A3",2,5,"B5", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn}, // Minimum should be one move
{8,4,"H4",1,3,"A3", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{4,4,"D4",1,8,"A8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{4,4,"D4",5,6,"E6", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,3,"A3",2,5,"B5", 12, DenyByPreviousRowOrColumn}, // Minimum should be one move
{1,3,"A3",2,5,"B5", DefaultBoardDimensionOnOneSide, DenyByPreviousLocation}, // Minimum should be one move
{1,3,"A3",2,5,"B5", MaximumBoardDimension, DenyByPreviousRowOrColumn} // Minimum should be one move
};
for (int i = 0; i < sizeof(TestCases)/sizeof(KMBaseData); i++) {
TestData.push_back(TestCases[i]);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int status = 0;
std::vector<KMBaseData> TestData;
std::vector<double> TestTimes;
try {
InitTestData(TestData);
int Choice = LetUserEnterTestCaseNumber(TestData);
if (Choice < 0)
{
return status;
}
if (Choice < 15)
{
ExecutionLoop(TestData[Choice-1]);
}
else
{
for (auto TestDataIter: TestData) {
TestTimes.push_back(ExecutionLoop(TestDataIter));
}
}
OutputOverAllStatistics(TestTimes);
return status;
}
catch(std::runtime_error &e) {
std::cerr << "A fatal error occurred in KnightMoves: ";
std::cerr << e.what() << std::endl;
status = 1;
}
catch(std::runtime_error *e) {
std::cerr << "A fatal error occurred in KnightMoves: ";
std::cerr << e->what() << std::endl;
status = 1;
}
catch(...) {
std::cerr << "An unknown fatal error occurred in KnightMoves." << std::endl;
status = 1;
}
return status;
}
KnightMovesImplementation.h
#pragma once
/*
* KnightMovesImplementation.h
*
* Created on: Mar 18, 2016
* Modified on: June 20, 2016
* Author: pacmaninbw
*
* This class provides the search for all the paths a Knight on a chess
* board can take from the point of origin to the destination. It
* implements a modified Knights Tour. The classic knights tour problem
* is to visit every location on the chess board without returning to a
* previous location. That is a single path for the knight. This
* implementation returns all possible paths from point a to point b.
* The actual implementation is documented in the CPP file because it
* can be changed. This head file provides the public interface which
* should not be changed. The public interface may be moved to a
* super class in the future.
*/
#ifndef KNIGHTMOVESIMPLEMENTATION_H_
#define KNIGHTMOVESIMPLEMENTATION_H_
#include "KMPath.h"
#include "KMOutputData.h"
#include "KMMoveFilters.h"
class KnightMovesImplementation {
private:
KMBoardLocation m_PointOfOrigin;
KMBoardLocation m_Destination;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
KMOutputData *m_Results;
KMMoveFilters *m_MoveFilters;
KMPath *m_Path;
protected:
bool CalculatePath(KMMove CurrentMove); // Recursive function
void InitPointOfOrigin(KMBaseData UserData);
void InitDestination(KMBaseData UserData);
public:
KnightMovesImplementation(KMBaseData UserData);
virtual ~KnightMovesImplementation(void);
KMOutputData CalculatePaths();
};
#endif /* KNIGHTMOVESIMPLEMENTATION_H_ */
KnightsImplementation.cpp
/*
* KnightMovesImplementation.cpp
*
* Created on: Mar 18, 2016
* Modified on: June 21, 2016
* Commented on: June 24, 2016
* Author: pacmaninbw
*
* This class implements the search for all possible paths for a Knight
* on a chess board from one particular square on the board to another
* particular square on the board.
*
* The current implementation is a Recursive Breadth First Search. Conceptually
* the algorithm implements a B+ tree with a maximum of 8 possible branches
* at each level. The root of the tree is the point of origin. A particular
* path terminates in a leaf. A leaf is the result of either reaching the
* destination, or reaching a point where there are no more branches to
* traverse.
*
* The m_Path variable is used as a stack within the search.
*
* The public interface CalculatePaths establishes the root and creates
* the first level of branching. The protected interface CalculatePath
* performs the recursive depth first search, however, the
* m_MoveFilters.GetPossibleMoves() function it calls performs a breadth
* first search of the current level.
*
*/
#include "stdafx.h"
#include "KnightMoves.h"
#include "KnightMovesImplementation.h"
#include "KMBoardDimensionConstants.h"
KnightMovesImplementation::~KnightMovesImplementation(void)
{
delete m_MoveFilters;
delete m_Results;
delete m_Path;
}
KnightMovesImplementation::KnightMovesImplementation(KMBaseData UserInputData)
: m_SingleSideBoardDimension(UserInputData.m_DimensionOneSide),
m_PathLimitations(UserInputData.m_LimitationsOnMoves)
{
InitPointOfOrigin(UserInputData);
InitDestination(UserInputData);
m_Path = new KMPath;
m_MoveFilters = new KMMoveFilters(static_cast<unsigned int>(UserInputData.m_DimensionOneSide), UserInputData.m_LimitationsOnMoves);
m_Results = new KMOutputData(m_PointOfOrigin, m_Destination, m_SingleSideBoardDimension, m_PathLimitations);
}
void KnightMovesImplementation::InitPointOfOrigin(KMBaseData UserInputData)
{
m_PointOfOrigin.SetRow(UserInputData.m_StartRow);
m_PointOfOrigin.SetColumn(UserInputData.m_StartColumn);
m_PointOfOrigin.SetName(UserInputData.m_StartName);
m_PointOfOrigin.SetBoardDimension(m_SingleSideBoardDimension);
}
void KnightMovesImplementation::InitDestination(KMBaseData UserInputData)
{
m_Destination.SetRow(UserInputData.m_TargetRow);
m_Destination.SetColumn(UserInputData.m_TargetColumn);
m_Destination.SetName(UserInputData.m_TargetName);
m_Destination.SetBoardDimension(m_SingleSideBoardDimension);
}
KMOutputData KnightMovesImplementation::CalculatePaths()
{
KMRandomAccessMoveCollection PossibleFirstMoves = m_MoveFilters->GetPossibleMoves(m_PointOfOrigin);
if (PossibleFirstMoves.empty())
{
std::cerr << "No Possible Moves in KnightMovesImplementation::CalculatePaths" << std::endl;
}
else
{
for (auto CurrentMoveIter : PossibleFirstMoves)
{
KMMove CurrentMove = CurrentMoveIter;
CurrentMove.SetOriginCalculateDestination(m_PointOfOrigin);
if (CurrentMove.IsValid()) {
CalculatePath(CurrentMove);
}
}
}
return *m_Results;
}
bool KnightMovesImplementation::CalculatePath(KMMove CurrentMove)
{
bool CompletedSearch = false;
KMBoardLocation CurrentLocation = CurrentMove.GetNextLocation();
m_Path->AddMoveToPath(CurrentMove);
m_MoveFilters->PushVisited(CurrentLocation);
if (CurrentLocation == m_Destination)
{
m_Results->AddPath(*m_Path);
CompletedSearch = true;
m_Results->IncrementAttemptedPaths();
}
else
{
if (CurrentMove.IsValid())
{
KMRandomAccessMoveCollection PossibleMoves = m_MoveFilters->GetPossibleMoves(CurrentLocation);
if (!PossibleMoves.empty())
{
for (auto NextMove : PossibleMoves)
{
CalculatePath(NextMove);
}
}
else
{
// No more moves to test, record the attempted path
m_Results->IncrementAttemptedPaths();
}
}
else
{
// There is a logic error if we get here.
std::cerr << "In KnightMovesImplementation::CalculatePath CurrentMove Not Valid" << std::endl;
}
}
m_Path->RemoveLastMove();
m_MoveFilters->PopVisited();
return CompletedSearch;
}
KMMoveFilters.h
#pragma once
/*
* KMMoveFilters.h
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*
* This class provides all the possible Knight moves for a specified location
* on the chess board. In the center of the chess board there are 8 possible
* moves. In the middle of the edge on the chess board there are 4 possible
* moves. In a corner of the chess board there are 2 possible moves. The
* location on the board provides the first filter.
* Slicing is used to allow the program to complete in a reasonable finite
* amount of time. The slicing method can be varied, the default slicing
* method is the knight can't return to any row or column it has previously
* visited. The slicing is the second filter.
*/
#ifndef KMMOVEFILTERS_H_
#define KMMOVEFILTERS_H_
#include <vector>
#include "KnightMoves.h"
#include "KMMove.h"
class KMMoveFilters {
private:
std::vector<KMBoardLocation> m_VisitedLocations;
std::vector<unsigned int> m_VisitedRows;
std::vector<unsigned int> m_VisitedColumns;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
static KMRandomAccessMoveCollection AllPossibleMoves;
// The 8 possible moves the knight can make.
static KMMove Left1Up2;
static KMMove Left2Up1;
static KMMove Left2Down1;
static KMMove Left1Down2;
static KMMove Right1Up2;
static KMMove Right2Up1;
static KMMove Right2Down1;
static KMMove Right1Down2;
protected:
bool IsNotPreviouslyVisited(KMMove Move) const { return IsNotPreviouslyVisited(Move.GetNextLocation()); };
bool IsNotPreviouslyVisited(KMBoardLocation Destination) const;
public:
KMMoveFilters(void);
KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod);
void ResetFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod) {m_SingleSideBoardDimension = BoardDimension; m_PathLimitations = SlicingMethod; }
virtual ~KMMoveFilters(void);
void PushVisited(KMBoardLocation Location);
void PopVisited();
KMRandomAccessMoveCollection GetPossibleMoves(const KMBoardLocation CurrentLocation) const;
};
KMMoveFilters.cpp
/*
* KMMoveFilters.cpp
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*/
#include "stdafx.h"
#include <stdexcept>
#include <algorithm>
#include "KMBoardDimensionConstants.h"
#include "KMMoveFilters.h"
KMMoveFilters::~KMMoveFilters(void)
{
}
KMMoveFilters::KMMoveFilters(void)
: m_SingleSideBoardDimension(DefaultBoardDimensionOnOneSide),
m_PathLimitations(DenyByPreviousRowOrColumn)
{
AllPossibleMoves.push_back(Left1Up2);
AllPossibleMoves.push_back(Left2Up1);
AllPossibleMoves.push_back(Left2Down1);
AllPossibleMoves.push_back(Left1Down2);
AllPossibleMoves.push_back(Right1Up2);
AllPossibleMoves.push_back(Right2Up1);
AllPossibleMoves.push_back(Right2Down1);
AllPossibleMoves.push_back(Right1Down2);
}
KMMoveFilters::KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod)
: m_SingleSideBoardDimension(BoardDimension), m_PathLimitations(SlicingMethod)
{
AllPossibleMoves.push_back(Left1Up2);
AllPossibleMoves.push_back(Left2Up1);
AllPossibleMoves.push_back(Left2Down1);
AllPossibleMoves.push_back(Left1Down2);
AllPossibleMoves.push_back(Right1Up2);
AllPossibleMoves.push_back(Right2Up1);
AllPossibleMoves.push_back(Right2Down1);
AllPossibleMoves.push_back(Right1Down2);
}
const int Left1 = -1;
const int Left2 = -2;
const int Down1 = -1;
const int Down2 = -2;
const int Right1 = 1;
const int Right2 = 2;
const int Up1 = 1;
const int Up2 = 2;
KMMove KMMoveFilters::Left1Up2(Left1, Up2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left2Up1(Left2, Up1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left2Down1(Left2, Down1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left1Down2(Left1, Down2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right1Up2(Right1, Up2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right2Up1(Right2, Up1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right2Down1(Right2, Down1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right1Down2(Right1, Down2, DefaultBoardDimensionOnOneSide);
KMRandomAccessMoveCollection KMMoveFilters::AllPossibleMoves;
KMRandomAccessMoveCollection KMMoveFilters::GetPossibleMoves(const KMBoardLocation CurrentLocation) const
{
KMRandomAccessMoveCollection PossibleMoves;
for (auto PossibeMove : AllPossibleMoves) {
KMMove *TempMove = new KMMove(PossibeMove);
TempMove->SetBoardDimension(m_SingleSideBoardDimension);
TempMove->SetOriginCalculateDestination(CurrentLocation);
if ((TempMove->IsValid()) && (IsNotPreviouslyVisited(*TempMove))) {
PossibleMoves.push_back(*TempMove);
}
}
return PossibleMoves;
}
bool KMMoveFilters::IsNotPreviouslyVisited(KMBoardLocation PossibleDestination) const
{
bool NotPrevioslyVisited = true;
if (!m_VisitedLocations.empty()) { // This is always a test, we can't move backwards
if (std::find(m_VisitedLocations.begin(), m_VisitedLocations.end(), PossibleDestination)
!= m_VisitedLocations.end()) {
NotPrevioslyVisited = false;
}
}
switch (m_PathLimitations) {
default :
throw std::runtime_error("KMPath::CheckMoveAgainstPreviousLocations : Unknown type of Path Limitation.");
case DenyByPreviousLocation :
// Always tested above.
break;
case DenyByPreviousRowOrColumn:
if ((!m_VisitedRows.empty()) && (!m_VisitedColumns.empty())) {
unsigned int PossibleRow = PossibleDestination.GetRow();
if (std::find(m_VisitedRows.begin(), m_VisitedRows.end(), PossibleRow) != m_VisitedRows.end()) {
NotPrevioslyVisited = false;
break;
}
unsigned int PossibleColum = PossibleDestination.GetColumn();
if (std::find(m_VisitedColumns.begin(), m_VisitedColumns.end(), PossibleColum) != m_VisitedColumns.end()) {
NotPrevioslyVisited = false;
}
}
break;
}
return NotPrevioslyVisited;
}
void KMMoveFilters::PushVisited(KMBoardLocation Location)
{
m_VisitedRows.push_back(Location.GetRow());
m_VisitedColumns.push_back(Location.GetColumn());
m_VisitedLocations.push_back(Location);
}
void KMMoveFilters::PopVisited()
{
m_VisitedRows.pop_back();
m_VisitedColumns.pop_back();
m_VisitedLocations.pop_back();
}

The problem was the static declaration of AllPossibleMoves, the memory leak in GetPossibleMoves may have been an additional contributor to the problem. In the CentOS C++11 version AllPossibleMoves was declared as static const, and was not initialized in the constructor, it was initialized outside as each of it's member moves are. This did not compile in Visual Studio 2012 C++. AllPossibleMoves was declared as static const for execution time reasons in the original version.
I am disappointed in the results since this is much slower than the CentOS version using C++11 compiled with g++. The computer I'm running this on is 2 years new than the CentOS computer and has 8GB of memory with an i7 processor.
First I present the working code, then I present the output of the program.
The final code that solves the problem is:
KMMoveFilters.h
#pragma once
/*
* KMMoveFilters.h
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*
* This class provides all the possible Knight moves for a specified location
* on the chess board. In the center of the chess board there are 8 possible
* moves. In the middle of the edge on the chess board there are 4 possible
* moves. In a corner of the chess board there are 2 possible moves. The
* location on the board provides the first filter.
* Slicing is used to allow the program to complete in a reasonable finite
* amount of time. The slicing method can be varied, the default slicing
* method is the knight can't return to any row or column it has previously
* visited. The slicing is the second filter.
*/
#ifndef KMMOVEFILTERS_H_
#define KMMOVEFILTERS_H_
#include <vector>
#include "KnightMoves.h"
#include "KMMove.h"
class KMMoveFilters {
private:
std::vector<KMBoardLocation> m_VisitedLocations;
std::vector<unsigned int> m_VisitedRows;
std::vector<unsigned int> m_VisitedColumns;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
KMRandomAccessMoveCollection AllPossibleMoves;
// The 8 possible moves the knight can make.
static KMMove Left1Up2;
static KMMove Left2Up1;
static KMMove Left2Down1;
static KMMove Left1Down2;
static KMMove Right1Up2;
static KMMove Right2Up1;
static KMMove Right2Down1;
static KMMove Right1Down2;
protected:
bool IsNotPreviouslyVisited(KMMove Move) const { return IsNotPreviouslyVisited(Move.GetNextLocation()); }
bool IsNotPreviouslyVisited(KMBoardLocation Destination) const;
public:
KMMoveFilters(void);
KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod);
void ResetFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod) {m_SingleSideBoardDimension = BoardDimension; m_PathLimitations = SlicingMethod; }
virtual ~KMMoveFilters(void);
void PushVisited(KMBoardLocation Location);
void PopVisited();
KMRandomAccessMoveCollection GetPossibleMoves(const KMBoardLocation CurrentLocation) const;
};
#endif /* KMMOVEFILTERS_H_ */
Only the changes in KMMoveFilters.cpp
KMRandomAccessMoveCollection KMMoveFilters::GetPossibleMoves(const KMBoardLocation CurrentLocation) const
{
KMRandomAccessMoveCollection SafeAllPossibleMoves = AllPossibleMoves;
KMRandomAccessMoveCollection PossibleMoves;
for (auto PossibleMove : SafeAllPossibleMoves) {
PossibleMove.SetBoardDimension(m_SingleSideBoardDimension);
PossibleMove.SetOriginCalculateDestination(CurrentLocation);
if ((PossibleMove.IsValid()) && (IsNotPreviouslyVisited(PossibleMove))) {
PossibleMoves.push_back(PossibleMove);
}
}
return PossibleMoves;
}
The resulting output
Select the number of the test case you want to run.
Test Case # Start Name Target Name Board Size Slicing Method
1 A3 H4 8 Can't return to previous row or column
2 A1 H8 8 Can't return to previous row or column
3 A8 H1 8 Can't return to previous row or column
4 B3 H4 8 Can't return to previous row or column
5 B3 H8 8 Can't return to previous row or column
6 C1 H4 8 Can't return to previous row or column
7 A3 H8 8 Can't return to previous row or column
8 A3 B5 8 Can't return to previous row or column
9 H4 A3 8 Can't return to previous row or column
10 D4 A8 8 Can't return to previous row or column
11 D4 E6 8 Can't return to previous row or column
12 A3 B5 12 Can't return to previous row or column
13 A3 B5 8 Can't return to previous location
14 A3 B5 26 Can't return to previous row or column
15 All of the above except for 13 and 14
16 All of the above (Go get lunch)
finished computation at 0
elapsed time: 0.209012 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 5 Resulting Paths
There were 323 attempted paths
The average path length is 4.8
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.0930054 Seconds
The point of origin for all path searches was A1
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 22 Resulting Paths
There were 160 attempted paths
The average path length is 6.36364
The median path length is 6
The longest path is 8 moves
The shortest path is 6 moves
finished computation at 0
elapsed time: 0.0950054 Seconds
The point of origin for all path searches was A8
The destination point for all path searches was H1
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 22 Resulting Paths
There were 160 attempted paths
The average path length is 6.36364
The median path length is 6
The longest path is 8 moves
The shortest path is 6 moves
finished computation at 0
elapsed time: 0.248014 Seconds
The point of origin for all path searches was B3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 8 Resulting Paths
There were 446 attempted paths
The average path length is 5
The median path length is 5
The longest path is 7 moves
The shortest path is 3 moves
finished computation at 0
elapsed time: 0.251014 Seconds
The point of origin for all path searches was B3
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 39 Resulting Paths
There were 447 attempted paths
The average path length is 6.23077
The median path length is 7
The longest path is 7 moves
The shortest path is 5 moves
finished computation at 0
elapsed time: 0.17801 Seconds
The point of origin for all path searches was C1
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 7 Resulting Paths
There were 324 attempted paths
The average path length is 4.85714
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.18201 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 36 Resulting Paths
There were 324 attempted paths
The average path length is 6
The median path length is 6
The longest path is 8 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.131008 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was B5
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 6 Resulting Paths
There were 243 attempted paths
The average path length is 3
The median path length is 3
The longest path is 5 moves
The shortest path is 1 moves
finished computation at 0
elapsed time: 0.17301 Seconds
The point of origin for all path searches was H4
The destination point for all path searches was A3
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 12 Resulting Paths
There were 318 attempted paths
The average path length is 5.66667
The median path length is 6
The longest path is 8 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.332019 Seconds
The point of origin for all path searches was D4
The destination point for all path searches was A8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 24 Resulting Paths
There were 602 attempted paths
The average path length is 5.25
The median path length is 5
The longest path is 7 moves
The shortest path is 3 moves
finished computation at 0
elapsed time: 0.266015 Seconds
The point of origin for all path searches was D4
The destination point for all path searches was E6
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 21 Resulting Paths
There were 487 attempted paths
The average path length is 4.14286
The median path length is 5
The longest path is 7 moves
The shortest path is 1 moves
finished computation at 0
elapsed time: 1.86411 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was B5
The number of squares on each edge of the board is 12
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 6 Resulting Paths
There were 3440 attempted paths
The average path length is 3
The median path length is 3
The longest path is 5 moves
The shortest path is 1 moves
Overall Results
The average execution time is 0.335186 seconds
The median execution time is 0.209012 seconds
The longest execution time is 1.86411 seconds
The shortest execution time is 0.0930054 seconds
Overall Results with optimized version.
Overall Results
The average execution time is 0.00266682 seconds
The median execution time is 0.0020001 seconds
The longest execution time is 0.0140008 seconds
The shortest execution time is 0.001 seconds
CentOS version Overall Results
The average execution time is 0.00195405 seconds
The median execution time is 0.00103346 seconds
The longest execution time is 0.00130368 seconds
The shortest execution time is 0.000716237 seconds

Related

Binary tree benchmark results

I stumbled upon a website making benchmakrs.
In this case Golang vs C++, binary trees.
The C++ solution does A LOT better than golang using allocation of a memory pool.
I can get behind that but wondered how an implementation without that would fare. So I modified it to look more like the Golang-Code and removed concurrency for both.
In this example and on my machine the golang code runs in around 24 seconds.
The C++ code takes an average of 126 seconds. I did not expect this result at all. I expected C++ to still be faster or maybe be a bit slower but not by a factor of 5.
Did I make some huge mistake? Or do you know the reason for this? Code for both programs is below:
Built with:
mingw32-g++.exe -Wall -fexceptions -O2 -c D:\TMP\Test\main.cpp -o
obj\Release\main.o
mingw32-g++.exe -o bin\Release\Test.exe obj\Release\main.o -s
#include <iostream>
using namespace std;
class Node {
public:
Node(uint64_t d);
~Node();
int Check();
private:
Node* l;
Node* r;
};
Node::Node(uint64_t d){
if (d > 0){
l = new Node(d - 1);
r = new Node(d - 1);
} else {
l = 0;
r = 0;
}
}
Node::~Node(){
if(l){
delete l;
delete r;
}
}
int Node::Check(){
if (l) {
return l->Check() + 1 + r->Check();
} else {
return 1;
}
}
int main()
{
uint64_t min_depth = 4;
uint64_t max_depth = 21;
for (uint64_t d = min_depth; d <= max_depth; d += 2) {
uint64_t iterations = 1 << (max_depth - d + min_depth);
uint64_t c = 0;
for (uint64_t i = 1; i < iterations; i++) {
Node* a = new Node(d);
c += a->Check();
delete a; // I tried commenting this line but it made no big impact
}
cout << iterations << " trees of depth " << d << " check: " << c << "\n";
}
return 0;
}
Golang:
go version go1.7.1 windows/amd64
package main
import(
"fmt"
)
type Node struct {
l *Node
r *Node
}
func (n *Node) check() int {
if n.l != nil {
return n.l.check() + 1 + n.r.check()
} else {
return 1
}
}
func make(d uint) *Node {
root := new(Node)
if d > 0 {
root.l = make(d-1)
root.r = make(d-1)
}
return root
}
func main(){
min_depth := uint(4)
max_depth := uint(21)
for d := min_depth; d <= max_depth; d += 2 {
iterations := 1 << (max_depth - d + min_depth)
c := 0
for i := 1; i < iterations; i++ {
a := make(d)
c += a.check()
}
fmt.Println(iterations, " trees of depth ", d, " check: ", c)
}
}
It's something with your computer your ran on, because I'm getting the expected result where C++ is twice as fast as go.
C++
time cmake-build-debug/main
2097152 trees of depth 4 check: 65011681
524288 trees of depth 6 check: 66584449
131072 trees of depth 8 check: 66977281
32768 trees of depth 10 check: 67074049
8192 trees of depth 12 check: 67092481
2048 trees of depth 14 check: 67074049
512 trees of depth 16 check: 66977281
128 trees of depth 18 check: 66584449
32 trees of depth 20 check: 65011681
cmake-build-debug/main 21.09s user 0.02s system 99% cpu 21.113 total
GO
jonny#skyhawk  ~/Projects/benchmark  time ./main  ✔  2604  02:34:29
2097152 trees of depth 4 check: 65011681
524288 trees of depth 6 check: 66584449
131072 trees of depth 8 check: 66977281
32768 trees of depth 10 check: 67074049
8192 trees of depth 12 check: 67092481
2048 trees of depth 14 check: 67074049
512 trees of depth 16 check: 66977281
128 trees of depth 18 check: 66584449
32 trees of depth 20 check: 65011681
./main 48.72s user 0.52s system 197% cpu 24.905 total
I built the C++ main.cpp with CLion's mose basic / default settings (this CMakeLists.txt that will build a main.cpp)
cmake_minimum_required(VERSION 3.3)
project(test_build)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(BUILD_1 main)
set(SOURCE_FILES_1 main.cpp)
add_executable(${BUILD_1} ${SOURCE_FILES_1})

Encountering "ReadBlockFromDisk: Errors in block header at CBlockDiskPos(nFile=0, nPos=8)" error when I ran modified litecoin chainparams.cpp

First: I am a newbite to altcoin development, next to generate an altcoin from litecoin,
1- I have made a clone of litecoin using git clone https://githubcom/litecoin-project/lotecoin.git
2- I changed some of chain and coin parameters in chainparams.cpp as below:
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chainparams.h"
#include "consensus/merkle.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
#include <assert.h>
#include "chainparamsseeds.h"
#include "arith_uint256.h"
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
CMutableTransaction txNew;
txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = genesisReward;
txNew.vout[0].scriptPubKey = genesisOutputScript;
CBlock genesis;
genesis.nTime = nTime;
genesis.nBits = nBits;
genesis.nNonce = nNonce;
genesis.nVersion = nVersion;
genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
return genesis;
}
/**
* Build the genesis block. Note that the output of its generation
* transaction cannot be spent since it did not originally exist in the
* database.
*
* CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, *nNonce=2083236893, vtx=1)
* CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
* CTxIn(COutPoint(000000, -1), coinbase *04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420**666f722062616e6b73)
* CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
* vMerkleTree: 4a5e1e
*/
static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
const char* pszTimestamp = "Tehran Times, Stonica wins finally";
const CScript genesisOutputScript = CScript() << ParseHex("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9") << OP_CHECKSIG;
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
}
void CChainParams::UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
{
consensus.vDeployments[d].nStartTime = nStartTime;
consensus.vDeployments[d].nTimeout = nTimeout;
}
/**
* Main network
*/
/**
* What makes a good checkpoint block?
* + Is surrounded by blocks with reasonable timestamps
* (no blocks before with a timestamp after, none after with
* timestamp before)
* + Contains no strange transactions
*/
class CMainParams : public CChainParams {
public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 840000;
consensus.BIP34Height = 710000;
consensus.BIP34Hash = uint256S("00000000b2c50d03d4d0bdd38681775ce522f137518145d6b3c913b7dd4423e5");
consensus.BIP65Height = 918684; // bab3041e8977e0dc3eeff63fe707b92bde1dd449d8efafb248c27c8264cc311a
consensus.BIP66Height = 811879; // 7aceee012833fa8952f8835d8b1b3ae233cd6ab08fdb27a771d2bd7bdc491894
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // 3.5 days
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 6048; // 75% of 8064
consensus.nMinerConfirmationWindow = 8064; // nPowTargetTimespan / nPowTargetSpacing * 4
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
// Deployment of BIP68, BIP112, and BIP113.
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1485561600; // January 28, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1517356801; // January 31st, 2018
// Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1485561600; // January 28, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1517356801; // January 31st, 2018
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000ba50a60f8b56c7fe0");
// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x29c8c00e1a5f446a6364a29633d3f1ee16428d87c8d3851a1c570be8170b04c2"); //1259849
/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
* a large 32-bit integer with any alignment.
*/
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0xd0;
pchMessageStart[2] = 0xb6;
pchMessageStart[3] = 0xdb;
nDefaultPort = 9335;
nPruneAfterHeight = 100000;
//static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
genesis = CreateGenesisBlock(1511279793, 1251189192, 0x1d00ffff , 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
/*
// calculate Genesis Block
// Reset genesis
consensus.hashGenesisBlock = uint256S("0x");
std::cout << std::string("Begin calculating Mainnet Genesis Block:\n");
if (true && (genesis.GetHash() != consensus.hashGenesisBlock)) {
LogPrintf("Calculating Mainnet Genesis Block:\n");
arith_uint256 hashTarget = arith_uint256().SetCompact(genesis.nBits);
uint256 hash;
genesis.nNonce = 0;
// This will figure out a valid hash and Nonce if you're
// creating a different genesis block:
// uint256 hashTarget = CBigNum().SetCompact(genesis.nBits).getuint256();
// hashTarget.SetCompact(genesis.nBits, &fNegative, &fOverflow).getuint256();
// while (genesis.GetHash() > hashTarget)
while (UintToArith256(genesis.GetHash()) > hashTarget)
{
++genesis.nNonce;
if (genesis.nNonce == 0)
{
LogPrintf("NONCE WRAPPED, incrementing time");
std::cout << std::string("NONCE WRAPPED, incrementing time:\n");
++genesis.nTime;
}
if (genesis.nNonce % 10000 == 0)
{
LogPrintf("Mainnet: nonce %08u: hash = %s \n", genesis.nNonce, genesis.GetHash().ToString().c_str());
// std::cout << strNetworkID << " nonce: " << genesis.nNonce << " time: " << genesis.nTime << " hash: " << genesis.GetHash().ToString().c_str() << "\n";
}
}
std::cout << "Mainnet ---\n";
std::cout << " nonce: " << genesis.nNonce << "\n";
std::cout << " time: " << genesis.nTime << "\n";
std::cout << " hash: " << genesis.GetHash().ToString().c_str() << "\n";
std::cout << " merklehash: " << genesis.hashMerkleRoot.ToString().c_str() << "\n";
// Mainnet --- nonce: 296277 time: 1390095618 hash: 000000bdd771b14e5a031806292305e563956ce2584278de414d9965f6ab54b0
}
std::cout << std::string("Finished calculating Mainnet Genesis Block:\n");
*/
//printf("%s\n",consensus.hashGenesisBlock.Tostring().c_str());
std::cout << std::string("ENTER:\n");
assert(consensus.hashGenesisBlock == uint256S("0x00000000b2c50d03d4d0bdd38681775ce522f137518145d6b3c913b7dd4423e5"));
assert(genesis.hashMerkleRoot == uint256S("0xf8621e34b0dcd43361fe589702e06aa79992229bfbca57d058d8561635c30fbe"));
std::cout << std::string("PASSED:\n");
printf("min nBit: %08x\n", consensus.powLimit);
// Note that of those with the service bits flag, most only support a subset of possible options
//vSeeds.emplace_back("seed-a.stonicacoin.loshan.co.uk", true);
//vSeeds.emplace_back("dnsseed.thrasher.io", true);
//vSeeds.emplace_back("dnsseed.stonicacointools.com", true);
//vSeeds.emplace_back("dnsseed.stonicacoinpool.org", true);
//vSeeds.emplace_back("dnsseed.koin-project.com", false);
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,127);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,65);
base58Prefixes[SCRIPT_ADDRESS2] = std::vector<unsigned char>(1,56);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,176);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
checkpointData = (CCheckpointData) {
{
{ 0, uint256S("0x00000000b2c50d03d4d0bdd38681775ce522f137518145d6b3c913b7dd4423e5")},
}
};
chainTxData = ChainTxData{
// Data as of block db42d00d824950a125f9b08b6b6c282c484781562fa8b3bd29d6ce4a2627c348 (height 1259851).
1502955334, // * UNIX timestamp of last known number of transactions
1, // * total number of transactions between genesis and that timestamp
// (the tx=... number in the SetBestChain debug.log lines)
0.00 // * estimated number of transactions per second after that timestamp
};
}
};
/**
* Testnet (v3)
*/
class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 840000;
consensus.BIP34Height = 76;
consensus.BIP34Hash = uint256S("8075c771ed8b495ffd943980a95f702ab34fce3c8c54e379548bda33cc8c0573");
consensus.BIP65Height = 76; // 8075c771ed8b495ffd943980a95f702ab34fce3c8c54e379548bda33cc8c0573
consensus.BIP66Height = 76; // 8075c771ed8b495ffd943980a95f702ab34fce3c8c54e379548bda33cc8c0573
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // 3.5 days
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
// Deployment of BIP68, BIP112, and BIP113.
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1483228800; // January 1, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1517356801; // January 31st, 2018
// Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1483228800; // January 1, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1517356801; // January 31st, 2018
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000000364b0cbc3568");
// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0xad8ff6c2f5580d2b50bd881e11312425ea84fa99f322bf132beb722f97971bba"); //153490
pchMessageStart[0] = 0xfd;
pchMessageStart[1] = 0xd2;
pchMessageStart[2] = 0xc8;
pchMessageStart[3] = 0xf1;
nDefaultPort = 19335;
nPruneAfterHeight = 1000;
genesis = CreateGenesisBlock(1511279793, 0, 0x1d00ffff , 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
//assert(consensus.hashGenesisBlock == uint256S("0x"));
//assert(genesis.hashMerkleRoot == uint256S("0x"));
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
//vSeeds.emplace_back("testnet-seed.stonicacointools.com", true);
//vSeeds.emplace_back("seed-b.stonicacoin.loshan.co.uk", true);
//vSeeds.emplace_back("dnsseed-testnet.thrasher.io", true);
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
base58Prefixes[SCRIPT_ADDRESS2] = std::vector<unsigned char>(1,58);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
checkpointData = (CCheckpointData) {
{
{0, uint256S("")},
}
};
chainTxData = ChainTxData{
// Data as of block 3351b6229da00b47ad7a8d7e1323b0e2874744b5296e3d6448293463ab758624 (height 153489)
//1502953751,
//382986,
//0.01
};
}
};
/**
* Regression test
*/
class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests)
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = true;
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 999999999999ULL;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x00");
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
nDefaultPort = 19444;
nPruneAfterHeight = 1000;
genesis = CreateGenesisBlock(1511279793, 0, 0x1d00ffff , 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x9"));
assert(genesis.hashMerkleRoot == uint256S("0x"));
vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds.
fDefaultConsistencyChecks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
checkpointData = (CCheckpointData) {
{
{0, uint256S("530827f38f93b43ed12af0b3ad25a288dc02ed74d6d7857862df51fc56c416f9")},
}
};
chainTxData = ChainTxData{
0,
0,
0
};
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
base58Prefixes[SCRIPT_ADDRESS2] = std::vector<unsigned char>(1,58);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
}
};
static std::unique_ptr<CChainParams> globalChainParams;
const CChainParams &Params() {
assert(globalChainParams);
return *globalChainParams;
}
std::unique_ptr<CChainParams> CreateChainParams(const std::string& chain)
{
if (chain == CBaseChainParams::MAIN)
return std::unique_ptr<CChainParams>(new CMainParams());
else if (chain == CBaseChainParams::TESTNET)
return std::unique_ptr<CChainParams>(new CTestNetParams());
else if (chain == CBaseChainParams::REGTEST)
return std::unique_ptr<CChainParams>(new CRegTestParams());
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
void SelectParams(const std::string& network)
{
SelectBaseParams(network);
globalChainParams = CreateChainParams(network);
}
void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
{
globalChainParams->UpdateVersionBitsParameters(d, nStartTime, nTimeout);
}
As you may know the bitcoin developers has omitted the genesis block mining code from source code published in github, but I fortunately found some piece of code in related blogs and it worked, then I have calculated the new Genesis hash, Merkelroot hash and Nonce and put into code as you can see above.
The code was compiled correctly and I have not received Assertion failed message for Genesis block but I received another error which you can see in debug.log as below:
2017-12-15 07:31:33
2017-12-15 07:31:33 Stonicacoin version v0.15.0.1-gba8ed3a93be
2017-12-15 07:31:33 InitParameterInteraction: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1
2017-12-15 07:31:33 Assuming ancestors of block 29c8c00e1a5f446a6364a29633d3f1ee16428d87c8d3851a1c570be8170b04c2 have valid signatures.
2017-12-15 07:31:33 Using the 'standard' SHA256 implementation
2017-12-15 07:31:33 Using RdRand as an additional entropy source
2017-12-15 07:31:33 Default data directory /home/kevin/.stonicacoin
2017-12-15 07:31:33 Using data directory /home/kevin/.stonicacoin
2017-12-15 07:31:33 Using config file /home/kevin/.stonicacoin/stonicacoin.conf
2017-12-15 07:31:33 Using at most 125 automatic connections (1024 file descriptors available)
2017-12-15 07:31:33 Using 16 MiB out of 32/2 requested for signature cache, able to store 524288 elements
2017-12-15 07:31:33 Using 16 MiB out of 32/2 requested for script execution cache, able to store 524288 elements
2017-12-15 07:31:33 Using 8 threads for script verification
2017-12-15 07:31:33 scheduler thread start
2017-12-15 07:31:33 HTTP: creating work queue of depth 16
2017-12-15 07:31:33 No rpcpassword set - using random cookie authentication
2017-12-15 07:31:33 Generated RPC authentication cookie /home/kevin/.stonicacoin/.cookie
2017-12-15 07:31:33 HTTP: starting 4 worker threads
2017-12-15 07:31:33 Cache configuration:
2017-12-15 07:31:33 * Using 2.0MiB for block index database
2017-12-15 07:31:33 * Using 8.0MiB for chain state database
2017-12-15 07:31:33 * Using 440.0MiB for in-memory UTXO set (plus up to 4.8MiB of unused mempool space)
2017-12-15 07:31:33 init message: Loading block index...
2017-12-15 07:31:33 Opening LevelDB in /home/kevin/.stonicacoin/blocks/index
2017-12-15 07:31:33 Opened LevelDB successfully
2017-12-15 07:31:33 Using obfuscation key for /home/kevin/.stonicacoin/blocks/index: 0000000000000000
2017-12-15 07:31:33 LoadBlockIndexDB: last block file = 0
2017-12-15 07:31:33 LoadBlockIndexDB: last block file info: CBlockFileInfo(blocks=0, size=0, heights=0...0, time=1970-01-01...1970-01-01)
2017-12-15 07:31:33 Checking all blk files are present...
2017-12-15 07:31:33 LoadBlockIndexDB: transaction index disabled
2017-12-15 07:31:33 Initializing databases...
2017-12-15 07:31:33 Pre-allocating up to position 0x1000000 in blk00000.dat
2017-12-15 07:31:33 Opening LevelDB in /home/kevin/.stonicacoin/chainstate
2017-12-15 07:31:33 Opened LevelDB successfully
2017-12-15 07:31:33 Wrote new obfuscate key for /home/kevin/.stonicacoin/chainstate: 77f259e28117a4e1
2017-12-15 07:31:33 Using obfuscation key for /home/kevin/.stonicacoin/chainstate: 77f259e28117a4e1
2017-12-15 07:31:33 init message: Rewinding blocks...
2017-12-15 07:31:33 block index 11ms
2017-12-15 07:31:33 No wallet support compiled in!
2017-12-15 07:31:33 ERROR: ReadBlockFromDisk: Errors in block header at CBlockDiskPos(nFile=0, nPos=8)
2017-12-15 07:31:33 *** Failed to read block
2017-12-15 07:31:33 Error: Error: A fatal internal error occurred, see debug.log for details
I found that this error(eg. ERROR: ReadBlockFromDisk: Errors in block header at CBlockDiskPos(nFile=0, nPos=8) ) occur in CheckProofOfWork function which is in pow.cpp, Any recommendation is appreciated.
After struggling too much I finally solve the issue:
1)
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
should be set to a lower limit like
consensus.powLimit = uint256S("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
and set genesis.nBits to 0x1f00ffff when in CreateGenesisBlock function like
genesis = CreateGenesisBlock(1519394018, 6446, 0x1f0fffff, 1, 1 * COIN);
For Testnet I used 0x1f0fffff.
2) For Bitcoin v0.15+ the following genesis block generating code should be used:
// calculate Genesis Block
// Reset genesis
consensus.hashGenesisBlock = uint256S("0x");
std::cout << std::string("Begin calculating Mainnet Genesis Block:\n");
if (true && (genesis.GetHash(consensus) != consensus.hashGenesisBlock)) {
// LogPrintf("Calculating Mainnet Genesis Block:\n");
arith_uint256 hashTarget = arith_uint256().SetCompact(genesis.nBits);
uint256 hash;
genesis.nNonce = ArithToUint256(0);
while (UintToArith256(genesis.GetHash(consensus)) > hashTarget)
{
genesis.nNonce = ArithToUint256(UintToArith256(genesis.nNonce) + 1);
if (genesis.nNonce == ArithToUint256(arith_uint256(0)))
{
LogPrintf("NONCE WRAPPED, incrementing time");
std::cout << std::string("NONCE WRAPPED, incrementing time:\n");
++genesis.nTime;
}
if ((int)genesis.nNonce.GetUint64(0) % 10000 == 0)
{
std::cout << strNetworkID << " hashTarget: " << hashTarget.ToString() << " nonce: " << genesis.nNonce.ToString() << " time: " << genesis.nTime << " hash: " << genesis.GetHash(consensus).ToString().c_str() << "\r";
}
}
std::cout << "Mainnet ---\n";
std::cout << " nonce: " << genesis.nNonce.ToString() << "\n";
std::cout << " time: " << genesis.nTime << "\n";
std::cout << " hash: " << genesis.GetHash(consensus).ToString().c_str() << "\n";
std::cout << " merklehash: " << genesis.hashMerkleRoot.ToString().c_str() << "\n";
}
std::cout << std::string("Finished calculating Mainnet Genesis Block:\n");
For the older codebases the genesis block generating code that #Hossein Mirheydari given is working. Actually you should check
genesis.nNonce = ArithToUint256(arith_uint256(nNonce));
definition in
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward);
function to see if it's given as above or as
genesis.nNonce = nNonce;
If it's given as the latter one then use #Hossein Mirheydari's genesis block generation code. If it's given with ArithToUint256() function use the genesis block generation code I pasted above.
3) This genesis block generation should be done for Mainnet and Testnet seperately. Regtest does not need a genesis block generation since it's pow limit is so small (but you may want to do it anyway just to be sure of everything works fine) and so
printf("TEST GENESIS HASH: %s\n",consensus.hashGenesisBlock.ToString().c_str());
printf("TEST MERKLE ROOT: %s\n",genesis.hashMerkleRoot.ToString().c_str());
assert(consensus.hashGenesisBlock == uint256S("0x0009b0d830d5e13f7a39dd6c30cae59ff95e1a4aa4fc22435dc1fcb92561cd8e"));
assert(genesis.hashMerkleRoot == uint256S("0xf1552bf3d58facdc6d7ec8461aff6b0560d20eb16e41749b9f8f5a7eaa1220fc"));
inserting the printed consensus.hashGenesisBlock and genesis.hashMerkleRoot into
assert(consensus.hashGenesisBlock == uint256S("0x0009b0d830d5e13f7a39dd6c30cae59ff95e1a4aa4fc22435dc1fcb92561cd8e"));
assert(genesis.hashMerkleRoot == uint256S("0xf1552bf3d58facdc6d7ec8461aff6b0560d20eb16e41749b9f8f5a7eaa1220fc"));
statements works.
4) If you have
consensus.powLimitStart = uint256S("0000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.powLimitLegacy = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
like the ones in Bitcoin Gold (which I now am using) use the same pow limit as consensus.powLimit.
Thus, with genesis generation code, genesis block is generated. With low pow limit, genesis block be in pow range and so no PoW validation error will occur anymore.
I hope this will help.
On the main branch at this time the solution for me was to change the GetHash() to GetPoWHash(). I also followed the answer of #Bedri Ozgur Guler for the PoWLimit and nBits:
consensus.hashGenesisBlock = uint256S("0x");
std::cout << std::string("Begin calculating Mainnet Genesis Block:\n");
if (true && (genesis.GetHash() != consensus.hashGenesisBlock)) {
LogPrintf("Calculating Mainnet Genesis Block:\n");
arith_uint256 hashTarget = arith_uint256().SetCompact(genesis.nBits);
uint256 hash;
genesis.nNonce = 0;
while (UintToArith256(genesis.GetPoWHash()) > hashTarget) // ---> Here GetPoWHash() !!
{
++genesis.nNonce;
if (genesis.nNonce == 0)
{
LogPrintf("NONCE WRAPPED, incrementing time");
std::cout << std::string("NONCE WRAPPED, incrementing time:\n");
++genesis.nTime;
}
if (genesis.nNonce % 10000 == 0)
{
LogPrintf("Mainnet: nonce %08u: hash = %s \n", genesis.nNonce, genesis.GetHash().ToString().c_str());
// std::cout << strNetworkID << " nonce: " << genesis.nNonce << " time: " << genesis.nTime << " hash: " << genesis.GetHash().ToString().c_str() << "\n";
}
}
std::cout << "Mainnet ---\n";
std::cout << " nonce: " << genesis.nNonce << "\n";
std::cout << " time: " << genesis.nTime << "\n";
std::cout << " hash: " << genesis.GetHash().ToString().c_str() << "\n"; // The hash for the assert is GetHash()
std::cout << " merklehash: " << genesis.hashMerkleRoot.ToString().c_str() << "\n";
// Mainnet --- nonce: 296277 time: 1390095618 hash: 000000bdd771b14e5a031806292305e563956ce2584278de414d9965f6ab54b0
}
std::cout << std::string("Finished calculating Mainnet Genesis Block:\n");
Looking in the file validation.cpp on the method ReadBlockFromDisk I found that the hash that must pass the CheckProofOfWork is the PoWHash
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
// ...
// Check the header
if (!CheckProofOfWork(block.GetPoWHash(), block.nBits, consensusParams))
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
}
EDIT: Tested with the litecoin PoWLimit and nBits values and It worked.
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
genesis = CreateGenesisBlock(1619494752, 721332, 0x1e0ffff0, 1, 50 * COIN);
FreddyJS, genesis.GetPoWHash() worked nicely for litecoin, the hashes match what I would get with GenesisH0. But unfortunately it doesn't work on another coin I'm testing, gives an error on compilation. Any ideas?
error: no matching function for call to ‘CBlock::GetPoWHash()’
After some digging, the code is different than litecoin. In validation.cpp:
// Check the header
if (!CheckProofOfWork(block.GetPoWHash(nHeight), block.nBits, consensusParams))
return error("ReadBlockFromDisk: Errors in block header at %s, %d", pos.ToString(), nHeight);
GetPoWHash(nHeight) vs GetPoWHash() in litecoin.
This is code of Raptoreum
https://github.com/Raptor3um/raptoreum/blob/master/src/chainparams.cpp
Them try debug Dash to find genesis block hash
Them change only Time
static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
const char* pszTimestamp = "The Times 22/Jan/2018 Raptoreum is name of the game for new generation of firms";
const CScript genesisOutputScript = CScript() << ParseHex("040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9") << OP_CHECKSIG;
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
}
The Dask use X11
###
static void FindMainNetGenesisBlock(uint32_t nTime, uint32_t nBits, const char* network)
{
CBlock block = CreateGenesisBlock(nTime, 0, nBits, 4, 5000 * COIN);
arith_uint256 bnTarget;
bnTarget.SetCompact(block.nBits);
for (uint32_t nNonce = 0; nNonce < UINT32_MAX; nNonce++) {
block.nNonce = nNonce;
uint256 hash = block.GetPOWHash();
if (nNonce % 48 == 0) {
printf("\nrnonce=%d, pow is %s\n", nNonce, hash.GetHex().c_str());
}
if (UintToArith256(hash) <= bnTarget) {
printf("\n%s net\n", network);
printf("\ngenesis is %s\n", block.ToString().c_str());
printf("\npow is %s\n", hash.GetHex().c_str());
printf("\ngenesisNonce is %d\n", nNonce);
std::cout << "Genesis Merkle " << block.hashMerkleRoot.GetHex() << std::endl;
return;
}
}
// This is very unlikely to happen as we start the devnet with a very low difficulty. In many cases even the first
// iteration of the above loop will give a result already
error("%sNetGenesisBlock: could not find %s genesis block",network, network);
assert(false);
}
###
It seems the -reindex parameter solves avoids the issue and gives the main reason of error which is Genesis Block does not have valid PoW. It is suggested in BITCOIN CORE CRASHED #8081 (https://github.com/bitcoin/bitcoin/issues/8081) for a solution for the issue of a corrupted blockchain data:
sipa commented on 21 May 2016
Start bitcoind or bitcoin-qt with
the -reindex command line option. This will throw away the indexes and
rebuild them from scratch, but reuse the blocks on disk in so far as
they are usable.

CGAL::Delaunay_d C++ on UCI Seeds dataset: “EXC_BAD_ACCESS”

For my PhD work, I need to construct the Delaunay triangulation (DT) of a given point set in any (low) dimension. So far, I have been using the C++ CGAL library with data up to 4D without any noticeable problem.
However, as I used the same class CGAL::Delaunay_d as I previously used on an 7D data set (namely UCI repository Seeds data set ), it seems like something is going wrong and I don't know how to trace my problem.
Here is a copy-pastable code to reproduce the execution:
// CGAL includes
#include <CGAL/Cartesian_d.h>
#include <CGAL/Delaunay_d.h>
#include <CGAL/Gmpq.h>
// STANDARD includes
#include <iostream>
#include <string>
#include <map>
// TYPEDEFS
typedef CGAL::Gmpq EXACT_RT;
typedef CGAL::Cartesian_d<EXACT_RT> EXACT_Kernel;
typedef EXACT_Kernel::Point_d EXACT_Point;
typedef EXACT_Kernel::Vector_d EXACT_Vector;
typedef CGAL::Delaunay_d<EXACT_Kernel> EXACT_Delaunay_any_d;
typedef EXACT_Delaunay_any_d::Vertex_handle EXACT_Vertex_handle;
// NAMESPACES
using namespace std;
using namespace CGAL;
// FUNCTIONS
int main(int argc, char *argv[]);
void delaunay_d(EXACT_Delaunay_any_d &DT, const map <unsigned, vector<EXACT_RT> > &data);
map <unsigned, vector<EXACT_RT> > data_parse(const string &data_set);
// DATASET
char seeds_data_char[] = "15,26 14,84 0,871 5,763 3,312 2,221 5,22\n\
14,88 14,57 0,8811 5,554 3,333 1,018 4,956\n\
14,29 14,09 0,905 5,291 3,337 2,699 4,825\n\
13,84 13,94 0,8955 5,324 3,379 2,259 4,805\n\
16,14 14,99 0,9034 5,658 3,562 1,355 5,175\n\
14,38 14,21 0,8951 5,386 3,312 2,462 4,956\n\
14,69 14,49 0,8799 5,563 3,259 3,586 5,219\n\
14,11 14,1 0,8911 5,42 3,302 2,7 5\n\
16,63 15,46 0,8747 6,053 3,465 2,04 5,877\n\
16,44 15,25 0,888 5,884 3,505 1,969 5,533\n\
15,26 14,85 0,8696 5,714 3,242 4,543 5,314\n\
14,03 14,16 0,8796 5,438 3,201 1,717 5,001\n\
13,89 14,02 0,888 5,439 3,199 3,986 4,738\n\
13,78 14,06 0,8759 5,479 3,156 3,136 4,872\n\
13,74 14,05 0,8744 5,482 3,114 2,932 4,825\n\
14,59 14,28 0,8993 5,351 3,333 4,185 4,781\n\
13,99 13,83 0,9183 5,119 3,383 5,234 4,781\n\
15,69 14,75 0,9058 5,527 3,514 1,599 5,046\n\
14,7 14,21 0,9153 5,205 3,466 1,767 4,649\n\
12,72 13,57 0,8686 5,226 3,049 4,102 4,914\n\
14,16 14,4 0,8584 5,658 3,129 3,072 5,176\n\
14,11 14,26 0,8722 5,52 3,168 2,688 5,219\n\
15,88 14,9 0,8988 5,618 3,507 0,7651 5,091\n\
12,08 13,23 0,8664 5,099 2,936 1,415 4,961\n\
15,01 14,76 0,8657 5,789 3,245 1,791 5,001\n\
16,19 15,16 0,8849 5,833 3,421 0,903 5,307\n\
13,02 13,76 0,8641 5,395 3,026 3,373 4,825\n\
12,74 13,67 0,8564 5,395 2,956 2,504 4,869\n\
14,11 14,18 0,882 5,541 3,221 2,754 5,038\n\
13,45 14,02 0,8604 5,516 3,065 3,531 5,097\n\
13,16 13,82 0,8662 5,454 2,975 0,8551 5,056\n\
15,49 14,94 0,8724 5,757 3,371 3,412 5,228\n\
14,09 14,41 0,8529 5,717 3,186 3,92 5,299\n\
13,94 14,17 0,8728 5,585 3,15 2,124 5,012\n\
15,05 14,68 0,8779 5,712 3,328 2,129 5,36\n\
16,12 15 0,9 5,709 3,485 2,27 5,443\n\
16,2 15,27 0,8734 5,826 3,464 2,823 5,527\n\
17,08 15,38 0,9079 5,832 3,683 2,956 5,484\n\
14,8 14,52 0,8823 5,656 3,288 3,112 5,309\n\
14,28 14,17 0,8944 5,397 3,298 6,685 5,001\n\
13,54 13,85 0,8871 5,348 3,156 2,587 5,178\n\
13,5 13,85 0,8852 5,351 3,158 2,249 5,176\n\
13,16 13,55 0,9009 5,138 3,201 2,461 4,783\n\
15,5 14,86 0,882 5,877 3,396 4,711 5,528\n\
15,11 14,54 0,8986 5,579 3,462 3,128 5,18\n\
13,8 14,04 0,8794 5,376 3,155 1,56 4,961\n\
15,36 14,76 0,8861 5,701 3,393 1,367 5,132\n\
14,99 14,56 0,8883 5,57 3,377 2,958 5,175\n\
14,79 14,52 0,8819 5,545 3,291 2,704 5,111\n\
14,86 14,67 0,8676 5,678 3,258 2,129 5,351\n\
14,43 14,4 0,8751 5,585 3,272 3,975 5,144\n\
15,78 14,91 0,8923 5,674 3,434 5,593 5,136\n\
14,49 14,61 0,8538 5,715 3,113 4,116 5,396\n\
14,33 14,28 0,8831 5,504 3,199 3,328 5,224\n\
14,52 14,6 0,8557 5,741 3,113 1,481 5,487\n\
15,03 14,77 0,8658 5,702 3,212 1,933 5,439\n\
14,46 14,35 0,8818 5,388 3,377 2,802 5,044\n\
14,92 14,43 0,9006 5,384 3,412 1,142 5,088\n\
15,38 14,77 0,8857 5,662 3,419 1,999 5,222\n\
12,11 13,47 0,8392 5,159 3,032 1,502 4,519\n\
11,42 12,86 0,8683 5,008 2,85 2,7 4,607\n\
11,23 12,63 0,884 4,902 2,879 2,269 4,703\n\
12,36 13,19 0,8923 5,076 3,042 3,22 4,605\n\
13,22 13,84 0,868 5,395 3,07 4,157 5,088\n\
12,78 13,57 0,8716 5,262 3,026 1,176 4,782\n\
12,88 13,5 0,8879 5,139 3,119 2,352 4,607\n\
14,34 14,37 0,8726 5,63 3,19 1,313 5,15\n\
14,01 14,29 0,8625 5,609 3,158 2,217 5,132\n\
14,37 14,39 0,8726 5,569 3,153 1,464 5,3\n\
12,73 13,75 0,8458 5,412 2,882 3,533 5,067\n\
17,63 15,98 0,8673 6,191 3,561 4,076 6,06\n\
16,84 15,67 0,8623 5,998 3,484 4,675 5,877\n\
17,26 15,73 0,8763 5,978 3,594 4,539 5,791\n\
19,11 16,26 0,9081 6,154 3,93 2,936 6,079\n\
16,82 15,51 0,8786 6,017 3,486 4,004 5,841\n\
16,77 15,62 0,8638 5,927 3,438 4,92 5,795\n\
17,32 15,91 0,8599 6,064 3,403 3,824 5,922\n\
20,71 17,23 0,8763 6,579 3,814 4,451 6,451\n\
18,94 16,49 0,875 6,445 3,639 5,064 6,362\n\
17,12 15,55 0,8892 5,85 3,566 2,858 5,746\n\
16,53 15,34 0,8823 5,875 3,467 5,532 5,88\n\
18,72 16,19 0,8977 6,006 3,857 5,324 5,879\n\
20,2 16,89 0,8894 6,285 3,864 5,173 6,187\n\
19,57 16,74 0,8779 6,384 3,772 1,472 6,273\n\
19,51 16,71 0,878 6,366 3,801 2,962 6,185\n\
18,27 16,09 0,887 6,173 3,651 2,443 6,197\n\
18,88 16,26 0,8969 6,084 3,764 1,649 6,109\n\
18,98 16,66 0,859 6,549 3,67 3,691 6,498\n\
21,18 17,21 0,8989 6,573 4,033 5,78 6,231\n\
20,88 17,05 0,9031 6,45 4,032 5,016 6,321\n\
20,1 16,99 0,8746 6,581 3,785 1,955 6,449\n\
18,76 16,2 0,8984 6,172 3,796 3,12 6,053\n\
18,81 16,29 0,8906 6,272 3,693 3,237 6,053\n\
18,59 16,05 0,9066 6,037 3,86 6,001 5,877\n\
18,36 16,52 0,8452 6,666 3,485 4,933 6,448\n\
16,87 15,65 0,8648 6,139 3,463 3,696 5,967\n\
19,31 16,59 0,8815 6,341 3,81 3,477 6,238\n\
18,98 16,57 0,8687 6,449 3,552 2,144 6,453\n\
18,17 16,26 0,8637 6,271 3,512 2,853 6,273\n\
18,72 16,34 0,881 6,219 3,684 2,188 6,097\n\
16,41 15,25 0,8866 5,718 3,525 4,217 5,618\n\
17,99 15,86 0,8992 5,89 3,694 2,068 5,837\n\
19,46 16,5 0,8985 6,113 3,892 4,308 6,009\n\
19,18 16,63 0,8717 6,369 3,681 3,357 6,229\n\
18,95 16,42 0,8829 6,248 3,755 3,368 6,148\n\
18,83 16,29 0,8917 6,037 3,786 2,553 5,879\n\
18,85 16,17 0,9056 6,152 3,806 2,843 6,2\n\
17,63 15,86 0,88 6,033 3,573 3,747 5,929\n\
19,94 16,92 0,8752 6,675 3,763 3,252 6,55\n\
18,55 16,22 0,8865 6,153 3,674 1,738 5,894\n\
18,45 16,12 0,8921 6,107 3,769 2,235 5,794\n\
19,38 16,72 0,8716 6,303 3,791 3,678 5,965\n\
19,13 16,31 0,9035 6,183 3,902 2,109 5,924\n\
19,14 16,61 0,8722 6,259 3,737 6,682 6,053\n\
20,97 17,25 0,8859 6,563 3,991 4,677 6,316\n\
19,06 16,45 0,8854 6,416 3,719 2,248 6,163\n\
18,96 16,2 0,9077 6,051 3,897 4,334 5,75\n\
19,15 16,45 0,889 6,245 3,815 3,084 6,185\n\
18,89 16,23 0,9008 6,227 3,769 3,639 5,966\n\
20,03 16,9 0,8811 6,493 3,857 3,063 6,32\n\
20,24 16,91 0,8897 6,315 3,962 5,901 6,188\n\
18,14 16,12 0,8772 6,059 3,563 3,619 6,011\n\
16,17 15,38 0,8588 5,762 3,387 4,286 5,703\n\
18,43 15,97 0,9077 5,98 3,771 2,984 5,905\n\
15,99 14,89 0,9064 5,363 3,582 3,336 5,144\n\
18,75 16,18 0,8999 6,111 3,869 4,188 5,992\n\
18,65 16,41 0,8698 6,285 3,594 4,391 6,102\n\
17,98 15,85 0,8993 5,979 3,687 2,257 5,919\n\
20,16 17,03 0,8735 6,513 3,773 1,91 6,185\n\
17,55 15,66 0,8991 5,791 3,69 5,366 5,661\n\
18,3 15,89 0,9108 5,979 3,755 2,837 5,962\n\
18,94 16,32 0,8942 6,144 3,825 2,908 5,949\n\
15,38 14,9 0,8706 5,884 3,268 4,462 5,795\n\
16,16 15,33 0,8644 5,845 3,395 4,266 5,795\n\
15,56 14,89 0,8823 5,776 3,408 4,972 5,847\n\
15,38 14,66 0,899 5,477 3,465 3,6 5,439\n\
17,36 15,76 0,8785 6,145 3,574 3,526 5,971\n\
15,57 15,15 0,8527 5,92 3,231 2,64 5,879\n\
15,6 15,11 0,858 5,832 3,286 2,725 5,752\n\
16,23 15,18 0,885 5,872 3,472 3,769 5,922\n\
13,07 13,92 0,848 5,472 2,994 5,304 5,395\n\
13,32 13,94 0,8613 5,541 3,073 7,035 5,44\n\
13,34 13,95 0,862 5,389 3,074 5,995 5,307\n\
12,22 13,32 0,8652 5,224 2,967 5,469 5,221\n\
11,82 13,4 0,8274 5,314 2,777 4,471 5,178\n\
11,21 13,13 0,8167 5,279 2,687 6,169 5,275\n\
11,43 13,13 0,8335 5,176 2,719 2,221 5,132\n\
12,49 13,46 0,8658 5,267 2,967 4,421 5,002\n\
12,7 13,71 0,8491 5,386 2,911 3,26 5,316\n\
10,79 12,93 0,8107 5,317 2,648 5,462 5,194\n\
11,83 13,23 0,8496 5,263 2,84 5,195 5,307\n\
12,01 13,52 0,8249 5,405 2,776 6,992 5,27\n\
12,26 13,6 0,8333 5,408 2,833 4,756 5,36\n\
11,18 13,04 0,8266 5,22 2,693 3,332 5,001\n\
11,36 13,05 0,8382 5,175 2,755 4,048 5,263\n\
11,19 13,05 0,8253 5,25 2,675 5,813 5,219\n\
11,34 12,87 0,8596 5,053 2,849 3,347 5,003\n\
12,13 13,73 0,8081 5,394 2,745 4,825 5,22\n\
11,75 13,52 0,8082 5,444 2,678 4,378 5,31\n\
11,49 13,22 0,8263 5,304 2,695 5,388 5,31\n\
12,54 13,67 0,8425 5,451 2,879 3,082 5,491\n\
12,02 13,33 0,8503 5,35 2,81 4,271 5,308\n\
12,05 13,41 0,8416 5,267 2,847 4,988 5,046\n\
12,55 13,57 0,8558 5,333 2,968 4,419 5,176\n\
11,14 12,79 0,8558 5,011 2,794 6,388 5,049\n\
12,1 13,15 0,8793 5,105 2,941 2,201 5,056\n\
12,44 13,59 0,8462 5,319 2,897 4,924 5,27\n\
12,15 13,45 0,8443 5,417 2,837 3,638 5,338\n\
11,35 13,12 0,8291 5,176 2,668 4,337 5,132\n\
11,24 13 0,8359 5,09 2,715 3,521 5,088\n\
11,02 13 0,8189 5,325 2,701 6,735 5,163\n\
11,55 13,1 0,8455 5,167 2,845 6,715 4,956\n\
11,27 12,97 0,8419 5,088 2,763 4,309 5\n\
11,4 13,08 0,8375 5,136 2,763 5,588 5,089\n\
10,83 12,96 0,8099 5,278 2,641 5,182 5,185\n\
10,8 12,57 0,859 4,981 2,821 4,773 5,063\n\
11,26 13,01 0,8355 5,186 2,71 5,335 5,092\n\
10,74 12,73 0,8329 5,145 2,642 4,702 4,963\n\
11,48 13,05 0,8473 5,18 2,758 5,876 5,002\n\
12,21 13,47 0,8453 5,357 2,893 1,661 5,178\n\
11,41 12,95 0,856 5,09 2,775 4,957 4,825\n\
12,46 13,41 0,8706 5,236 3,017 4,987 5,147\n\
12,19 13,36 0,8579 5,24 2,909 4,857 5,158\n\
11,65 13,07 0,8575 5,108 2,85 5,209 5,135\n\
12,89 13,77 0,8541 5,495 3,026 6,185 5,316\n\
11,56 13,31 0,8198 5,363 2,683 4,062 5,182\n\
11,81 13,45 0,8198 5,413 2,716 4,898 5,352\n\
10,91 12,8 0,8372 5,088 2,675 4,179 4,956\n\
11,23 12,82 0,8594 5,089 2,821 7,524 4,957\n\
10,59 12,41 0,8648 4,899 2,787 4,975 4,794\n\
10,93 12,8 0,839 5,046 2,717 5,398 5,045\n\
11,27 12,86 0,8563 5,091 2,804 3,985 5,001\n\
11,87 13,02 0,8795 5,132 2,953 3,597 5,132\n\
10,82 12,83 0,8256 5,18 2,63 4,853 5,089\n\
12,11 13,27 0,8639 5,236 2,975 4,132 5,012\n\
12,8 13,47 0,886 5,16 3,126 4,873 4,914\n\
12,79 13,53 0,8786 5,224 3,054 5,483 4,958\n\
13,37 13,78 0,8849 5,32 3,128 4,67 5,091\n\
12,62 13,67 0,8481 5,41 2,911 3,306 5,231\n\
12,76 13,38 0,8964 5,073 3,155 2,828 4,83\n\
12,38 13,44 0,8609 5,219 2,989 5,472 5,045\n\
12,67 13,32 0,8977 4,984 3,135 2,3 4,745\n\
11,18 12,72 0,868 5,009 2,81 4,051 4,828\n\
12,7 13,41 0,8874 5,183 3,091 8,456 5\n\
12,37 13,47 0,8567 5,204 2,96 3,919 5,001\n\
12,19 13,2 0,8783 5,137 2,981 3,631 4,87\n\
11,23 12,88 0,8511 5,14 2,795 4,325 5,003\n\
13,2 13,66 0,8883 5,236 3,232 8,315 5,056\n\
11,84 13,21 0,8521 5,175 2,836 3,598 5,044\n\
12,3 13,34 0,8684 5,243 2,974 5,637 5,063";
//////////
// MAIN //
//////////
int main(int argc, char *argv[]) {
// DATA SET declaration
string seeds_data(seeds_data_char);
map <unsigned, vector<EXACT_RT> > my_DATA = data_parse(seeds_data);
// DT declaration
EXACT_Delaunay_any_d my_DT(7);
// DT construction
delaunay_d(my_DT, my_DATA);
return 0;
}
// DELAUNAY TRIANGULATION function
void delaunay_d(
EXACT_Delaunay_any_d &DT,
const map <unsigned, vector<EXACT_RT> > &data)
{
// Dim size variable
int d = ((data.begin()) ->second).size();
int i = 1;
// Scanning data set -- DT construction
for(map <unsigned, vector<EXACT_RT> >::const_iterator it = data.begin(); it != data.end(); it++, i++){
// Constructing Point objects
EXACT_Point tmp = EXACT_Point(d, (it ->second).begin(), (it ->second).end());
// Inserting point in the triangulation
EXACT_Vertex_handle v_tmp = DT.insert(tmp);
// DEBUG
std::cout << "-- DEBUG POST -- " << i << " -- DT.all_simplices().size() : " << DT.all_simplices().size() << " -- DT.current_dimension() : " << DT.current_dimension() << endl;
}
}
// PARSING DATA function
map <unsigned, vector<EXACT_RT> > data_parse(
const string &data_set)
{
// RETURNED map
map <unsigned, vector<EXACT_RT> > result;
// TMP variables declaration
vector<EXACT_RT> vect;
string tmp_value;
char current_char;
for (unsigned i=0; i<data_set.length(); i++)
{
current_char = data_set[i];
// Testing if read character is tab or space (i.e. end of a number) ...
if( (current_char == '\t') || (current_char == ' ')) {
double curr_num = atof(tmp_value.c_str());
vect.push_back(EXACT_RT(curr_num)); // Storing the double value.
tmp_value.clear(); // Clearing current number
}
// ... end of a line ...
else
if ( (current_char == '\n') || (current_char == '\r') ) {
double curr_num = atof(tmp_value.c_str());
vect.push_back(EXACT_RT(curr_num)); // Storing the double value.
result.insert ( pair <unsigned, vector<EXACT_RT> > (i++, vect) ); // Feeding returned map
tmp_value.clear(); // Clearing current number
vect.clear(); // Clearing the vector containing the converted values
}
// .. storing any other character
else {
// Dealing with decimal character (from ',' to '.')
if(current_char == ',') {
// Storing current character
tmp_value.push_back('.');
}
else
// Storing current character
tmp_value.push_back(current_char);
}
}
return result;
}
As I used exact number type CGAL::Gmpq for the computation of the DT, I suspect an internal bug of CGAL but I can't assert it. My error actually occurs within the call of function EXACT_Delaunay_any_d::insert()and I don't know how to find a way to debug it.
An “EXC_BAD_ACCESS” signal stops my program while trying to insert the 78-th point, after construction of 20926 simplices.
My questions are:
Should I use some other exact number type ?
Is it an internal issue of CGAL function EXACT_Delaunay_any_d::insert() ?
Is it a problem of memory allocation related to my OS (Mac OS X 10.6.8) ?
Thanks in advance if you have any answer / clue for investigation !
Octavio
Interestingly, you just reported a stack overflow on stackoverflow.com.
The function visibility_search in Convex_hull_d.h is recursive (not a terminal recursion) and the depth of the recursion is apparently not bounded. This is a bug. You should be able to get a bit further by increasing the stack size (the procedure is explained in other questions on this site). Let us know how that fares.
You can also try to reduce other stack use. Maybe using mpq_class or CGAL::Quotient<CGAL::MP_Float> instead of CGAL::Gmpq would help, or it might be even worse. You could also recompile the GMP library after replacing 65536 with 1024 in gmp-impl.h.

Extract array's elements as object's constant properties into a temporary place

I am a senior PHP/Perl developer and a relative beginner in C++.
What I have is an array of objects of a class, one element of which in it's turn is an array-pointer for the subclass (if I'm using the right terms).
What I need is to process one by one the main array and extract it's elements into a separate place if they meet a certain condition (unique Name property).
Then output extracted one with it's sub-arrays. Then output the original.
I have came up with various solutions and trying to define which is the best to use with your help.
Details.
These is the header file's part of the 2 classes I was mentioned:
/// class to define the modificable parameters of the machine
class CMachineParameter {
public:
/// Short name: "Cutoff"
char const *Name;
/// Longer description: "Cutoff Frequency (0-7f)"
char const *Description;
/// recommended >= 0. If negative, minValue is represented as 0 in the pattern
int MinValue;
/// recommended <= 65535. Basically so that it can be represented in the pattern
int MaxValue;
/// flags. (see below)
int Flags;
/// default value for params that have MPF_STATE flag set
int DefValue;
};
///\name CMachineParameter flags
///\{
/// shows a line with no text nor knob
int const MPF_NULL = 0;
/// shows a line with the text in a centered label
int const MPF_LABEL = 1;
/// shows a tweakable knob and text
int const MPF_STATE = 2;
///\}
///\name CFxCallback::CallbackFunc codes
///\{
int const CBID_GET_WINDOW = 0;
///\}
///\name CMachineInfo::HostEvent codes
///\{
/// Sent by the host to ask if this plugin uses the auxiliary column. return true or false.
int const HE_NEEDS_AUX_COLUMN = 0;
///\}
/*////////////////////////////////////////////////////////////////////////*/
/// class defining the machine properties
class CMachineInfo {
public:
CMachineInfo(
short APIVersion, int flags, int numParameters, CMachineParameter const * const * parameters,
char const * name, char const * shortName, char const * author, char const * command, int numCols
) :
APIVersion(APIVersion), PlugVersion(0), Flags(flags), numParameters(numParameters), Parameters(parameters),
Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
{}
CMachineInfo(
short APIVersion, short PlugVersion, int flags, int numParameters, CMachineParameter const * const * parameters,
char const * name, char const * shortName, char const * author, char const * command, int numCols
) :
APIVersion(APIVersion), PlugVersion(PlugVersion), Flags(flags), numParameters(numParameters), Parameters(parameters),
Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
{}
/// API version. Use MI_VERSION
short const APIVersion;
/// plug version. Your machine version. Shown in Hexadecimal.
short const PlugVersion;
/// Machine flags. Defines the type of machine
int const Flags;
/// number of parameters.
int const numParameters;
/// a pointer to an array of pointers to parameter infos
CMachineParameter const * const * const Parameters;
/// "Name of the machine in listing"
char const * const Name;
/// "Name of the machine in machine Display"
char const * const ShortName;
/// "Name of author"
char const * const Author;
/// "Text to show as custom command (see Command method)"
char const * const Command;
/// number of columns to display in the parameters' window
int numCols;
};
This is the code I have:
for(int i(0) ; i < MAX_MACHINES ; ++i) if(song.machine(i)) {
if (song.machine(i)->GetDllName() == "") continue;
Plugin & plug = *((Plugin*)song.machine(i));
const psycle::plugin_interface::CMachineInfo psycle_info = plug.GetInfo();
// Process machine general info: psycle_info.Name, psycle_info.ShortName, psycle_info.Author etc
if(psycle_info.numParameters > 0 && psycle_info.Parameters) {
const int n = psycle_info.numParameters;
for(int i(0) ; i < n; ++i) {
const psycle::plugin_interface::CMachineParameter & psycle_param(*psycle_info.Parameters[i]);
// Process machine's parameters: psycle_param.MinValue, psycle_param.MaxValue, psycle_param.DefValue, psycle_param.Flags etc
Basically, I have a list of virtual machines each with its parameters. Only ShortName differs (Machine red 1, Machine red 3, Machine grey 4). I need to output the unique machines and it's parameters by Name (Machine red, Machine grey).
In PHP I would have simply created and array like $original[psycle_info.Name] = array('author'=>psycle_info.Author, 'parameters'=>array(psycle_param.MinValue, psycle_param.MaxValue, psycle_param.DefValue, psycle_param.Flags));
In C++ I have found that I could achieve something like this with std::map and std::vector STL libraries.
This article shows a very similar problem and the solution which I came up to also from the other sources that came up to me:
http://www.dreamincode.net/forums/topic/67804-c-multidimensional-associative-arrays/
But what is the general way of doing this?
Maybe I need to create a 2 new classes of non-const elements? Or maybe a simple standard array and use standard array looping functions all the time?
Thanks very much for your attention!
PS. An example of data:
0.
Name: 'Red Machine v.098'
ShortName: 'Red Machine 1'
Author: 'Jeremy'
Parameters: 0(Name: 'OSC type', MinValue: 0, MaxValue: 255, DefValue:0), 1(Name: 'CutOff', MinValue: 0, MaxValue: 16555, DefValue: 1000), 2(Name: 'LFO', MinValue: 100, MaxValue: 30555, DefValue: 3000)
1.
Name: 'Red Machine v.098'
ShortName: 'Red Machine 2'
Author: 'Jeremy'
Parameters: 0(Name: 'OSC type', MinValue: 0, MaxValue: 255, DefValue:0), 1(Name: 'CutOff', MinValue: 0, MaxValue: 16555, DefValue: 1000), 2(Name: 'LFO', MinValue: 100, MaxValue: 30555, DefValue: 3000)
2.
Name: 'Yellow Machine v.2.4.5'
ShortName: 'Yellow Machine 1'
Author: 'Anthony'
Parameters: 0(Name: 'OSC 1 wave', MinValue: 0, MaxValue: 255, DefValue: 0), 1(Name: 'OSC 2 Wave', MinValue: 0, MaxValue: 255, DefValue: 0), 2(Name: 'OSC 3 Wave', MinValue: 0, MaxValue: 255, DefValue: 0)
3.
Name: 'Yellow Machine v.2.4.5'
ShortName: 'Yellow Machine 2'
Author: 'Anthony'
Parameters: 0(Name: 'OSC 1 wave', MinValue: 0, MaxValue: 255, DefValue: 0), 1(Name: 'OSC 2 Wave', MinValue: 0, MaxValue: 255, DefValue: 0), 2(Name: 'OSC 3 Wave', MinValue: 0, MaxValue: 255, DefValue: 0)
Obviously, as the output in this case I would need to have 2 unique machines.
PS2. I will now make the further description of what I have and what needs to be done.
I have an array song.machine(i)
Algorithm:
As song.machine(i) info is limited, cycle through it to get another object and operate with it
In cycle, create Plugin (class object) plug from each song.machine(i) so finally can get
object CMachineInfo psycle_info via psycle_info = plug.GetInfo();
which has all the information we need to output
Compare Name in psycle_info.Name. If it has been shown already, skip to the next.
Otherwise, output the data.
This is the header file I am including which contains the 2 classes I've shown originally:
http://sourceforge.net/p/psycle/code/HEAD/tree/trunk/psycle-plugins/src/psycle/plugin_interface.hpp
To sum up again: as I can access objects iteratively only, plus I need to perform some operations on the data (like replace all spaces to '+' in Name), I thought of creating a temporary array/class. But probably, it would be enough to create a simple array char nameShown[100] where I can store all the names that are shown already and with each song.machine(i) iteration, cycle through whole nameShown and if it contains current Name, continue to the next.
I just didn't want to cycle through "nameShown" every time and in PHP we could use associative arrays for this: so I can only check if ($nameShown[$Name]) exists or no.
It also appeared to me a headache that like you said, I cannot copy properties and parameters because they are constants!!
Seemed like a very simple task, but so hard for a beginner like me.
Hope I've covered all the confusing points!
PS4. I have just also updated the topic's name so it would contain "constant" mentioning.
PS5. Here is the code that basically should do what I need:
std::string nameShown[100];
bool should_skip = false;
for (int k(0); k < i; k++) {
if (nameShown[k] == psycle_info.Name) {
should_skip = true;
}
}
if(should_skip) continue;
nameShown[i] = psycle_info.Name;
std::ostringstream l; l << "Plugin: " << psycle_info.Name; loggers::warning()(l.str());
So the full piece would look like:
std::string nameShown[100];
for(int i(0) ; i < MAX_MACHINES ; ++i) if(song.machine(i)) {
if (song.machine(i)->GetDllName() == "") continue;
Plugin & plug = *((Plugin*)song.machine(i));
const psycle::plugin_interface::CMachineInfo psycle_info = plug.GetInfo();
// Process machine general info: psycle_info.Name, psycle_info.ShortName, psycle_info.Author etc
bool should_skip = false;
for (int k(0); k < i; k++) {
if (nameShown[k] == psycle_info.Name) {
should_skip = true;
}
}
if(should_skip) continue;
nameShown[i] = psycle_info.Name;
std::ostringstream l; l << "Plugin: " << psycle_info.Name; loggers::warning()(l.str());
if(psycle_info.numParameters > 0 && psycle_info.Parameters) {
const int n = psycle_info.numParameters;
for(int i(0) ; i < n; ++i) {
const psycle::plugin_interface::CMachineParameter & psycle_param(*psycle_info.Parameters[i]);
// Process machine's parameters: psycle_param.MinValue, psycle_param.MaxValue, psycle_param.DefValue, psycle_param.Flags etc
The output before the cycle inserted:
log: 446322us: W: main: Plugin: Sublime 1.1
log: 446413us: W: main: Plugin: Pooplog FM UltraLight0.68b
log: 446497us: W: main: Plugin: Phantom 1.2
log: 446581us: W: main: Plugin: Pooplog FM UltraLight0.68b
log: 446649us: W: main: Plugin: FeedMe 1.2
log: 446729us: W: main: Plugin: Drum Synth v.2.5
log: 446793us: W: main: Plugin: Sublime 1.1
log: 446876us: W: main: Plugin: Arguru Compressor
log: 446945us: W: main: Plugin: Pooplog Filter 0.06b
log: 447016us: W: main: Plugin: Slicit
log: 447095us: W: main: Plugin: EQ-3
log: 447163us: W: main: Plugin: Arguru Compressor
log: 447231us: W: main: Plugin: Pooplog Filter 0.06b
log: 447294us: W: main: Plugin: Koruz
log: 447361us: W: main: Plugin: Pooplog Filter 0.06b
log: 447425us: W: main: Plugin: EQ-3
log: 447496us: W: main: Plugin: Arguru Compressor
log: 447558us: W: main: Plugin: EQ-3
After:
log: 414242us: W: main: Plugin: Sublime 1.1
log: 414331us: W: main: Plugin: Pooplog FM UltraLight0.68b
log: 414415us: W: main: Plugin: Phantom 1.2
log: 414499us: W: main: Plugin: FeedMe 1.2
log: 414560us: W: main: Plugin: Drum Synth v.2.5
log: 414622us: W: main: Plugin: Arguru Compressor
log: 414694us: W: main: Plugin: Pooplog Filter 0.06b
log: 414761us: W: main: Plugin: Slicit
log: 414830us: W: main: Plugin: EQ-3
log: 414897us: W: main: Plugin: Koruz
Note, in the newly added cycle, I have tried to use for (int k(0); k < sizeof(nameShown); k++) which sounded to me more obvious as for a PHP programmer, but even on a first song.machine(i) iteration, it loops itself for pretty many times and then gives a segfault, so I've changed this to "k < i".
This is basically what I was needed. And was just curious if it's the right way of doing, because looping every time through non existent elements of the filter array sounds primitive and ineffective to me.
Another thing is that after the output of the unique machines, which I have just accomplished, I would need to output the whole list. So what, I would have to create the whole song.machine(i) cycle again, so to avoid code repetition, I was thought of extraction of the values I need into a simpler data handles. In PHP I would have used associative arrays for this.
Again, to sum up, first I need to output the unique machines list and then all of them with different details set for each list.
Probably, as it seems to complex to explain (but it's a very simple task actually, XML generation) I will stick to what works and seeking for which code is best is may be too luxurious in this case.
Lets start with what is clear, you have a array song.machine(i)
Algorithm:
Compare Names in song.machine(i)
If Match, Dynamic Cast song.machine(i) to Plugin (class object) plug
Use this to make object CMachineInfo psycle_info via psycle_info = plug.GetInfo();
Process this data / Output / Extract it ?.
Lets start with what you have written in class definition:
char*
A char*, declared allocates memory on heap/Stack. This in turn has to be deleted as objects are destroyed in application. Your code is creating a lot of objects then you copy them, pass them around to another objects. The memory location for pointer is not allocated (e.g. new [] operator / malloc) which would eventually be overwritten by any type / Object data. You may not get segmentation fault sometimes, but your data is surely not safe in such case.
In such a case you should use string, in-built char* or char arrays. They allocate and destroy on their own. So no memory faults and also the functions like string.compare() can be easy to use. refer here
Copy / Assignment Operator
Copy and Assignment operator (e.g. CMachineInfo obj1 = CMachineInfo Obj2) work on object of a class and as name suggest they are meant to pass on data among objects. C++ defines by default, operators for you. But the behavior is tricky when you are dealing with pointers. You can override this by defining what you want (See Below).
Const members
In c++ class, members can be const (integers with no work around) with a rule, Objects with const members cannot be used in COPY AND ASSIGNMENT OPERATOR. It is simple to understand. You have a object say obj1, now you want to copy all its content to another object obj2 (of same class). When Obj2 is created, it members get defined as constant and now you are trying to overwrite the values. The compiler wont allow this. The work around such a problem is that you declare such members as private. Private members aren't allowed access directly (e.g. pyscle_info.Name). You have to write a public function which in turn can deliver this access to them (e.g. pyscle_info.GET_NAME_OF_MACHINE();)
Let look at the modified code CMachineParameter:
class CMachineParameter{
public:
CMachineParameter(string Name, string Description, int MinValue,
int MaxValue, int Flags, int DefValue
): Name(Name), Description(Description), MinValue(MinValue), MaxValue(MaxValue), Flags(Flags), DefValue(DefValue)
{}
/*DeFault Constructor*/
CMachineParameter(): Name("TEST"), Description("Temp Object")
{}
// Copy Constructor
CMachineParameter(const CMachineParameter &TO_BE_COPIED)
: Name(TO_BE_COPIED.Name), Description(TO_BE_COPIED.Description), MinValue(TO_BE_COPIED.MinValue),
MaxValue(TO_BE_COPIED.MaxValue) ,Flags(TO_BE_COPIED.Flags), DefValue(TO_BE_COPIED.DefValue)
{}
// Assignment Operator
CMachineParameter & operator=(const CMachineParameter & TO_BE_Assigned)
{
if(this != &TO_BE_Assigned)
{
Name = TO_BE_Assigned.Name;
Description = TO_BE_Assigned.Description;
MinValue = TO_BE_Assigned.MinValue;
MaxValue = TO_BE_Assigned.MaxValue;
Flags = TO_BE_Assigned.Flags;
DefValue = TO_BE_Assigned.DefValue;
}
return *this;
}
void show(void) const;
/*To access the Private members*/
std::string GET_NAME(void) const;
/// recommended >= 0. If negative, minValue is represented as 0 in the pattern
int MinValue;
/// recommended <= 65535. Basically so that it can be represented in the pattern
int MaxValue;
/// flags. (see below)
int Flags;
/// default value for params that have MPF_STATE flag set
int DefValue;
private:
/*
* Making them as Private as Assignment and copy operator Cannot be used with Const members.
*/
/// Short name: "Cutoff"
string Name;
/// Longer description: "Cutoff Frequency (0-7f)"
string Description;
};
void CMachineParameter::show() const
{
cout << "------------------------------------------------------\n";
cout << "My Machine " << Name << endl
<< "\t" << Description << endl
<< "\tMinValue: " << MinValue << endl
<< "\tMaxValue: " << MaxValue << endl
<< "\tFlags: " << Flags << endl
<< "\tDefValue: " << DefValue << endl;
cout << "------------------------------------------------------\n";
}
std::string CMachineParameter::GET_NAME(void) const
{
return Name;
}
For CMachineInfo you need to implement the Assignment / Copy Operator. I implemented a vector of CMachineParameter const *.
class CMachineInfo {
public:
CMachineInfo(
short APIVersion, int flags, int numParameters,
string name, string shortName, string author, string command, int numCols
) :
APIVersion(APIVersion), PlugVersion(0), Flags(flags), numParameters(numParameters),
Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
{}
CMachineInfo(
short APIVersion, short PlugVersion, int flags, int numParameters,
string name, string shortName, string author, string command, int numCols
) :
APIVersion(APIVersion), PlugVersion(PlugVersion), Flags(flags), numParameters(numParameters),
Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
{}
// Copy Constructor
CMachineInfo (const CMachineInfo &TO_BE_COPIED)
: APIVersion(TO_BE_COPIED.APIVersion), PlugVersion(TO_BE_COPIED.PlugVersion),
Flags(TO_BE_COPIED.Flags), numParameters(TO_BE_COPIED.numParameters), Name(TO_BE_COPIED.Name),
ShortName(TO_BE_COPIED.ShortName), Author(TO_BE_COPIED.Author), Command(TO_BE_COPIED.Command),
numCols(TO_BE_COPIED.numCols), Parameter(TO_BE_COPIED.Parameter)
{}
// Assignment Operator
CMachineInfo & operator=(const CMachineInfo &TO_BE_Assigned)
{
if(this != &TO_BE_Assigned)
{
APIVersion = TO_BE_Assigned.APIVersion;
PlugVersion = TO_BE_Assigned.PlugVersion;
Flags = TO_BE_Assigned.Flags;
numParameters = TO_BE_Assigned.numParameters;
Name = TO_BE_Assigned.Name;
ShortName = TO_BE_Assigned.ShortName;
Author = TO_BE_Assigned.Author;
Command = TO_BE_Assigned.Command;
numCols = TO_BE_Assigned.numCols;
Parameter = TO_BE_Assigned.Parameter;
}
return *this;
}
void SHOW(void) const;
/// a pointer to an array of pointers to parameter infos
/// CMachineParameter const * const * const Parameters;
vector<CMachineParameter const *> Parameter;
/// "Name of the machine in listing"
std::string Name;
/// "Name of the machine in machine Display"
std::string ShortName;
/// "Name of author"
std::string Author;
/// "Text to show as custom command (see Command method)"
std::string Command;
/// number of columns to display in the parameters' window
int numCols;
private:
/// API version. Use MI_VERSION
short APIVersion;
/// plug version. Your machine version. Shown in Hexadecimal.
short PlugVersion;
/// Machine flags. Defines the type of machine
int Flags;
/// number of parameters.
int numParameters;
};
void CMachineInfo::SHOW() const
{
cout << "My Machine IS: " << endl
<< "\tAPIVersion: " << APIVersion << endl
<< "\tPlugVersion: " << PlugVersion << endl
<< "\tFlags: " << Flags << endl
<< "\tnumParameters: " << numParameters << endl
<< "\tName: " << Name << endl
<< "\tShortName: " << ShortName << endl
<< "\tAuthor: " << Author << endl
<< "\tCommand: " << Command << endl
<< "\tnumCols: " << numCols << endl;
}

Boost.thread code presents different behaviour in Ubuntu and in Windows

I have a little simple program to test wether I can visualize a point cloud from a different thread and continue working in the main thread until typing 'q' in the terminal.
In Ubuntu 10.04, the code works, letting me visualize the cloud as new points are added to it in each iteration. However, in Windows 7 this dosn't work (I'm compiling it with QtCreator). The cloud is shown and new points are computed in each turn, but this never exits. When typing 'q', the loop stops but the visualization thread keeps running. The only way to stop execution is to explicitly use CTRL+C.
More things:
If I don't uncomment the addPointCloud line before the !viewer->wasStopped() loop in the Visualize function, the point cloud is never shown. It doesn't matter that later in the loop I explicitly add it. It has to be done before the loop (now that line is commented to demonstrate that behaviour).
I also tried to use boost::mutex instead of *tbb::queuing_mutex*, but again, the program won't exit.
Do you have any idea why the thread is never joining?. Also, constructive critics about my thread usage are always welcomed, I want to keep improving.
Here's the code:
#include <boost/thread/thread.hpp>
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include "tbb/queuing_mutex.h"
typedef pcl::PointXYZ PointType;
typedef pcl::PointCloud<PointType> PointCloudType;
typedef tbb::queuing_mutex MutexType;
//typedef boost::mutex MutexType;
MutexType safe_update;
const unsigned int HEIGHT = 100;
const unsigned int WIDTH = 100;
bool has_to_update(true);
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
// viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
while(!viewer->wasStopped()) {
viewer->spinOnce(100);
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
}
delete viewer;
};
int main(int argc, char** argv) {
PointCloudType::Ptr c(new PointCloudType);
c->height=HEIGHT;
c->width=WIDTH;
const unsigned int size( c->height*c->width);
c->points.resize(size);
for(unsigned int i(0);i<size;++i){
c->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
c->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
c->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cout << "Filled cloud height: " << c->height << " ** widht = "
<< c->width << " ** size: " << c->points.size()
<< "\n"
;
boost::thread vis_thread( boost::bind( &Visualize, boost::ref(c) ) );
char exit;
std::vector<PointType> new_points;
new_points.resize(10);
PointType new_point;
while(exit!='q') {
for(unsigned int i(0);i<10;++i) {
new_point.x = 2000 * rand () / (RAND_MAX + 1.0f);
new_point.y = 2000 * rand () / (RAND_MAX + 1.0f);
new_point.z = 2000 * rand () / (RAND_MAX + 1.0f);
std::cout << "New point " << i << " with x = " << new_point.x
<< " ; y = " << new_point.y << " ; z = "
<< new_point.z << "\n"
;
new_points.push_back(new_point);
}
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
c->insert( c->points.end(), new_points.begin(), new_points.end() );
has_to_update = true;
} // end scoped_lock
std::cout << "Exit?: ";
std::cin>>exit;
}
vis_thread.join();
return 0;
}
Thanks for your time!.
EDIT: Since I can't use a debugger due to Windows not recognizing the executable format(?) I've put some qDebug() lines over the Visualize function (also, instead of directly calling viewer->wasStopped() now I'm using a volatile intermediate var, stopped):
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
volatile bool stopped( false );
int iterations( -1 );
while(!stopped) {
++iterations;
qDebug() << "Before spinOnce - it: << iteration << "\n";
viewer->spinOnce(100);
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
stopped = viewer->wasStopped();
qDebug() << "Before a new loop - it:" << iteration << "\n";
}
delete viewer;
};
Well, Before spinOnce is only displayed once, with iteration=0. The Before a new loop line is never printed.
On the other hand, the main thread keeps calculating and printing those points to the standard output until 'q' is inputted.
It seems that the visualization thread frozens in the viewer->spinOnce(100) call. If instead of spinOnce(100) I use the other visualization method, spin(), nothing changes.
Maybe there's a data race in my code, but for much I keep checking it, I can't find the race myself.
NOTE: According to the PCL library doc, spinOnce(int time) calls the interactor and updates the screen once, whereas spin() calls the interactor and runs an internal loop.
EDIT #2: Today I tried to execute the code again in Ubuntu and resulted in a deadlock with the PCL visualizer. I added some volatile keywords and a new loop check. Now it seems it goes well (at least it worked as expected, no wrong turns...). Here's the new version:
Global vars:
volatile bool has_to_update(true); // as suggested by #daramarak
volatile bool quit(false); // new while loop control var
Visualize method:
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
while(!viewer->wasStopped() && !quit ) {
viewer->spinOnce(100);
{
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
}
delete viewer;
};
Main function:
// everything the same until...
std::cin>>exit;
quit = (exit=='q');
// no more changes
I dont' like, however, the new control loop var hack. Isn't there a better way to know when to exit?. Right now, I can't realize any other way...
I believe that the wasStopped() function is a const member function thereby not changing the state of the object, so there might be an optimization in play here (It might cache the wasStopped() value as the compiler assumes the answer won't change. I suggest you try to wrap the viewer in another object with a function bool wasStopped() volatile, that might prevent such optimizations.