Format the output of qDebug for QMaps - c++

i am currently in the process of maintaining a legacy app. This has quite a few structures like:
QMap<QString, QMap<QString, QMap<QString, QMap<QString, QVariant> > > > Dep;
As interfaces are hardly used and I only need to make minor adjustments, I would like to keep the structure as it is, although some refactoring might be needed anyway.
But to be able to understand what is going on, currently I just put some qDebug() << Dep; in there, and try to understand the output.
Problem is that it has no formatting at all. Does anyone know of a little script to create a better understandable display format? Or maybe of some patches to Qt?
To give you an example for my suffering:
QMap(("Test enable|test enable block", QMap(("disabled", QMap(("testblock1", QMap(("enableblock", QVariant(QString, "false") ) ) ) ) ) ( "enabled" , QMap(("testblock1", QMap(("enableblock", QVariant(QString, "true") ) ) ) ) ) ) ) ( "Test enable|test enable key" , QMap(("disabled", QMap(("testblock1|testkey", QMap(("enablekey", QVariant(QString, "false") ) ) ) ) ) ( "enabled" , QMap(("testblock1|testkey", QMap(("enablekey", QVariant(QString, "true") ) ) ) ) ) ) ) ( "testinsertitems|Insert item" , QMap(("test1", QMap(("testinsertitems|testinsert", QMap(("insertitems", QVariant(QVariantMap, QMap(("test1", QVariant(QString, "test1") ) ) ) ) ) ) ( "testinsertitems|testremove" , QMap(("removeitems", QVariant(QVariantMap, QMap(("test1", QVariant(QString, "test1") ) ) ) ) ) ) ) ) ( "test2" , QMap(("testinsertitems|testinsert", QMap(("insertitems", QVariant(QVariantMap, QMap(("test2", QVariant(QString, "test2") ) ) ) ) ) ) ( "testinsertitems|testremove" , QMap(("removeitems", QVariant(QVariantMap, QMap(("test2", QVariant(QString, "test2") ) ) ) ) ) ) ) ) ) ) ( "testsetminmax|test setmin" , QMap(("2", QMap(("testsetminmax|testkey1", QMap(("setmin", QVariant(int, 2) ) ) ) ( "testsetminmax|testkey2" , QMap(("setmax", QVariant(int, 2) ) ) ) ) ) ( "3" , QMap(("testsetminmax|testkey1", QMap(("setmin", QVariant(int, 3) ) ) ) ( "testsetminmax|testkey2" , QMap(("setmax", QVariant(int, 3) ) ) ) ) ) ) ) ( "testsetvalue|test set value" , QMap(("2", QMap(("testsetvalue|testkey1", QMap(("setvalue", QVariant(QString, "2") ) ) ) ( "testsetvalue|testkey2" , QMap(("setvalue", QVariant(QString, "2") ) ) ) ( "testsetvalue|testkey3" , QMap(("setvalue", QVariant(QString, "2") ) ) ) ) ) ( "3" , QMap(("testsetvalue|testkey1", QMap(("setvalue", QVariant(QString, "3") ) ) ) ( "testsetvalue|testkey2" , QMap(("setvalue", QVariant(QString, "3") ) ) ) ( "testsetvalue|testkey3" , QMap(("setvalue", QVariant(QString, "3") ) ) ) ) ) ) ) )
Thanks

This one is for n-dimensions and will use the standard qDebug output for known types:
template<class NonMap>
struct Print
{
static void print(const QString& tabs, const NonMap& value)
{
qDebug() << tabs << value;
}
};
template <class Key, class ValueType >
struct Print<class QMap<Key, ValueType> >
{
static void print(const QString& tabs, const QMap< Key, ValueType>& map )
{
const QString extraTab = tabs + "\t";
QMapIterator<Key, ValueType> iterator(map);
while(iterator.hasNext())
{
iterator.next();
qDebug() << tabs << iterator.key();
Print<ValueType>::print(extraTab, iterator.value());
}
}
};
template<class Type>
void printMe(const Type& type )
{
Print<Type>::print("", type);
};

