How to implement logic based on a relationship matrix - c++

Consider that I have a symmetrical relationship matrix, similar to this:
Except that each "outcome" is a small piece of code.
My scenario: I have a bunch of Entity objects that "collide" with eachother. Each entity has a CollisionType value (an enum). In the design, a relationship matrix exists which describes how the entities behave when different CollisionTypes meet each other.
I'm wondering: How would I represent the relationships, and also implement logic on top of it, in an clean and high-performance manner which is easy to add new CollisionTypes to? In my mind it looks something like a 2D Switch statement.
Example (poor) solution:
void CollideEntities( Entity e1, Entity e2 ) {
CollisionType t1 = e1.GetCollisionType();
CollisionType t2 = e2.GetCollisionType();
// perform basic logic based on t1 & t2
if ( (t1 == COL_SOLID && t2 == COL_SQUISHY) || (t1 == COL_SQUISHY && t2 == COL_SOLID) ) {
// do stuff..
} else if ( (t1 == COL_SOLID && t2 == COL_DAMAGE) || (t1 == COL_DAMAGE && t2 == COL_SOLID) ) {
// do other stuff..
} // and so on...
}
Many potential solutions are apparent to me, but none of them strike me as particularly clean or efficient or easy to add new types to...

I wouldn't do it that way. I'd have a Map where the key would look up a Command object containing the desired behavior.
Another possibility would be a Visitor pattern (aka "double dispatch").

Try this:
#include <vector>
#include <iostream>
class Symmetric_matrix {
private:
size_t size1;
// The next should be <bool> rather than <int>,
// but the writer's compiler objects.
std::vector<int> outcomes;
public:
size_t size() const { return size1; }
int &operator()(const size_t i, const size_t j) {
const size_t a = i <= j ? i : j;
const size_t b = i <= j ? j : i;
return outcomes[(b*(b-1))/2 + a];
}
Symmetric_matrix(const size_t size0)
: size1(size0), outcomes((size()*(size()-1))/2, false) {}
};
// Here is a test driver.
int main() {
Symmetric_matrix sm(5);
sm(0, 1) = true;
sm(0, 3) = true;
sm(1, 3) = true;
sm(2, 3) = true;
sm(3, 4) = true;
std::cout << "buyer-approver : " << sm(0, 2) << "\n";
std::cout << "approver-buyer : " << sm(2, 0) << "\n";
std::cout << "approver-requisition: " << sm(2, 3) << "\n";
std::cout << "requisition-approver: " << sm(3, 2) << "\n";
return 0;
}
Your question is an interesting one. As you have observed, one need only store the upper or the lower triangle of the matrix, not both.
But what's the (b*(b-1))/2 about, you ask? Answer: it comes of the curious arithmetical fact that 0 + 1 + 2 + ... + (b-1) == (b*(b-1))/2 (try it).
Of course, my sample code could stand some improvement. For one thing, for some reason (advice is requested), my code fails when it uses a std::vector<bool>, so I have used a std::vector<int> as a workaround. For another, it does not include proper handling for the case i == j. What it does do however is to convey the essential technique. You can fill out details at your discretion.
(Update: It has later occurred to my why the std::vector<bool> fails. It fails because std::vector<bool> is implemented as an array of bits, whereas a single bit cannot be an lvalue because it has no address of its own. With clever coding, by having the operator()() return a manipulator of some specially defined type, one could probably finesse the problem without altering main(), but it is probably easiest just to define and use a set() member function if the <bool> is what we want to use.)

Related

Handling int and std::vector::size_type in comparsion

So I have something like this (C++03):
class MyClass
{
// ...
}
class something
{
private:
std::vector<MyClass*> container;
// ...
}
// cmdarg can be anything, negative int too...
void something::foo(const std::string& cmdarg)
{
const int res = std::stoi(cmdarg);
if (res >= 0 && static_cast<std::vector<MyClass*>::size_type>(res) < this->container.size())
{
// ...
}
}
I would like to ask if the conversion from int to std::vector<MyClass*>::size_type is valid. The res >= 0 says it's non negative, so I guess converting to an another non-negative number is okey.
My problem is, if I write
if (res >= 0 && res < container.size())
I get a warning, because of comparsion with signed and unsigned integer types.
My above code (the full one) compiles and seems to work, but I'm not sure.
Thank you.
Your code looks a bit too perfect for my taste.
Breaking it down:
const int res = std::stoi(cmdarg);
if (res >= 0 && static_cast<std::vector<MyClass*>::size_type>(res) < this->container.size())
The if-statement for checking below zero is nice. Personally I would write this as:
if (res < 0)
{
std::cerr << "Negative number " << res <<" given for ..., a positive was expected" << std::endl;
return -1;
}
This leads us to the cast:
auto unsigned_res = static_cast<std::vector<MyClass*>::size_type>(res);
However, size_type this vector always size_t as it uses the std::allocator. In code review, I would request to change this for readability to:
auto unsigned_res = static_cast<std::size_t>(res);
Finally, you can indeed nicely compare it:
if (unsiged_res < container.size())
// Do something
Note that I mentioned both the comparison and the cast, as this needs to happen in that order. On top of that, you also need some exception handling for when std::stoi fails, see it's documentation
For more details on how to correctly deal with signed/unsigned, I can recommend this article on ithare.

