Cuda Thrust - max vec3 - cuda

When i want to perform a reduction on an array of float i usually do the following :
float res = *thrust::max_element(thrust::device,
thrust::device_ptr<float>(dDensities),
thrust::device_ptr<float>(dDensities+numParticles)
);
However what i would like to do now is pretty much the same thing on a vec3 (the glm library type) array :
float res = *thrust::max_element(thrust::device,
thrust::device_ptr<glm::vec3>(dDensities),
thrust::device_ptr<glm::vec3>(dDensities+numParticles)
);
As you can see, this has no sense because the '<' operator is not defined on. But i would like to get the maximum vec3 based on his length :
len = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
Is that possible ?

Yes, its possible. You may want to read the thrust quickstart guide if you're not already familiar with it.
If you review the thrust extrema documentation, you'll note that thrust::max_element comes in several different varieties (as do most thrust algorithms). One of these accepts a binary comparison functor. We can define a comparison functor which will do what you want.
Here's a trivial worked example:
$ cat t134.cu
#include <thrust/extrema.h>
#include <thrust/device_ptr.h>
#include <glm/glm.hpp>
#include <iostream>
struct comp
{
template <typename T>
__host__ __device__
bool operator()(T &t1, T &t2){
return ((t1.x*t1.x+t1.y*t1.y+t1.z*t1.z) < (t2.x*t2.x+t2.y*t2.y+t2.z*t2.z));
}
};
int main(){
int numParticles = 3;
glm::vec3 d[numParticles];
d[0].x = 0; d[0].y = 0; d[0].z = 0;
d[1].x = 2; d[1].y = 2; d[1].z = 2;
d[2].x = 1; d[2].y = 1; d[2].z = 1;
glm::vec3 *dDensities;
cudaMalloc(&dDensities, numParticles*sizeof(glm::vec3));
cudaMemcpy(dDensities, d, numParticles*sizeof(glm::vec3), cudaMemcpyHostToDevice);
glm::vec3 res = *thrust::max_element(thrust::device,
thrust::device_ptr<glm::vec3>(dDensities),
thrust::device_ptr<glm::vec3>(dDensities+numParticles),
comp()
);
std::cout << "max element x: " << res.x << " y: " << res.y << " z: " << res.z << std::endl;
}
$ nvcc -arch=sm_61 -o t134 t134.cu
$ ./t134
max element x: 2 y: 2 z: 2
$

Related

How to combine thrust comparisons using placeholders?

I have a device_vector of float values A of size N. I also have a float value V for comparison. Depending on an input value I need to extract indices of A for which the values are > OR < OR == V.
I use the following code but it seems cumbersome. Is there a more concise way to do it?
void detect_indices_lesser_greater_equal_to_value(thrust::device_vector<float> S, float value,
int criterion, thrust::device_vector<int>& indices)
{
int N=S.size();
int size=N;
if(criterion==0) // criterion =0 => equal
{
thrust::device_vector<int>::iterator end = thrust::copy_if(thrust::device,thrust::make_counting_iterator(0),
thrust::make_counting_iterator(N),
S.begin(),
indices.begin(),
thrust::placeholders::_1 == value);
size = end-indices.begin();
}
if(criterion==1) // criterion =1 => less
{
thrust::device_vector<int>::iterator end = thrust::copy_if(thrust::device,thrust::make_counting_iterator(0),
thrust::make_counting_iterator(N),
S.begin(),
indices.begin(),
thrust::placeholders::_1 < value);
size = end-indices.begin();
}
if(criterion==2) // criterion =2 => greater
{
thrust::device_vector<int>::iterator end = thrust::copy_if(thrust::device,thrust::make_counting_iterator(0),
thrust::make_counting_iterator(N),
S.begin(),
indices.begin(),
thrust::placeholders::_1 > value);
size = end-indices.begin();
}
indices.resize(size);
}
This can be done with two thrust::partition operations. Partitioning is pretty simple: everything that results in a true predicate is moved to the left side of the input vector. Everything else is moved to the right. Here's a simple example:
$ cat t22.cu
#include <thrust/partition.h>
#include <thrust/copy.h>
#include <thrust/device_vector.h>
typedef float mt;
using namespace thrust::placeholders;
int main(){
const mt pval = 4;
mt data[] = {1,3,7,4,5,2,4,3,9};
const int ds = sizeof(data)/sizeof(data[0]);
thrust::device_vector<mt> d(data, data+ds);
auto end1 = thrust::partition(d.begin(), d.end(), _1<pval);
auto end2 = thrust::partition(end1, d.end(), _1==pval);
std::cout << "less than pval:" << std::endl;
thrust::copy(d.begin(), end1, std::ostream_iterator<mt>(std::cout,","));
std::cout << std::endl << "equal to pval:" << std::endl;
thrust::copy(end1, end2, std::ostream_iterator<mt>(std::cout,","));
std::cout << std::endl << "greater than pval:" << std::endl;
thrust::copy(end2, d.end(), std::ostream_iterator<mt>(std::cout,","));
std::cout << std::endl;
}
$ nvcc -o t22 t22.cu
$ ./t22
less than pval:
1,3,2,3,
equal to pval:
4,4,
greater than pval:
7,5,9,
$
If you require that the ordering in the 3 resultant sub-vectors be the same as the original input ordering, you could use the thrust::stable_partition variant.
(Note that in your question you refer to float quantities, but your example code uses <int> iterators. However the above code can work with either by modifying the typedef).