A four dimensional structure is notoriously hard to visualize.
But how about some small loops?
typedef QMap<QString, QVariant> T1;
typedef QMap<QString, T1> T2;
typedef QMap<QString, T2> T3;
foreach( T3 i, dep ) {
cout << "******" << i.key() << "*******" << endl << endl;
foreach ( T2 j, i.value() ) {
cout << j.key() << ":" << endl;
foreach ( T3 k, j.value() ) {
cout << k.key() << "= ";
foreach ( QVariant l, k.value() ) {
cout << l.key() << ": " << l.value() << " ";
}
cout << endl;
}
}
}
Using namespace std, of course. Add in setw() as you like. Hope you get the idea.

Related

Common character count giving unexpected problems

I have a simple problem where you get two strings where you need to see how many characters are common.
For s1 = "aabcc" and s2 = "dacaa", the output should be
solution(s1, s2) = 3.
I've seen a lot of people solve these types of problems, but I don't want to copy and paste. I want to learn it my way with my solution and improve upon that. I think my solution makes sense but it obviously doesn't, because it doesn't work.
This is my solution:
#include <iostream>
using namespace std;
int main()
{
int counter {};
string s1 = "aabcc";
string s2 = "dacaa";
for (int i {}; i < s1.size(); ++i)
{
for (int j {}; j < s2.size(); ++j)
{
if (s1.at(i) == s2.at(j));
{
cout << "Found character " << s1.at(i) << " at index " << i << " and " << s2.at(j) << " at index " << j << endl;
counter++;
s2.erase(s2.begin()+j);
break;
}
}
cout << s2 << endl;
}
cout << counter << endl;
return 0;
}
This is the output I get (I did a lot of "cout" for debugging purposes.
Found character a at index 0 and d at index 0
acaa
Found character a at index 1 and a at index 0
caa
Found character b at index 2 and c at index 0
aa
Found character a at index 3 and a at index 0
Found character a at index 4 and a at index 0
5
Let's talk about the first iteration. What I don't understand is how s1.at(i) is equal to s2.at(j) at index 0? s1.at(0) is "a" and s2.at(0) is "d". Since when was a = d?
This problem is driving me crazy and I would appreciate if you could explain why my solution acts like this.
There is a typo
if (s1.at(i) == s2.at(j));
Remove the semicolon.
In general the approach is bad because it changes one of the source strings.
I can suggest the following solution by means of using an additional container.
#include <iostream>
#include <string>
#include <string_view>
#include <utility>
#include <map>
#include <iterator>
#include <algorithm>
#include <numeric>
size_t common_letters( std::string_view s1, std::string_view s2 )
{
std::map<char, std::pair<size_t, size_t>> m;
for (char c : s1)
{
if ( m.count( c ) == 0 && s2.find( c ) != std::string_view::npos )
{
m[c].first = std::count( std::begin( s1 ), std::end( s1 ), c );
m[c].second = std::count( std::begin( s2 ), std::end( s2 ), c );
}
}
return std::accumulate( std::begin( m ), std::end( m ), ( size_t )0,
[]( const auto &acc, const auto &item )
{
return acc + std::min( item.second.first, item.second.second );
} );
}
int main()
{
std::string s1 = "aabcc";
std::string s2 = "dacaa";
std::cout << "common_letters( s1, s2 ) = " << common_letters(s1, s2) << '\n';
const char *s3 = "aabcc";
const char *s4 = "dacaa";
std::cout << "common_letters( s3, s4 ) = " << common_letters( s3, s4 ) << '\n';
}
The program output is
common_letters( s1, s2 ) = 3
common_letters( s3, s4 ) = 3
The if statement within the range-based for loop can be rewritten the following way to make the function more efficient
for (char c : s1)
{
if ( auto pos = std::string_view::npos;
m.count( c ) == 0 && ( pos = s2.find( c ) ) != std::string_view::npos )
{
m[c].first = std::count( std::begin( s1 ), std::end( s1 ), c );
m[c].second = std::count( std::next( std::begin( s2 ), pos ), std::end( s2 ), c );
}
}
Or if the compiler supports the C++ 20 then
for ( size_t i = 0; char c : s1)
{
if ( auto pos = std::string_view::npos;
m.count( c ) == 0 && ( pos = s2.find( c ) ) != std::string_view::npos )
{
m[c].first = std::count( std::next( std::begin( s1 ), i ), std::end( s1 ), c );
m[c].second = std::count( std::next( std::begin( s2 ), pos ), std::end( s2 ), c );
}
i++;
}
Or instead of the range-based for loop there can be used an ordinary for loop with iterators. That is the function can look the following way
size_t common_letters( std::string_view s1, std::string_view s2 )
{
std::map<char, std::pair<size_t, size_t>> m;
for ( auto first = std::begin( s1 ), last = std::end( s1 ); first != last; ++first )
{
if ( auto pos = std::string_view::npos;
m.count( *first ) == 0 && ( pos = s2.find( *first ) ) != std::string_view::npos )
{
m[*first] = { std::count( first , last, *first ),
std::count( std::next( std::begin( s2 ), pos ), std::end( s2 ), *first ) };
}
}
return std::accumulate( std::begin( m ), std::end( m ), ( size_t )0,
[]( const auto &acc, const auto &item )
{
return acc + std::min( item.second.first, item.second.second );
} );
}
There is a small typo in your code as Vlad from Moscow said. The reason why that small semicolon ruins the result is that then the code:
if (s1.at(i) == s2.at(j));
{ // From here
cout << "Found character " << s1.at(i) << " at index " << i << " and " << s2.at(j) << " at index " << j << endl;
counter++;
s2.erase(s2.begin()+j);
break;
} // To here
...is not considered as the part of the if statement because a semicolon refers to the end of a statement. So the semicolon ended the if statement, and as the code in the brackets is after the if statement has been ended by the semicolon, it is not considered as a part of the if statement. I hope the explanation is clear :).