How to write custom datatype (std::array filled with std::pairs) to a filestream

I am quite new to c++ and I am building a model studying certain mutations in genes. My "genes" are defined as a function of two doubles, a and b. A single gene is saved in a std::pair format. The whole genome consists of four of these genes collected in a std:array.
I perform some changes on the genes and want to write the information in a text file for analysis. The way I have currently implemented this is tedious. I have separate functions (8 in total) which collect the information like g[i].first, g[i[.second etc. for every i in the array. I feel this could be done much more efficiently.
Relevant code:
Declaration of data type:
using gene = std::pair<double, double>;
using genome = std::array<gene, 4>;
Function in which I create a genome called g:
genome Individual::init_Individual()
{
double a1, a2, a3, a4 = -1.0;
double b1, b2, b3, b4 = 0.0;
gene g1{ a1,b1 };
gene g2{ a2,b2 };
gene g3{ a3,b3 };
gene g4{ a4,b4 };
genome g{g1,g2,g3,g4};
return g;
}
Example of collect function:
double get_Genome_a1() { return g[0].first; };
Function in which I write information to a text file:
void Individual::write_Statistics(unsigned int &counter)
{
//Generate output file stream
std::ofstream ofs;
ofs.open("data.txt", std::ofstream::out | std::ofstream::app);
ofs << counter << std::setw(14) << get_Genome_a1() << std::setw(14)
<< get_Genome_a2() << std::setw(14) << get_Genome_b1() <<
std::setw(14) << get_Genome_b2() << "\n";
}
ofs.close();
}
etc, etc. So the final result of my data file in this example looks like this:
1 a1 a2 b1 b2
2 a1 a2 b1 b2
3 a1 a2 b1 b2
etc, etc.
My question:
I am currently storing the two doubles in a std::pair, which I collect in a std::array. Is this an efficient storage mechanism or can this be improved?
Is there a way to directly reference an individual element from my custom data type "genome" using only one function to write every element away in the exact same manner as I am doing now (with fourteen spaces between every element)? Something in pseudocode like: get_Genome() {return g;};, and when you call it you can specify the element like: get_Genome([0].first) which would be the first value stored in the first pair of the array, for example.
Happy to learn, any insight is appreciated.
Your storage is good. Neither pair nor array requires indirect/dynamic allocation, so this is great for cache locality.
As for referencing elements, no, not exactly like that. You could have an enum with members FIRST, SECOND then pass that as another argument to get_Genome. But, honestly, this doesn't seem to me to be worthwhile.
Overall, your approach looks great to me. My only suggestions would be:
Re-use one ofstream
…rather than opening and closing the file for every sample. You should see substantial speed improvements from that change.
You could make one in your main or whatever, and have write_Statistics take a std::ostream&, which would also be more flexible!
Initialise a bit quicker
All those declarations in init_Individual may get optimised, but why take the risk? The following is pretty expressive:
genome Individual::init_Individual()
{
const double a = -1.0;
const double b = 0.0;
return {{a, b}, {a, b}, {a, b}, {a, b}};
}
It's worth noting here that your double initialisations were wrong: you were only initialising a4 and b4; your compiler ought to have warned you about this. But, as shown, we don't need all of those anyway as they [are intended to] have the same values!
Your array looks good, however using std::pair in this situation might make it a bit more tedious. I would create 2 simple classes or structures one to represent a gene and the other to represent your genome. I'd still use array. The class might look something like this:
#include <array>
const int genesPerGenome = 4; // change this to set how many...
struct Gene {
double a_;
double b_;
Gene() = default;
Gene(double a, double b) : a_(a), b_(b) {}
};
struct Genome {
std::array<Gene, genesPerGenome> genome_;
int geneCount_{0};
Genome() = default;
void addGene(const Gene& gene) {
if ( geneCount_ >= genesPerGenome ) return;
genome_[geneCount_++] = gene; // post increment since we added one
}
};
Then I would have a stand alone function that would generate your genome as such:
void generateGenome( Genome& genome ) {
for (int i = 0; i < 4; i++) {
// When looking at your example; I notices that the genes were all
// initialized with [-1.0,0.0] so I used Gene's constructor to init
// them with those values.
Gene gene(-1.0, 0.0);
genome.addGene(gene);
}
}
Then to couple these together, I'll just print them to the console for demonstration. You can then take this approach and apply it to what ever calculations that will be done and then writing the results to a file.
#include <array>
#include <iostream>
int main() {
Genome genome;
generateGenome( genome );
// printing to console here is where you would do your calculations then write to file
for ( int i = 0; i < 4; i++ ) {
if ( i >= genome.geneCount_ ) break; // prevent accessing beyond array bounds
std::cout << (i+1) << " [" << genome.genome_[i].a_ << "," << genome.genome_[i].b_ << "]\n";
}
return 0;
}
-Output- - No calculations, only the initialized values:
1 [-1,0]
2 [-1,0]
3 [-1,0]
4 [-1,0]
Maybe this will help. From here you can write a operartor<<() function that will take an ostream reference object and a const reference to a Genome and from there you should be able to print the entire Genome to file in a single function call.
-Edit-
User t.niese left a comment with a valid point that I had overlooked. I was using a static variable in the addGene() function. This would work okay as long as you are working only with a single Genome, but if you had more than one Genome object, every time you'd call the addGene() function this value would increase and you wouldn't be able to add more than gene to each genome due to the condition of the if statement in the addGene() function.
I had modified the original code above to fix this limitation. Here I removed the static variable and I introduced two new variables; one is a const int that represents how many genes per genome as it will be used to define the size of your array as well as checking against how many genes to add to that genome. The other variable I added is a member variable to the Genome class itself that keeps track of how many genes there are per each Genome object.
Here is an example of what i meant in my comment by overloading the operator [].
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
class Genome {
public:
typedef std::pair<double, double> gene;
private:
double a1 = -1.0, a2 = -1.0, a3 = -1.0, a4 = -1.0;
double b1 = 0.0, b2 = 0.0, b3 = 0.0, b4 = 0.0;
gene g1{ a1,b1 };
gene g2{ a2,b2 };
gene g3{ a3,b3 };
gene g4{ a4,b4 };
public:
Genome() {}
const double operator[] (std::string l) const {
if (l == "a1") {return g1.first;}
else if (l == "b1") {return g1.second;}
else if (l == "a2") {return g2.first;}
else if (l == "b2") {return g2.second;}
else if (l == "a3") {return g3.first;}
else if (l == "b3") {return g3.second;}
else if (l == "a4") {return g4.first;}
else if (l == "b4") {return g4.second;}
else {
throw std::invalid_argument("not valid label");
}
}
void setvalue(std::string l, double x) {
if (l == "a1") {g1.first = x;}
else if (l == "b1") {g1.second = x;}
else if (l == "a2") {g2.first = x;}
else if (l == "b2") {g2.second = x;}
else if (l == "a3") {g3.first = x;}
else if (l == "b3") {g3.second = x;}
else if (l == "a4") {g4.first = x;}
else if (l == "b4") {g4.second = x;}
else {
throw std::invalid_argument("not valid label");
}
}
void write_Statistics(unsigned int counter) {
std::ofstream ofs;
ofs.open("data.txt", std::ofstream::out | std::ofstream::app);
ofs << counter
<< std::setw(14) << (*this)["a1"] << std::setw(14) << (*this)["a2"]
<< std::setw(14) << (*this)["b1"] << std::setw(14) << (*this)["b2"] << "\n";
ofs.close();
}
}
};
I don't know if you may find useful to access to the individual genes by a label instead of an index, but this is what this overload do.
int main(int argc, char **argv) {
Genome a = Genome();
std::cout << a["b1"] << std::endl; #this prints 0
a.setvalue("b2", 3.0);
std::cout << a["b2"] << std::endl; #this prints 3
a.write_Statistics(0);
return 0;
}