LLVM MCJIT / SEH Exception handling

Lately, I've been attempting to get SEH exception handling to work in LLVM (3.8.1) together with MCJIT. So far without any luck.
From what I understand from the website ( http://llvm.org/docs/ExceptionHandling.html ), this is pretty much how this should be implemented. Compiling a minimal piece of code with clang gives pretty much the same LLVM IR code. However, when I try it, the program crashes with a nasty Stack cookie instrumentation code detected a stack-based buffer overrun..
To illustrate what I've been attempting to do, I've created a minimum test case (I apologise for the amount of code...):
#include <string>
#include <iostream>
#include <exception>
#pragma warning(push)
#pragma warning(disable: 4267)
#pragma warning(disable: 4244)
#pragma warning(disable: 4800)
#pragma warning(disable: 4996)
#pragma warning(disable: 4141)
#pragma warning(disable: 4146)
#pragma warning(disable: 4624)
#pragma warning(disable: 4291)
#define DONT_GET_PLUGIN_LOADER_OPTION
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Triple.h"
#include "llvm/PassRegistry.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#pragma warning(pop)
static void test()
{
// You can use this to see that function calls work fine.
// std::cout << "Foo!" << std::endl;
throw std::exception("Something we should try to catch.");
}
int main()
{
// Initialize LLVM
std::cout << "Initializing LLVM." << std::endl;
llvm::InitializeNativeTarget();
llvm::InitializeAllTargetMCs();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetAsmParser();
llvm::PassRegistry *Registry = llvm::PassRegistry::getPassRegistry();
llvm::initializeCore(*Registry);
llvm::initializeScalarOpts(*Registry);
llvm::initializeObjCARCOpts(*Registry);
llvm::initializeVectorization(*Registry);
llvm::initializeIPO(*Registry);
llvm::initializeAnalysis(*Registry);
llvm::initializeTransformUtils(*Registry);
llvm::initializeInstCombine(*Registry);
llvm::initializeInstrumentation(*Registry);
llvm::initializeTarget(*Registry);
// For codegen passes, only passes that do IR to IR transformation are
// supported.
llvm::initializeCodeGenPreparePass(*Registry);
llvm::initializeAtomicExpandPass(*Registry);
llvm::initializeRewriteSymbolsPass(*Registry);
llvm::initializeWinEHPreparePass(*Registry);
llvm::initializeDwarfEHPreparePass(*Registry);
llvm::initializeSjLjEHPreparePass(*Registry);
llvm::StringRef MCPU = llvm::sys::getHostCPUName();
std::string MTrip = llvm::sys::getProcessTriple();
static llvm::StringMap<bool, llvm::MallocAllocator> features;
llvm::sys::getHostCPUFeatures(features);
// Initialize module & context:
auto context = std::unique_ptr<llvm::LLVMContext>(new llvm::LLVMContext());
auto module = std::unique_ptr<llvm::Module>(new llvm::Module("native", *context));
// Create 'main' method:
llvm::Type* returnType = llvm::Type::getInt32Ty(*context);
std::vector<llvm::Type*> arguments;
// MCJIT only supports main(int, char**)
arguments.push_back(llvm::Type::getInt32Ty(*context));
arguments.push_back(llvm::Type::getInt8PtrTy(*context)->getPointerTo());
llvm::Function *fcn = llvm::cast<llvm::Function>(module->getOrInsertFunction("main", llvm::FunctionType::get(returnType, arguments, false)));
// Generate exception handler info for main:
llvm::AttrBuilder argBuilder;
argBuilder.addAttribute(llvm::Attribute::UWTable);
argBuilder.addAttribute("stack-protector-buffer-size", "8");
fcn->addAttributes(llvm::AttributeSet::FunctionIndex, llvm::AttributeSet::get(*context, llvm::AttributeSet::FunctionIndex, argBuilder));
// Exception handling requires a personality function. We want to use the SEH personality handler
llvm::Function *personalityHandler = llvm::cast<llvm::Function>(module->getOrInsertFunction("__CxxFrameHandler3", llvm::FunctionType::get(llvm::Type::getInt32Ty(*context), true)));
auto personalityPtr = llvm::ConstantExpr::getBitCast(personalityHandler, llvm::Type::getInt8PtrTy(*context));
fcn->setPersonalityFn(personalityPtr);
// Create some code. Basically we want to invoke our 'test' method
auto block = llvm::BasicBlock::Create(*context, "code", fcn);
llvm::IRBuilder<> builder(block);
// all other cases might throw an exception
auto continueBlock = llvm::BasicBlock::Create(*context, "invoke.cont", fcn);
auto catchDispatch = llvm::BasicBlock::Create(*context, "catch.dispatch", fcn);
// Register 'test' as an external function:
const void* testFunctionPtr = &test;
auto testFunctionType = llvm::FunctionType::get(builder.getVoidTy(), false);
auto testFunction = llvm::Function::Create(testFunctionType, llvm::Function::ExternalLinkage, "test", module.get());
// %call = invoke i32 #"test"() to label %invoke.cont unwind label %catch.dispatch
auto call = builder.CreateInvoke(testFunction, continueBlock, catchDispatch);
// return [ 0 from ok, 1 from catch handler ]
builder.SetInsertPoint(continueBlock);
auto phi = builder.CreatePHI(builder.getInt32Ty(), 2, "result");
phi->addIncoming(builder.getInt32(0), block);
builder.CreateRet(phi);
// Create exception handler:
// Create default catch block. Basically handles the exception and returns '1'.
builder.SetInsertPoint(catchDispatch);
auto parentPad = llvm::ConstantTokenNone::get(*context);
// %0 = catchswitch within none [label %catch] unwind to caller
auto catchSwitch = builder.CreateCatchSwitch(parentPad, nullptr, 1);
auto catchBlock = llvm::BasicBlock::Create(*context, "catch", fcn);
builder.SetInsertPoint(catchBlock);
catchSwitch->addHandler(catchBlock);
// MSVC code:
// %1 = catchpad within %0 [i8* null, i32 64, i8* null] == "catch all"
llvm::Value *nullPtr = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(*context));
auto catchPad = builder.CreateCatchPad(catchSwitch, { nullPtr, builder.getInt32(0x40), nullPtr });
// catchret from %1 to label %return
auto const1 = builder.getInt32(1);
builder.CreateCatchRet(catchPad, continueBlock);
// set 1 for the catch handler
phi->addIncoming(builder.getInt32(1), catchBlock);
// *DONE* building the code.
// Dump the LLVM IR:
module->dump();
// Let's JIT the code:
std::string error;
auto trip = llvm::Triple::normalize(MTrip);
llvm::Triple triple(trip);
const llvm::Target *target = llvm::TargetRegistry::lookupTarget("x86-64", triple, error);
if (!target)
{
throw error.c_str();
}
llvm::TargetOptions Options;
std::unique_ptr<llvm::TargetMachine> targetMachine(
target->createTargetMachine(trip, MCPU, "", Options, llvm::Reloc::Default, llvm::CodeModel::Default, llvm::CodeGenOpt::Aggressive));
if (!targetMachine.get())
{
throw "Could not allocate target machine!";
}
// Create the target machine; set the module data layout to the correct values.
auto DL = targetMachine->createDataLayout();
module->setDataLayout(DL);
module->setTargetTriple(trip);
// Pass manager builder:
llvm::PassManagerBuilder pmbuilder;
pmbuilder.OptLevel = 3;
pmbuilder.BBVectorize = false;
pmbuilder.SLPVectorize = true;
pmbuilder.LoopVectorize = true;
pmbuilder.Inliner = llvm::createFunctionInliningPass(3, 2);
llvm::TargetLibraryInfoImpl *TLI = new llvm::TargetLibraryInfoImpl(triple);
pmbuilder.LibraryInfo = TLI;
// Generate pass managers:
// 1. Function pass manager:
llvm::legacy::FunctionPassManager FPM(module.get());
pmbuilder.populateFunctionPassManager(FPM);
// 2. Module pass manager:
llvm::legacy::PassManager PM;
PM.add(llvm::createTargetTransformInfoWrapperPass(targetMachine->getTargetIRAnalysis()));
pmbuilder.populateModulePassManager(PM);
// 3. Execute passes:
// - Per-function passes:
FPM.doInitialization();
for (llvm::Module::iterator I = module->begin(), E = module->end(); I != E; ++I)
{
if (!I->isDeclaration())
{
FPM.run(*I);
}
}
FPM.doFinalization();
// - Per-module passes:
PM.run(*module);
// All done, *RUN*.
llvm::EngineBuilder engineBuilder(std::move(module));
engineBuilder.setEngineKind(llvm::EngineKind::JIT);
engineBuilder.setMCPU(MCPU);
engineBuilder.setMArch("x86-64");
engineBuilder.setUseOrcMCJITReplacement(false);
engineBuilder.setOptLevel(llvm::CodeGenOpt::None);
llvm::ExecutionEngine* engine = engineBuilder.create();
// Register global 'test' function:
engine->addGlobalMapping(testFunction, const_cast<void*>(testFunctionPtr)); // Yuck...
// Finalize
engine->finalizeObject();
// Invoke:
std::vector<llvm::GenericValue> args(2);
args[0].IntVal = llvm::APInt(32, static_cast<uint64_t>(0), true);
args[1].PointerVal = nullptr;
llvm::GenericValue gv = engine->runFunction(fcn, args);
auto result = int(gv.IntVal.getSExtValue());
std::cout << "Result after execution: " << result << std::endl;
std::string s;
std::getline(std::cin, s);
}
This produces the following IR code:
; ModuleID = 'native'
; Function Attrs: uwtable
define i32 #main(i32, i8**) #0 personality i8* bitcast (i32 (...)* #__CxxFrameHandler3 to i8*) {
code:
invoke void #test()
to label %invoke.cont unwind label %catch.dispatch
invoke.cont: ; preds = %catch, %code
%result = phi i32 [ 0, %code ], [ 1, %catch ]
ret i32 %result
catch.dispatch: ; preds = %code
%2 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
%3 = catchpad within %2 [i8* null, i32 64, i8* null]
catchret from %3 to label %invoke.cont
}
declare i32 #__CxxFrameHandler3(...)
declare void #test()
attributes #0 = { uwtable "stack-protector-buffer-size"="8" }
Q: What am I missing, why doesn't this work and how to fix it?
After posting this issue on the llvm developer list, I got a friendly reply explaining how this issue is related to a known bug: https://llvm.org/bugs/show_bug.cgi?id=24233 .
Basically what happens is that LLVM doesn't implement the code that Windows (more specifically: SEH and debugging) requires for handling stack frames. I'm by no means an expert on this subject, but until this is implemented, SEH won't know what to do, which means C++ exception basically won't work.
An obvious workaround is of course to pass the object as a pointer during the function call and perform an if-then-else. That way, exceptions are avoided. However, this is pretty nasty and will probably give a serious performance penalty. Also, this makes the flow in the compiler as well as the generated program much more complicated. In other words: let's just say I'd rather not.
I'll leave the question open; if someone happens to find a hack or figure out a workaround, I'll gladly accept it.