Insert rvalue in bst

I'm trying to write an STL like container for BST. I have two different functions to insert lvalue and rvalue. Function with rvalue overwrites the all the previous inserted values.
Here is the code:
std::pair<iterator, bool> insert( value_type&& value ) {
return insert_unique( std::move( value ) );
}
template<typename Vp_> std::pair<iterator, bool> insert_unique( Vp_&& value ) {
node_holder_ h_ = make_node_holder( std::move( value ) );
node_pointer_ root_ = ( *header_ ).parent_;
node_pointer_ inserted_node = h_.release();
if ( root_ == nullptr ) {
( *header_ ).parent_ = inserted_node;
( *header_ ).left_ = inserted_node;
( *header_ ).right_ = inserted_node;
inserted_node->parent_ = header_;
size_++;
return std::make_pair( make_iterator( inserted_node ), true );
}
node_pointer_ parent = root_;
node_pointer_ x = root_;
while ( x != nullptr ) {
parent = x;
if ( compare_( inserted_node->key_, x->key_ ) )
x = x->left_;
else if ( compare_( x->key_, inserted_node->key_ ) )
x = x->right_;
else
return std::make_pair( make_iterator( x ), false );
}
if ( compare_( inserted_node->key_, parent->key_ ) )
parent->left_ = inserted_node;
else
parent->right_ = inserted_node;
inserted_node->parent_ = parent;
// Update leftmost and right most
if ( compare_( inserted_node->key_, leftmost()->key_ ) ) ( *header_ ).left_ = inserted_node;
if ( !( compare_( inserted_node->key_, rightmost()->key_ ) ) &&
!( compare_( rightmost()->key_, inserted_node->key_ ) ) ) {
( *header_ ).right_ = inserted_node;
inserted_node->right_ = header_;
}
size_++;
return std::make_pair( make_iterator( inserted_node ), true );
}
node_holder_ make_node_holder( value_type&& value ) {
// std::cout << "args holders " << std::endl;
node_allocator_& na_ = get_allocator();
node_holder_ nh_( na_.allocate( 1 ), node_destructor_( na_ ) );
node_traits_::construct( na_, nh_.get(), std::move( value ) );
nh_.get_deleter().value_constructed_ = true;
return std::move( nh_ );
}
I referred to the talk by Scott-Meyers and cascaded the rvalue by using std::move. But, there is some error in the code which is causing the overwrite. Can you please share if you are able to identify the error causing this issue?
Code repository. The bst.h class is in lib/ directory.
Please share if you have any other comments and feedback on the code.