Return from calling function inside lambda

Lambdas are an awesome way to create reusable code inside a function/method without polluting the parent class. They're a very functional replacement for C-style macros most of the time.
However, there's one bit of syntactic sugar from macros that I can't seem to replicate with a lambda, and that's the ability to exit from the containing function. For example, if I need to return while checking the range of a series of ints, I can do that easily with a macro:
const int xmin(1), xmax(5);
#define CHECK_RANGE(x) { if((x) < xmin || (x) > xmax) return false; }
bool myFunc(int myint) {
CHECK_RANGE(myint);
int anotherint = myint + 2;
CHECK_RANGE(anotherint);
return true;
}
Obviously this is an oversimplified example, but the basic premise is that I'm performing the same check over and over on different variables, and I think it's more readable to encapsulate the check and related exits. Still, I know that macros aren't very safe, especially when they get really complex. However, as far as I can tell, trying to do the equivalent lambda requires awkward additional checks like so:
const int xmin(1), xmax(5);
auto check_range = [&](int x) -> bool { return !(x < xmin || x > xmax); };
bool myFunc(int myint) {
if(!check_range(myint)) return false;
int anotherint = myint + 2;
if(!check_range(anotherint)) return false;
return true;
}
Is there a way to do this with a lambda? Or am I missing some alternative solution?
Edit: I recognize that returning from inside a macro is generally a bad idea unless significant precautions are taken. I'm just wondering if it's possible.
You are correct--there's no way to return from the caller from inside a lambda. Since a lambda can be captured and stored to be called later, from inside an arbitrary caller, doing so would result in unpredictable behavior.
class Foo
{
Foo(std::function<void(int)> const& callMeLater) : func(callMeLater) {}
void CallIt(int* arr, int count)
{
for (index = count; index--;)
func(count);
// do other stuff here.
}
std::function<void(int)> func;
};
int main()
{
auto find3 = [](int arr)
{
if (arr == 3)
return_from_caller; // making up syntax here.
};
Foo foo(find3);
};
Is there a way to do this with a lambda?
Not exactly like the macro but your lambda, instead of returning a bool, can throw a special exception (of type bool, by example)
auto check_range
= [](int x) { if ( (x < xmin) || (x > xmax) ) throw bool{false}; };
and the function myFunc() can intercept this special type
bool myFunc (int myint)
{
try
{
check_range(myint);
int anotherint = myint + 2;
check_range(anotherint);
return true;
}
catch ( bool e )
{ return e; }
}
For a single check_range() call, this is (I suppose) a bad idea; if you have a lot of calls, I suppose can be interesting.
The following is a full working example
#include <iostream>
constexpr int xmin{1}, xmax{5};
auto check_range
= [](int x) { if ( (x < xmin) || (x > xmax) ) throw bool{false}; };
bool myFunc (int myint)
{
try
{
check_range(myint);
int anotherint = myint + 2;
check_range(anotherint);
return true;
}
catch ( bool e )
{ return e; }
}
int main ()
{
std::cout << myFunc(0) << std::endl; // print 0
std::cout << myFunc(3) << std::endl; // print 1
std::cout << myFunc(7) << std::endl; // print 0
}
No better way to do this than just to use the return value of the lambda and then return from the calling function. Macros are ew for this.
As it stands in C++, that is the idiomatic way to exit from a function that uses another condition to determine whether or not to exit.
Not C++11, but people have hacked C++2a coroutines to basically do this.
It would look a bit like:
co_await check_range(foo);
where the co_await keyword indicates that in some cases, this coroutine could return early with an incomplete result. In your cases, this incomplete result would be non-resumabable error.
The playing around I saw was with optionals, and required using a shared ptr, but things may improve before it is standardized.

