I'm transforming a parser for v8 in NodeJS. Currently I have the following structure
struct Node {
short tag;
std::string data;
Node(std::string input, short tagId) {
tag = tagId;
data = input;
}
};
std::vector<Node> elems;
And I'm populating the vector from loop like this:
elems.push_back(Node(STRING, 3));
My goal is return a javascript object like this:
[
{ tag: 2, data: "asdsad" },
{ tag: 2, data: "asdsad" },
{ tag: 2, data: "asdsad" }
]
But since the V8 documentation is crappy, I couldn't figure out how to do it. My best shot was to make
Local<Value> data[2] = {
Local<Value>::New(Integer::New(2)),
String::New("test")
};
but I can't figure out how to make it an array and return it.
I'm using this example as template.
Here's what you might try (node v0.10.x):
// in globals
static Persistent<String> data_symbol;
static Persistent<String> tag_symbol;
// in addon initialization function
data_symbol = NODE_PSYMBOL("data");
tag_symbol = NODE_PSYMBOL("tag");
// in some function somewhere
HandleScope scope;
Local<Array> nodes = Array::New();
for (unsigned int i = 0; i < elems.length; ++i) {
HandleScope scope;
Local<Object> node_obj = Object::New();
node_obj->Set(data_symbol, String::New(elems[i].data.c_str()));
node_obj->Set(tag_symbol, Integer::New(elems[i].tag));
nodes->Set(i, node_obj);
}
return scope.Close(nodes);
I was looking for a solution for Node 5, and it seems mscdex's answer is outdated now. Hope this helps someone.
HandleScope scope(isolate);
Local<Array> nodes = Array::New(isolate);
for (unsigned int i = 0; i < elems.length; ++i) {
HandleScope scope(isolate);
Local<Object> node = Object::New(isolate);
node->Set(String::NewFromUtf8(isolate, "data"), String::New(isolate, elems[i].data.c_str()));
node->Set(String::NewFromUtf8(isolate, "tag"), Integer::New(isolate, elems[i].tag));
nodes->Set(i, node);
}
args.GetReturnValue().Set(nodes);
My problem is I have a header file in which I store all my classes and in my cpp file I have my initializations of these classes, the initialization is not dynamic I have a number of arrays of different classes.
Now the problem is when I started expanding the classes in my header, adding more members and methods,the initialization of 1 specific class start throwing assertions at me of memory overlapping and suggested using memmove() instead of memcpy(), though I use neither of them in that class.
I tried replacing this class with a downgraded version of it that worked in older versions of my source but it still threw the same assertion at me I don't know what part of the code is relevant here is the assertion is being asserted in the initialization of the class without any pointer to what exactly is wrong.
this is my initialization of the class :
Shuriken(cpFloat m,cpVect veloc,cpFloat elast,cpFloat myu) : Spark() , Bang1() , ShurikenFlame()
{
smass = m;
sv = veloc;
se = elast;
su = myu;
ToDraw = false;
Removed = true;
AllocatedBombAnim = false;
DrawFlamedShuriken = false;
DeployFlameBang = false;
PassedLine = false;
hitfruit = false;
FruitIsBeingHit = false;
ToRemoveBody = false;
DummyAdded = false;
HitBossBanana = false;
fruitnum = 11;//11 means it has no fruit
Sec_FlameCounter = 3;
LitShuriken_UVs[0] = CIwFVec2(0, 0);
LitShuriken_UVs[2] = CIwFVec2(1.0/4, 1.0/4);
LitShuriken_UVs[3] = CIwFVec2(1.0/4, 0);
LitShuriken_UVs[1] = CIwFVec2(0, 1.0/4);
Sparkle_UVs[0] = CIwFVec2(0, 0);
Sparkle_UVs[2] = CIwFVec2(1.0/2, 1.0/4);
Sparkle_UVs[3] = CIwFVec2(1.0/2, 0);
Sparkle_UVs[1] = CIwFVec2(0, 1.0/4);
lastPos = cpvzero;
lastAngle = 0;
struct cpVect initShurikenBody_Verts[35] =
{
cpv(-128.01,41.26),
cpv(-58.74,45.42),
cpv(-47.79,32.04),
cpv(-40.06,33.94),
cpv(-20.63,48.29),
cpv(-16.13,55.67),
cpv(-25.33,69.7),
cpv(0,134.67),
cpv(25.34,70.16),
cpv(16.14,55.67),
cpv(20.75,48.1),
cpv(39.98,34.04),
cpv(47.96,32.15),
cpv(58.86,45.38),
cpv(128.01,41.26),
cpv(74.55,-2.82),
cpv(57.95,1.45),
cpv(52.25,-5.19),
cpv(45.16,-26.79),
cpv(45.77,-35.34),
cpv(61.86,-41.64),
cpv(79.1,-108.95),
cpv(20.79,-71.41),
cpv(19.62,-54.33),
cpv(11.91,-51.14),
cpv(-12.02,-51.11),
cpv(-19.64,-54.26),
cpv(-20.81,-71.4),
cpv(-79.11,-108.95),
cpv(-61.87,-41.6),
cpv(-45.77,-35.03),
cpv(-45.18,-26.75),
cpv(-52.23,-5.35),
cpv(-57.88,1.31),
cpv(-74.48,-2.8),
};
struct cpVect initShurikenShape_Verts1[5] =
{
cpv(-128.01,41.26),
cpv(-58.74,45.42),
cpv(-47.79,32.04),
cpv(-57.88,1.31),
cpv(-74.48,-2.8),
};
struct cpVect initShurikenShape_Verts2[5] =
{
cpv(0,134.67),
cpv(25.34,70.16),
cpv(16.14,55.67),
cpv(-16.13,55.67),
cpv(-25.33,69.7),
};
struct cpVect initShurikenShape_Verts3[5] =
{
cpv(47.96,32.15),
cpv(58.86,45.38),
cpv(128.01,41.26),
cpv(74.55,-2.82),
cpv(57.95,1.45),
};
struct cpVect initShurikenShape_Verts4[5] =
{
cpv(79.1,-108.95),
cpv(20.79,-71.41),
cpv(19.62,-54.33),
cpv(45.77,-35.34),
cpv(61.86,-41.64),
};
struct cpVect initShurikenShape_Verts5[5] =
{
cpv(-79.11,-108.95),
cpv(-61.87,-41.6),
cpv(-45.77,-35.03),
cpv(-19.64,-54.26),
cpv(-20.81,-71.4),
};
struct cpVect initShurikenShape_Verts6[4] =
{
cpv(-47.79,32.04),
cpv(-40.06,33.94),
cpv(-52.23,-5.35),
cpv(-57.88,1.31),
};
struct cpVect initShurikenShape_Verts7[4] =
{
cpv(-20.63,48.29),
cpv(-16.13,55.67),
cpv(16.14,55.67),
cpv(20.75,48.1),
};
struct cpVect initShurikenShape_Verts8[4] =
{
cpv(39.98,34.04),
cpv(47.96,32.15),
cpv(57.95,1.45),
cpv(52.25,-5.19),
};
struct cpVect initShurikenShape_Verts9[4] =
{
cpv(45.16,-26.79),
cpv(45.77,-35.34),
cpv(19.62,-54.33),
cpv(11.91,-51.14),
};
struct cpVect initShurikenShape_Verts10[4] =
{
cpv(-12.02,-51.11),
cpv(-19.64,-54.26),
cpv(-45.77,-35.03),
cpv(-45.18,-26.75),
};
struct cpVect initShurikenShape_Verts11[10] =
{
cpv(-40.06,33.94),
cpv(-20.63,48.29),
cpv(20.75,48.1),
cpv(39.98,34.04),
cpv(52.25,-5.19),
cpv(45.16,-26.79),
cpv(11.91,-51.14),
cpv(-12.02,-51.11),
cpv(-45.18,-26.75),
cpv(-52.23,-5.35),
};
for(int i=0;i<5;i++)
ShurikenShape_Verts1[i] = initShurikenShape_Verts1[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts2[i] = initShurikenShape_Verts2[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts3[i] = initShurikenShape_Verts3[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts4[i] = initShurikenShape_Verts4[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts5[i] = initShurikenShape_Verts5[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts6[i] = initShurikenShape_Verts6[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts7[i] = initShurikenShape_Verts7[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts8[i] = initShurikenShape_Verts8[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts9[i] = initShurikenShape_Verts9[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts10[i] = initShurikenShape_Verts10[i];
for(int i=0;i<10;i++)
ShurikenShape_Verts11[i] = initShurikenShape_Verts11[i];
for(int i=0;i<35;i++)
ShurikenBody_Verts[i] = initShurikenBody_Verts[i];
}
I am using Visual Studio 2010 with Marmalade SDK and I am writing in C++.
Thanks for any help,
Anton
Ok, so if we assume that ShurikenShape_Verts1 is either a regular C style array or a C++ style std::array and has the type cpVect, and cpVect is a POD struct:
for(int i=0;i<5;i++)
ShurikenShape_Verts1[i] = initShurikenShape_Verts1[i];
can be copied as:
memcpy(ShurikenShape_Verts1, initShurikenShape_Verts1,
sizeof(initShurikenShape_Verts1));
However, I have made some assumptions here, since you haven't posted enough code. I'd hate to start a "can post this, can you post that" type thread, asking for a large number of other bits of your code, but it also means that I may not have answered the question correctly, since I don't know for sure that your cpVect is indeed a POD struct, for example.
(I'd submit a comment but I don't have enough of a stackoverflow "reputation" to do so:-()
I would seriously stand back and look at why you are trying to copy this stuff to start with. Copying lots of stuff is comparatively slow. Far better to use a pointer to the existing array or a reference, which depends on your style.
If by "cpVect is just 2 floats made into a vector" you mean vector, then don't use memcpy or whatever. This is just going to give you heap issues later. Remember that these work by allocating behind the scenes. If you use memcpy you are going to get two objects pointing to the same content, and when the first goes out of scope that content will be freed.
I am using libsvm version 3.16. I have done some training in Matlab, and created a model. Now I would like to save this model to disk and load this model in my C++ program. So far I have found the following alternatives:
This answer explains how to save a model from C++, which is based on this website. Not exactly what I need, but could be adapted. (This requires development time).
I could find the best training parameters (kernel,C) in Matlab and re-train everything in C++. (Will require doing the training in C++ each time I change a parameter. It's not scalable).
Thus, both of these options are not satisfactory,
Does anyone have an idea?
My solution was to retrain in C++ because I couldn't find a nice way to directly save the model. Here's my code. You'll need to adapt it and clean it up a bit. The biggest change you'll have to make it not hard coding the svm_parameter values like I did. You'll also have to replace FilePath with std::string. I'm copying, pasting and making small edits here in SO so the formatting won't e perfect:
Used like this:
auto targetsPath = FilePath("targets.txt");
auto observationsPath = FilePath("observations.txt");
auto targetsMat = MatlabMatrixFileReader::Read(targetsPath, ',');
auto observationsMat = MatlabMatrixFileReader::Read(observationsPath, ',');
auto v = MiscVector::ConvertVecOfVecToVec(targetsMat);
auto model = SupportVectorRegressionModel{ observationsMat, v };
std::vector<double> observation{ { // 32 feature observation
0.883575729725847,0.919446119013878,0.95359403450317,
0.968233630936732,0.91891307107125,0.887897763183844,
0.937588566544751,0.920582702918882,0.888864454119387,
0.890066735260163,0.87911085669864,0.903745573664995,
0.861069296586979,0.838606194934074,0.856376230548304,
0.863011311537075,0.807688936997926,0.740434984165146,
0.738498042748759,0.736410940165691,0.697228384912424,
0.608527698289016,0.632994967880269,0.66935784966765,
0.647761430696238,0.745961037635717,0.560761134660957,
0.545498063585615,0.590854855113663,0.486827902942118,
0.187128866890822,- 0.0746523069562551
} };
double prediction = model.Predict(observation);
miscvector.h
static vector<double> ConvertVecOfVecToVec(const vector<vector<double>> &mat)
{
vector<double> targetsVec;
targetsVec.reserve(mat.size());
for (size_t i = 0; i < mat.size(); i++)
{
targetsVec.push_back(mat[i][0]);
}
return targetsVec;
}
libsvmtargetobjectconvertor.h
#pragma once
#include "machinelearning.h"
struct svm_node;
class LibSvmTargetObservationConvertor
{
public:
svm_node ** LibSvmTargetObservationConvertor::ConvertObservations(const vector<MlObservation> &observations, size_t numFeatures) const
{
svm_node **svmObservations = (svm_node **)malloc(sizeof(svm_node *) * observations.size());
for (size_t rowI = 0; rowI < observations.size(); rowI++)
{
svm_node *row = (svm_node *)malloc(sizeof(svm_node) * numFeatures);
for (size_t colI = 0; colI < numFeatures; colI++)
{
row[colI].index = colI;
row[colI].value = observations[rowI][colI];
}
row[numFeatures].index = -1; // apparently needed
svmObservations[rowI] = row;
}
return svmObservations;
}
svm_node* LibSvmTargetObservationConvertor::ConvertMatToSvmNode(const MlObservation &observation) const
{
size_t numFeatures = observation.size();
svm_node *obsNode = (svm_node *)malloc(sizeof(svm_node) * numFeatures);
for (size_t rowI = 0; rowI < numFeatures; rowI++)
{
obsNode[rowI].index = rowI;
obsNode[rowI].value = observation[rowI];
}
obsNode[numFeatures].index = -1; // apparently needed
return obsNode;
}
};
machinelearning.h
#pragma once
#include <vector>
using std::vector;
using MlObservation = vector<double>;
using MlTarget = double;
//machinelearningmodel.h
#pragma once
#include <vector>
#include "machinelearning.h"
class MachineLearningModel
{
public:
virtual ~MachineLearningModel() {}
virtual double Predict(const MlObservation &observation) const = 0;
};
matlabmatrixfilereader.h
#pragma once
#include <vector>
using std::vector;
class FilePath;
// Matrix created with command:
// dlmwrite('my_matrix.txt', somematrix, 'delimiter', ',', 'precision', 15);
// In these files, each row is a matrix row. Commas separate elements on a row.
// There is no space at the end of a row. There is a blank line at the bottom of the file.
// File format:
// 0.4,0.7,0.8
// 0.9,0.3,0.5
// etc.
static class MatlabMatrixFileReader
{
public:
static vector<vector<double>> Read(const FilePath &asciiFilePath, char delimiter)
{
vector<vector<double>> values;
vector<double> valueline;
std::ifstream fin(asciiFilePath.Path());
string item, line;
while (getline(fin, line))
{
std::istringstream in(line);
while (getline(in, item, delimiter))
{
valueline.push_back(atof(item.c_str()));
}
values.push_back(valueline);
valueline.clear();
}
fin.close();
return values;
}
};
supportvectorregressionmodel.h
#pragma once
#include <vector>
using std::vector;
#include "machinelearningmodel.h"
#include "svm.h" // libsvm
class FilePath;
class SupportVectorRegressionModel : public MachineLearningModel
{
public:
SupportVectorRegressionModel::~SupportVectorRegressionModel()
{
svm_free_model_content(model_);
svm_destroy_param(¶m_);
svm_free_and_destroy_model(&model_);
}
SupportVectorRegressionModel::SupportVectorRegressionModel(const vector<MlObservation>& observations, const vector<MlTarget>& targets)
{
// assumes all observations have same number of features
size_t numFeatures = observations[0].size();
//setup targets
//auto v = ConvertVecOfVecToVec(targetsMat);
double *targetsPtr = const_cast<double *>(&targets[0]); // why aren't the targets const?
LibSvmTargetObservationConvertor conv;
svm_node **observationsPtr = conv.ConvertObservations(observations, numFeatures);
// setup observations
//svm_node **observations = BuildObservations(observationsMat, numFeatures);
// setup problem
svm_problem problem;
problem.l = targets.size();
problem.y = targetsPtr;
problem.x = observationsPtr;
// specific to out training sets
// TODO: This is hard coded.
// Bust out these values for use in constructor
param_.C = 0.4; // cost
param_.svm_type = 4; // SVR
param_.kernel_type = 2; // radial
param_.nu = 0.6; // SVR nu
// These values are the defaults used in the Matlab version
// as found in svm_model_matlab.c
param_.gamma = 1.0 / (double)numFeatures;
param_.coef0 = 0;
param_.cache_size = 100; // in MB
param_.shrinking = 1;
param_.probability = 0;
param_.degree = 3;
param_.eps = 1e-3;
param_.p = 0.1;
param_.shrinking = 1;
param_.probability = 0;
param_.nr_weight = 0;
param_.weight_label = NULL;
param_.weight = NULL;
// suppress command line output
svm_set_print_string_function([](auto c) {});
model_ = svm_train(&problem, ¶m_);
}
double SupportVectorRegressionModel::Predict(const vector<double>& observation) const
{
LibSvmTargetObservationConvertor conv;
svm_node *obsNode = conv.ConvertMatToSvmNode(observation);
double prediction = svm_predict(model_, obsNode);
return prediction;
}
SupportVectorRegressionModel::SupportVectorRegressionModel(const FilePath & modelFile)
{
model_ = svm_load_model(modelFile.Path().c_str());
}
private:
svm_model *model_;
svm_parameter param_;
};
Option 1 is actually pretty reasonable. If you save the model in libsvm's C format through matlab, then it is straightforward to work with the model in C/C++ using functions provided by libsvm. Trying to work with matlab-formatted data in C++ will probably be much more difficult.
The main function in "svm-predict.c" (located in the root directory of the libsvm package) probably has most of what you need:
if((model=svm_load_model(argv[i+1]))==0)
{
fprintf(stderr,"can't open model file %s\n",argv[i+1]);
exit(1);
}
To predict a label for example x using the model, you can run
int predict_label = svm_predict(model,x);
The trickiest part of this will be to transfer your data into the libsvm format (unless your data is in the libsvm text file format, in which case you can just use the predict function in "svm-predict.c").
A libsvm vector, x, is an array of struct svm_node that represents a sparse array of data. Each svm_node has an index and a value, and the vector must be terminated by an index that is set to -1. For instance, to encode the vector [0,1,0,5], you could do the following:
struct svm_node *x = (struct svm_node *) malloc(3*sizeof(struct svm_node));
x[0].index=2; //NOTE: libsvm indices start at 1
x[0].value=1.0;
x[1].index=4;
x[1].value=5.0;
x[2].index=-1;
For SVM types other than the classifier (C_SVC), look at the predict function in "svm-predict.c".