istream tellg() returns -1 when applying a streambuffer filter

I want to keep track of the linenumber in a istream and therefore wanted to use a streambuffer filter:
class LineNumberStreambuf : public std::streambuf
{
std::streambuf* mySource;
std::istream* myOwner;
bool myIsAtStartOfLine;
int myLineNumber;
char myBuffer;
protected:
int underflow()
{
int ch = mySource->sbumpc();
if ( ch != EOF ) {
myBuffer = ch;
setg( &myBuffer, &myBuffer, &myBuffer + 1 );
if ( myIsAtStartOfLine ) {
++ myLineNumber;
}
myIsAtStartOfLine = myBuffer == '\n';
}
return ch;
}
public:
LineNumberStreambuf( std::streambuf* source )
: mySource( source )
, myOwner( nullptr )
, myIsAtStartOfLine( true )
, myLineNumber( 0 )
{
}
LineNumberStreambuf( std::istream& owner )
: mySource( owner.rdbuf() )
, myOwner( &owner )
, myIsAtStartOfLine( true )
, myLineNumber( 0 )
{
myOwner->rdbuf( this );
}
~LineNumberStreambuf()
{
if ( myOwner != nullptr ) {
myOwner.rdbuf( mySource );
}
}
int lineNumber() const
{
return myLineNumber;
}
};
Source: https://stackoverflow.com/a/24861313/7483073
When i try to read istreams current position via tellg() it fails after applying the stream buffer filter:
int main()
{
std::istringstream input("i am a dummy test string");
std::cout << input.tellg() << std::endl; //prints 0
char c;
input >> c;
std::cout << input.tellg() << std::endl; //prints 1
LineNumberStreambuf ln(input);
std::cout << input.tellg() << std::endl; //prints -1 ??
return 0;
}
Edit:
I still couldn't find out why tellg() returns -1 after redirecting the streambuffer. The strange thing is that reading from istream is still possible. How can this be, if tellg() returns an invalid position?

error: no matching function for call to ‘get(long unsigned int*&, long unsigned int&)’ with union_set