How to properly check multiple times statment

if(a=='b' && b=='b' && c=='b' ...)
Is it the proper way to do this?
I already found other way to solve my problem but would like to know for future times how to do this
If all you have are discrete variables, then you'll have to do this check this way.
There are a few things you'll want to consider though:
It's bad practice to keep using 'b' over and over and over. Either assign it as a constant or have all the other variables compare against the first one, so that if you need to change that 'b' to a 'c' you only have to do it once in the code.
if(a=='b' && a == b && a == c && a == d/*...*/)
Also, this is still a lot of code to maintain. Depending on how long the chain goes (do you go up to a==g && a==h && a == i or further?) You might want to wrap those variables into a vector and iteratively check them.
bool equal = std::find_if_not(
characters.begin(), characters.end(),
[](const char & c) {return c == 'b';}
) == characters.end();
if you'd like a succinct way to describe intent then a little pair of template functions can help you:
template<class X, class Y>
bool all_equal(X&& x, Y&& y)
{
return (x == y);
}
template<class X, class Y, class...Rest>
bool all_equal(X&& x, Y&& y, Rest&&...rest)
{
return all_equal(std::forward<X>(x), std::forward<Y>(y))
&& all_equal(x, std::forward<Rest>(rest)...);
}
which allows code like this:
int main()
{
int a = 10;
int b = 10;
int c = 10;
int d = 11;
std::cout << std::boolalpha << all_equal(a, b) << std::endl;
std::cout << std::boolalpha << all_equal(a, b, c) << std::endl;
std::cout << std::boolalpha << all_equal(a, b, c, d) << std::endl;
}
Your way looks proper. Some coding standards require extra parens like this
if((a=='b') && (b=='b') && (c=='b') ...)
I personally don't think that it is necessary, if you know your operator precedence. see http://www.cppreference.com and search for precedence.