How can a Eigen matrix be written to file in CSV format?

Suppose I have a double Eigen matrix and I want to write it to a csv file. I find the way of writing into a file in raw format but I need commas between entries. Here is the code I foudn for simple writing.
void writeToCSVfile(string name, MatrixXd matrix)
{
ofstream file(name.c_str());
if (file.is_open())
{
file << matrix << '\n';
//file << "m" << '\n' << colm(matrix) << '\n';
}
}
Using format is a bit more concise:
// define the format you want, you only need one instance of this...
const static IOFormat CSVFormat(StreamPrecision, DontAlignCols, ", ", "\n");
...
void writeToCSVfile(string name, MatrixXd matrix)
{
ofstream file(name.c_str());
file << matrix.format(CSVFormat);
}
Here is what I came up;
void writeToCSVfile(string name, MatrixXd matrix)
{
ofstream file(name.c_str());
for(int i = 0; i < matrix.rows(); i++){
for(int j = 0; j < matrix.cols(); j++){
string str = lexical_cast<std::string>(matrix(i,j));
if(j+1 == matrix.cols()){
file<<str;
}else{
file<<str<<',';
}
}
file<<'\n';
}
}
This is the MWE to the solution given by Partha Lal.
// eigen2csv.cpp
#include <Eigen/Dense>
#include <iostream>
#include <fstream>
// define the format you want, you only need one instance of this...
// see https://eigen.tuxfamily.org/dox/structEigen_1_1IOFormat.html
const static Eigen::IOFormat CSVFormat(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", "\n");
// writing functions taking Eigen types as parameters,
// see https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
template <typename Derived>
void writeToCSVfile(std::string name, const Eigen::MatrixBase<Derived>& matrix)
{
std::ofstream file(name.c_str());
file << matrix.format(CSVFormat);
// file.close() is not necessary,
// desctructur closes file, see https://en.cppreference.com/w/cpp/io/basic_ofstream
}
int main()
{
Eigen::MatrixXd vals = Eigen::MatrixXd::Random(10, 3);
writeToCSVfile("test.csv", vals);
}
Compile with g++ eigen2csv.cpp -I<EigenIncludePath>.

odeint streaming observer and related questions

I have a system of 4 coupled equations to solve and a parameter Gamma[i] to iterate over. Since I am quite new to C++, my code is a very rudimentary. If it looks sophisticated and elegant in certain parts, it is only because I have adapted code from the author of odeint. :)
This question is related to (http://stackoverflow.com/questions/12060111/using-odeint-function-definition/12066958#comment16253600_12066958) but not exactly the same. Please do not delete this. :(
Questions have been inserted between the lines of code.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <boost/numeric/odeint.hpp>
#include <cmath>
#include <vector>
#include <fstream>
#include <iomanip>
using namespace std;
using namespace boost::numeric::odeint;
class NLI_class {
private:
double gamma;
public:
NLI_class (double r) : gamma(r) {}
void operator()( vector<double> &u , vector<double> &du , double z ) {
du[0] = u[0]*u[1]*cos(u[3]); //u1
du[1] = -u[0]*u[0]*cos(u[3]); //u2
du[2] = gamma * (2/(u[0]*u[0]) - 1/(u[1]*u[1])); //theta
du[3] = gamma * (1.0/(u[0]*u[0])); //phi1
du[4] = gamma * (1.0/(u[1]*u[1])); //phi2;
}
};
Question #1:
In my original program, I had something like this to pipe the output to a csv file:
inline void save(vector<double>& v, string filename)
{
ofstream output(filename);
for(int i=0;i<v.size();++i){
output << setprecision(64) << v[i] << endl;
}
}
How do I adapt streaming_observer to do what my save() does? Basically, I want to generate .csv files for each iteration i. At this point, I am doing it the ugly way, i.e compiling everything, opening a windows command prompt and then piping the exe output to a text file. This generates one big file with all iterations thrown in there.
This becomes very painful to analyze for a large number of iterations.
struct streaming_observer {
std::ostream &m_out;
streaming_observer( std::ostream &out ) : m_out( out ) {}
void operator()( const vector<double> &x , double t ) const
{
m_out << t;
for( size_t i=0 ; i < x.size() ; ++i )
m_out << "\t" << x[i];
m_out << "\n";
}
};
int main(){
vector<double> x( 5 );
vector<double> Gamma;
vector<double>delta;
const double pi=acos(-1.0);
short delta_n=5;
const double delta_step=(2*pi)/delta_n;
const double dz = 0.01;
const double zeta = 3.0;
const double theta_initial=0.0;
const double u20=tanh(zeta);
const double u10=sqrt(1.0-(u20*u20));
double d=0.0;
double G=0.0;
for(int i=0;i<=delta_n;i++){
//When i=0, the d=0.0 and G=0.0 are pushed into the vector.
delta.push_back(d);
Gamma.push_back(G);
// Compute delta and Gamma
d=d+delta_step;
G=-u10*u10*u20*sin(theta_initial+d);
}
save(delta,"delta.csv");
save(Gamma,"Gamma.csv");
Question#2:
The results I get here do not agree with what I get with what I get using a simple explicit Euler method. Hence, I would like to see the RK4 coefficients (preferably dump them to a file) or the intermediate steps. How can I get this information?
//Numeric Integration
for (unsigned i = 0; i < Gamma.size(); ++i) {
x[0] = u10;
x[1] = u20;
x[2] = 0.0;
x[3] = 0.0;
x[4] = 0.0;
NLI_class nli_obj(Gamma[i]);
integrate_const( runge_kutta4< vector<double > >(), nli_obj, x , 0.0 , 3.0 , dz,streaming_observer( std::cout ) );
}
}
Thank you for all those who helped!
Edit:
Is there some way to get a running error estimate? Note that u[0]*u[0]+u[1]*u[1]=1 at all times.
Question #1 :
I do not understand exactly what kind of output you need. But if you want to write the result after each iteration you can implement an output observer like this:
struct output_observer
{
string filename_;
size_t count_;
output_observer( const string &filename ) : filename_( filename ) , count_( 0 ) { }
void operator()( const state_type &x , time_type dt )
{
char fn[512] = "";
sprintf( fn , "%s_%04lu.csv" , filename_.c_str() , count_ );
ofstream fout( fn );
for( size_t i=0 ; i<x.size() ; ++i ) fout << x[i] << "\n";
++count_;
}
};
You can apply this observer simply by
integrate_const( runge_kutta4< vector<double > >() , nli_obj , x ,
0.0 , 3.0 , dz , output_observer( "filename" ) );
Is this the desired functionality?
Question #2 :
It is not possible to see the intermediate e steps of runge_kutta4. The coefficients are the standard ones for the classical Runge-Kutta method: http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
Question #3 :
odeint has several error steppers, which estimate the error made during one step. You can use for example the Runge_Kutta Cash Karp algorithm;
runge_kutta_cash_karp54< state_type > rk;
state_type xerr;
rk.do_step( nli_obj , x , t , xerr );
which makes ONE step and estimates the error and writes the error result in xerr.

Getting html attributes from DOM trees ( libxml )

I'm using this program to display a list of all html tags in a given file:
#include <cstdio>
#include <libxml/HTMLparser.h>
#include <libxml/tree.h>
#include <iostream>
#include <cstring>
using namespace std;
static void
print_element_names(htmlNodePtr a_node)
{
htmlNodePtr cur_node = NULL;
for (cur_node = a_node; cur_node!=NULL; cur_node = cur_node->next) {
printf("node type: Element, name: %s\n", cur_node->name);
print_element_names(cur_node->children);
}
}
int main(int argc, char **argv) {
htmlDocPtr doc;
htmlNodePtr root_node;
doc = htmlReadFile(argv[1], NULL, 0);
root_node = xmlDocGetRootElement(doc);
print_element_names(root_node);
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
How do I get it to display the attributes as well (eg. href="something" for <a>)?
It seems there is no such field:
zajec#linux-lbnn:~/Prog_zesp> g++ `xml2-config --cflags --libs` -o tester tester.cpp
tester.cpp: In function ‘void print_element_names(xmlNode*)’:
tester.cpp:17: error: ‘struct _xmlNode’ has no member named ‘attributes’
=== EDIT ===
If I do something like this:
if (strcmp((char *)cur_node->name, "a")==0) {
cout << cur_node->properties->name << endl;
I get the name of the attribute - "href"
If I go one step further:
if (strcmp((char *)cur_node->name, "a")==0) {
cout << cur_node->properties->children->name << endl;
I get "text", but not the actual link.