This code
table_edges[ this_relationship ] = boost::add_edge(
table_vertices[ string( foreign_keys[i]["parent_table"].c_str() ) ],
table_vertices[ string( foreign_keys[i]["child_table"].c_str() ) ],
this_relationship,
rg
).first;
ds.union_set(
table_vertices[ string( foreign_keys[i]["parent_table"].c_str() ) ],
table_vertices[ string( foreign_keys[i]["child_table"].c_str() ) ]
);
gives this error and many others regarding get
/usr/include/boost/pending/detail/disjoint_sets.hpp:59:33: error: no matching function for call to ‘get(long unsigned int*&, long unsigned int&)’
I am using bundled properties.
typedef boost::adjacency_list <
boost::vecS,
boost::vecS,
boost::undirectedS,
string,
foreign_key_relationship
> relational_graph;
The rank & parent typedefs are declared globally.
How can this error be resolved?
struct foreign_key_relationship{
string parent_table;
string parent_column;
string child_table;
string child_column;
foreign_key_relationship(){}
foreign_key_relationship( string pt, string pc, string ct, string cc ) : parent_table( pt ), parent_column( pc ), child_table( ct ), child_column( cc ) {}
};
inline bool operator==(const foreign_key_relationship& lhs, const foreign_key_relationship& rhs)
{
return
lhs.parent_table == rhs.parent_table
&& lhs.parent_column == rhs.parent_column
&& lhs.child_table == rhs.child_table
&& lhs.child_column == rhs.child_column
;
}
inline bool operator<(const foreign_key_relationship& lhs, const foreign_key_relationship& rhs)
{
return
lhs.parent_table < rhs.parent_table
&& lhs.parent_column < rhs.parent_column
&& lhs.child_table < rhs.child_table
&& lhs.child_column < rhs.child_column
;
}
typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS, string, foreign_key_relationship > relational_graph;
typedef boost::graph_traits<relational_graph>::vertex_descriptor relational_vertex;
typedef boost::graph_traits<relational_graph>::vertices_size_type relational_vertex_index;
typedef boost::graph_traits<relational_graph>::edge_descriptor relational_edge;
typedef relational_vertex_index* relational_rank;
typedef relational_vertex* relational_parent;
void libpqxx_error( const pqxx_exception &e ){
cerr << "*** Caught pqxx_exception:\n";
cerr << e.base().what() << "\n";
const sql_error *s=dynamic_cast<const sql_error*>(&e.base());
if (s) std::cerr << "Query was: " << s->query() << "\n";
}
void connect_relational_vertices( map< foreign_key_relationship, relational_edge > &table_edges, result &foreign_keys, set<string> &tables_to_connect, map< string, relational_vertex > &table_vertices, relational_graph &rg, boost::disjoint_sets<relational_rank, relational_parent> &ds ){
for( unsigned i=0; i<foreign_keys.size(); i++ ){
foreign_key_relationship this_relationship(
foreign_keys[i]["parent_table"].c_str(),
foreign_keys[i]["parent_column"].c_str(),
foreign_keys[i]["child_table"].c_str(),
foreign_keys[i]["child_column"].c_str()
);
if( !table_edges.count( this_relationship ) && tables_to_connect.count( foreign_keys[i]["parent_table"].c_str() ) && tables_to_connect.count( foreign_keys[i]["child_table"].c_str() ) ){
table_edges[ this_relationship ] = boost::add_edge(
table_vertices[ string( foreign_keys[i]["parent_table"].c_str() ) ],
table_vertices[ string( foreign_keys[i]["child_table"].c_str() ) ],
this_relationship,
rg
).first;
ds.union_set( table_vertices[ string( foreign_keys[i]["parent_table"].c_str() ) ], table_vertices[ string( foreign_keys[i]["child_table"].c_str() ) ] );
}
}
}
void add_possible_linking_vertex( result &foreign_keys, map< string, relational_vertex > &table_vertices, relational_graph &rg ){
for( unsigned i=0; i<foreign_keys.size(); i++ ){
if( !table_vertices.count( foreign_keys[i]["parent_table"].c_str() ) ){
table_vertices[ foreign_keys[i]["parent_table"].c_str() ] = boost::add_vertex( foreign_keys[i]["parent_table"].c_str(), rg );
break;
}
if( foreign_keys[i]["child_table"].c_str() ){
table_vertices[ foreign_keys[i]["child_table"].c_str() ] = boost::add_vertex( foreign_keys[i]["child_table"].c_str(), rg );
break;
}
}
}
set< foreign_key_relationship > get_foreign_keys( transaction_base &t, set<string> tables_to_connect ){
try{
result foreign_keys = t.prepared("get_foreign_keys").exec();
set< foreign_key_relationship > relational_routes;
if( tables_to_connect.size() ){
relational_graph rg;
map< string, relational_vertex > table_vertices;
for( string table: tables_to_connect )
table_vertices[ table ] = boost::add_vertex( table, rg );
std::vector<relational_vertex_index> rank( num_vertices(rg) );
std::vector<relational_vertex> parent( num_vertices(rg) );
boost::disjoint_sets<relational_rank, relational_parent> ds(&rank[0], &parent[0]);
boost::initialize_incremental_components(rg, ds);
boost::incremental_components(rg, ds);
map< foreign_key_relationship, relational_edge > table_edges;
for( unsigned i=0; i<foreign_keys.size(); i++ )
connect_relational_vertices( table_edges, foreign_keys, tables_to_connect, table_vertices, rg, ds );
}
return relational_routes;
}
catch( const pqxx_exception &e ){
libpqxx_error( e );
set< foreign_key_relationship > relational_routes;
return relational_routes;
}
}
I am using libpqxx, and the query to find all foreign key relationships is here.
I have just spent ~15 minute to add the missing bits to the sample code. I was gonna edit the question and leave a comment, "sadly I ran out of time to look at your actual question".
However, then it struck me that the actual question was "why does it not compile"?
Well then, it compiles for me, so maybe this will help you figure out what's different none-the-less?
#include <boost/graph/use_mpi.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/distributed/dehne_gotz_min_spanning_tree.hpp>
#include <boost/graph/incremental_components.hpp>
#include <iostream>
#include <pqxx/except.hxx>
#include <pqxx/transaction_base.hxx>
#include <set>
#include <map>
#include <string>
using std::string;
using std::set;
using std::map;
using namespace pqxx;
struct foreign_key_relationship{
string parent_table;
string parent_column;
string child_table;
string child_column;
foreign_key_relationship(){}
foreign_key_relationship( string pt, string pc, string ct, string cc ) : parent_table( pt ), parent_column( pc ), child_table( ct ), child_column( cc ) {}
};
inline bool operator==(const foreign_key_relationship& lhs, const foreign_key_relationship& rhs)
{
return
lhs.parent_table == rhs.parent_table
&& lhs.parent_column == rhs.parent_column
&& lhs.child_table == rhs.child_table
&& lhs.child_column == rhs.child_column
;
}
inline bool operator<(const foreign_key_relationship& lhs, const foreign_key_relationship& rhs)
{
return
lhs.parent_table < rhs.parent_table
&& lhs.parent_column < rhs.parent_column
&& lhs.child_table < rhs.child_table
&& lhs.child_column < rhs.child_column
;
}
typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS, string, foreign_key_relationship > relational_graph;
typedef boost::graph_traits<relational_graph>::vertex_descriptor relational_vertex;
typedef boost::graph_traits<relational_graph>::vertices_size_type relational_vertex_index;
typedef boost::graph_traits<relational_graph>::edge_descriptor relational_edge;
typedef relational_vertex_index* relational_rank;
typedef relational_vertex* relational_parent;
void libpqxx_error( const pqxx_exception &e ){
std::cerr << "*** Caught pqxx_exception:\n";
std::cerr << e.base().what() << "\n";
const sql_error *s=dynamic_cast<const sql_error*>(&e.base());
if (s) std::cerr << "Query was: " << s->query() << "\n";
}
void connect_relational_vertices( map< foreign_key_relationship, relational_edge > &table_edges, result &foreign_keys, set<string> &tables_to_connect, map< string, relational_vertex > &table_vertices, relational_graph &rg, boost::disjoint_sets<relational_rank, relational_parent> &ds ){
for( unsigned i=0; i<foreign_keys.size(); i++ ){
foreign_key_relationship this_relationship(
foreign_keys[i]["parent_table"].c_str(),
foreign_keys[i]["parent_column"].c_str(),
foreign_keys[i]["child_table"].c_str(),
foreign_keys[i]["child_column"].c_str()
);
if( !table_edges.count( this_relationship ) && tables_to_connect.count( foreign_keys[i]["parent_table"].c_str() ) && tables_to_connect.count( foreign_keys[i]["child_table"].c_str() ) ){
table_edges[ this_relationship ] = boost::add_edge(
table_vertices[ string( foreign_keys[i]["parent_table"].c_str() ) ],
table_vertices[ string( foreign_keys[i]["child_table"].c_str() ) ],
this_relationship,
rg
).first;
ds.union_set( table_vertices[ string( foreign_keys[i]["parent_table"].c_str() ) ], table_vertices[ string( foreign_keys[i]["child_table"].c_str() ) ] );
}
}
}
void add_possible_linking_vertex( result &foreign_keys, map< string, relational_vertex > &table_vertices, relational_graph &rg ){
for( unsigned i=0; i<foreign_keys.size(); i++ ){
if( !table_vertices.count( foreign_keys[i]["parent_table"].c_str() ) ){
table_vertices[ foreign_keys[i]["parent_table"].c_str() ] = boost::add_vertex( foreign_keys[i]["parent_table"].c_str(), rg );
break;
}
if( foreign_keys[i]["child_table"].c_str() ){
table_vertices[ foreign_keys[i]["child_table"].c_str() ] = boost::add_vertex( foreign_keys[i]["child_table"].c_str(), rg );
break;
}
}
}
set< foreign_key_relationship > get_foreign_keys( transaction_base &t, set<string> tables_to_connect ){
try{
result foreign_keys = t.prepared("get_foreign_keys").exec();
set< foreign_key_relationship > relational_routes;
if( tables_to_connect.size() ){
relational_graph rg;
map< string, relational_vertex > table_vertices;
for( string table: tables_to_connect )
table_vertices[ table ] = boost::add_vertex( table, rg );
std::vector<relational_vertex_index> rank( num_vertices(rg) );
std::vector<relational_vertex> parent( num_vertices(rg) );
boost::disjoint_sets<relational_rank, relational_parent> ds(&rank[0], &parent[0]);
boost::initialize_incremental_components(rg, ds);
boost::incremental_components(rg, ds);
map< foreign_key_relationship, relational_edge > table_edges;
for( unsigned i=0; i<foreign_keys.size(); i++ )
connect_relational_vertices( table_edges, foreign_keys, tables_to_connect, table_vertices, rg, ds );
}
return relational_routes;
}
catch( const pqxx_exception &e ){
libpqxx_error( e );
set< foreign_key_relationship > relational_routes;
return relational_routes;
}
}
int main()
{
relational_graph rg;
map<foreign_key_relationship, relational_edge> table_edges;
pqxx::result data;
set<string> tables { "foo", "bar" };
map<string, relational_vertex> table_vertices;
boost::disjoint_sets<relational_rank, relational_parent> ds(relational_rank{}, relational_parent{});
connect_relational_vertices(table_edges, data, tables, table_vertices, rg, ds);
}
I compiled with
gcc 4.8, 4.9, clang 3.5-1
boost 1_56_0
command line:
g++ -std=c++0x -Wall -pedantic -lpthread -g -O0 -isystem ~/custom/boost/ -isystem /usr/include/mpi test.cpp -o test -lmpich -lpqxx