dynamic_bitset, crash my program

I'm new with boost. I have a program which uses dynamic_bitset inside a lambda function. After I try to run the program, I get this message. This message appears even without the function that initializes the bitset and the functions that handle it.
Does anybody know what this message means and what might be the problem?
The message:
/usr/include/boost/dynamic_bitset/dynamic_bitset.hpp:616: boost::dynamic_bitset<Block, Allocator>::~dynamic_bitset() [with Block = long unsigned int, Allocator = std::allocator<long unsigned int>]: Assertion 'm_check_invariants()' failed.
Aborted
well the code is something like this
main call to this function :
int Molecule::initSimilarity(int depth){
cout << "_size is: " << _size << "\t depth is: " << depth << endl; //TODO delete
AtomSet viewing(_size);
int m = 0;
{
// break into initial groups by symbol and valancy
for(int i=0 ; i<_size ; i++)
{
if(viewing[i]) continue;
AtomSet mask = getSetMask( //AtomSet is typedef for dynamic_bitset
[&](const Atom& b)->bool
{
return (!viewing[b._index] && b._valence == _atoms[i]->_valence && strcmp(b._symbol, _atoms[i]->_symbol) == 0);
},
[&](Atom &b)
{
b._class = m; //set the equivalence class of atom 'b' to 'm'
}
);
m++;
viewing |= mask; //viewing now contains a set of atoms and for each atom it's equivalence class
}
cout << "number of equivalence class: " << m << endl; //TODO DELETE!
}
for (int j = 0; j < depth ; j++){
AtomSet viewed(_size);
int before = m;
// iteratively refine the breakdown into groups
for (int i = 0 ; i < _size ; i++) //for any atom A
{
if (viewed[i]) continue;
viewed.flip(i);
AtomSet mask = getSetMask(//put all atoms which are equivalnt but not similar to A in
//their own equivalence class
[&](const Atom& b)->bool
{
if (viewed[b._index])
return false; //if b is in viewed return false;
if (_atoms[i]->_class == b._class) //if in the same class add b to viewed
{
viewed.flip(b._index);
bool similar = !isSimilar(*_atoms[i],b);
return similar;
}
return false;
},
[&m](Atom& b)
{
b._class = m;
}
);
if (!mask.none()) m++;
}
if (before == m){
std::cout << "Finished early after just " << j << " iterations" << std::endl;
return m;
}
}
return m;
}
the signature of getSetMask is:
AtomSet getSetMask(std::function property, std::function action);
and the weirdest thing that even when i remove all the content of that function it still give me the error message
Probably the dynamic_bitset variable that you are referencing in the lambda has gone out of scope and has already been destroyed, or something similar. (Without the source code it's difficult to be more specific)
I had that problem and it took me 3 hours to find out the problem. Here is what can happen: The operator[] in dynamic_bitset does not do bound checking. So, one value can be assigned outside of allowed range and this does not create any error (sanitizer/valgrind do not see anything) since dynamic_bitset is using 64 bit integers (on my computer at least) in order to store values. So, you can get a stored integer of 32 while you allowed only 4 bits in the dynamic_bitset. The error is triggered at a later time when m_check_invariant() is called for example when the destructor is called.
So, the problem becomes to find this range error. The solution is to edit the boost/dynamic_bitset.hpp and add print statement in the code of operator[] when an operation out of range is called. If you cannot do that then download the boost library and install it in your home directory.
I had a similar problem with dynamic_bitset that was solved by calling reset() on it before it got destroyed.
That can indicate that you are writing past the end of the bitset without resizing it. Might want to do some bounds checking.
Read the explaination of Mathieu Dutour Sikiric. The problem is that you write outside of allowed range of the bitset via operator[] and this does not create any error because it's boost and it doesn't bother to waste compute time checking that you have right to write where you want. It is C++ you know...
So to detect it, go to boost/dynamic_bitset/dynamic_bitset.hpp, and modify the code to impose checks every time you use operator[].
boost/dynamic_bitset/dynamic_bitset.hpp, around line 300.
reference operator[](size_type pos) {
assert(m_check_invariants());
return reference(m_bits[block_index(pos)], bit_index(pos));
}
bool operator[](size_type pos) const {
assert(m_check_invariants());
return test(pos);
}
This makes it easier to detect the error in your code.