odeint (c++) - downsample observations

Sorry if this is a simple question - but is there a "best practice" for downsampling the evolution of the state variables in odeint?
Below, I've copied a nice example for building an "observer" to log the state variables provided in this article (http://www.codeproject.com/Articles/268589/odeint-v2-Solving-ordinary-differential-equations)
struct streaming_observer
{
std::ostream &m_out;
streaming_observer( std::ostream &out ) : m_out( out ) {}
void operator()( const state_type &x , double t ) const
{
m_out << t;
for( size_t i=0 ; i < x.size() ; ++i )
m_out << "\t" << x[i];
m_out << "\n";
}
};
// ...
integrate_const( runge_kutta4< state_type >() , lorenz , x , 0.0 , 10.0 , dt , streaming_observer( std::cout ) );
How would you alter the observer to only log the state every 10 steps (for example). I'm wondering whether there is a more elegant solution than putting in an if-statement:
struct streaming_observer
{
std::ostream &m_out;
int count;
streaming_observer( std::ostream &out ) : m_out( out ) {count = 10;}
void operator()( const state_type &x , double t ) const
{
if( count == 10 ) {
count = 1;
m_out << t;
for( size_t i=0 ; i < x.size() ; ++i )
m_out << "\t" << x[i];
m_out << "\n";
}
else {
count++;
}
}
};
I had the same issue and solved it exactly like you did. However, you could also consider using a stepper with step-size control and then use integrate_const with a dt such that the observer is called at the required intervals. When you use a stepper with step-size control (even better: dense ouput like dopri5), integrate_const adjusts the step size according to your error tolerance, but then assures that the observer is called at times t0 + n*dt.
Actually I would do it exactly like you did. You can also write a small adapter for doing the striding:
template< typename Obs >
struct striding_observer {
size_t stride , count;
Observer obs;
striding_observer( size_t s , Obs o ) : stride(s) , count(1) , obs(o) { }
template< typename S , typename T >
void operator()( State const& s , Time const& t ) {
if( count == stride ) {
obs( s , t );
count = 1;
} else {
++count;
}
}
};
template< typename Obs >
striding_observer< Obs > make_striding_observer( size_t stride , Obs o ) {
return striding_observer< Obs >( stride , o );
}
Then the striding is optional and composable. You can then write the very first example as
integrate_const( runge_kutta4< state_type >() ,
lorenz , x , 0.0 , 10.0 , dt ,
make_striding_observer( 10 , streaming_observer( std::cout ) ) );