tags:

views:

150

answers:

2

I am trying to adapt a digital electronics problem to a C++ STL based program.

Originally I have 4 inputs C1, C2, C3, C4. This means I have a total of 16 combinations:

0000
0001
.
.
.
1111

I have a multimap defined by

typedef std::pair<int, int> au_pair; //vertices
typedef std::pair<int, int> acq_pair; //ch qlty
typedef std::multimap<int, acq_pair> au_map;
typedef au_map::iterator It_au;

The no. of simulations depend on the size of the au_map. For eg: if the au_map.size() = 5 I will have C1, C2, C3, C4, C5. and therefore 2^5 = 32 cases.

For example: If theau_map.size()=4, I need to simulate my algorithm for 16 cases.

for(It_au it = a_map.begin(); it != a_map.end(); it++)
{
  acq_pair it1 = it->second;
  //case 0:
  //C3 = 0, C2 = 0, C1 = 0, C0 = 0 
  //Update it1.second with corresponding C values

  //simulate algorithm

  //case 1:
  //C3 = 0, C2 = 0, C1 = 0, C0 = 1 
  //simulate

  .........
  //case 15: 
  //C3 = 1, C2 = 1, C1 = 1, C0 = 1 
  //simulate

}
+1  A: 

Not the best idea. Right now you're doing a lot of useless work by manually setting your C1-C4 and by writing some simulation routines right in your for loop.

Automate it.

Use some abstract State-Simulator mapper (where Simulator actually stands for some concrete functional object).

typedef char State;

struct basic_simulator {
   // You could also pass some other parameters to your
   // simulator
   virtual void operator()(...) = 0
};

struct concrete_simulator : public basic_simulator {
   virtual void operator()(...) {
      // Do something concrete
      // Trolololo
   }
};

typedef basic_simulator Simulator;

And in this case your actual wrapper would look like std::map<State, Simulator*> map;


What you need to do next do means getting C1-C4 values from your state which is defined as char. Use bitwise operators.

All your states could be defined as 0-15 numbers converted to binary (2 -> 0010). So to get C1-C4 values you would simply have to make appropriate shifts:

// C1 C2 C3 C4
// -----------
// 1  1  1  1
State state = 15;

for (int i = 3; i >= 0; i--) {
   // State of some of the inputs, defined by one bit
   InputState C_xx = ((state >> i) & 1);
}

Now simply map all those 0-15 states to appropriate simulating functor:

std::map<State, Simulator*> mapper;
// Generally speaking, you should use some sort of
// smart pointer here
mapper[0] = new concrete_simulator(...);
mapper[1] = ...

What is really cool that you could have only, let's say, 3 or four concrete simulators which would be mapped to some states accordingly.

In this case invoking actual simulation would mean something like:

  // Fire appropriate simulation object
  (*(mapper[actual_state]))(...);

and making every possible simulation means iterating over every map element.


Update: the same technique could be used for states where you have more than 4 inputs / single input state can have more than two possible values.

Just write an appropriate mapping function and state generator.

Kotti
Why is a std::map preferable to std::vector? You would certainly get better performance with std::vector.
andand
@andand In case of 16 states - yes - `O(N)` lookup time in `std::vector` would be better than `O(log N)` lookup time in `std::map`. But simply because state number grows as `A^N` where `A` stands for possible values and `N` stands for input numbers, `std::map` would give better asymptotical performance. **And yes - why even talk about performance before profiling?**
Kotti
@andand Also to mention, `std::map` could be easily switched to, for example, `boost::unordered_map` granting `O(1)` lookup time.
Kotti
A: 

Hum... why not letting a for loop enumerate the various combinations for you ?

for (size_t i = 0; i != 16; ++i)
{
  bool const c1 = i & 1;
  bool const c2 = i & 2;
  bool const c3 = i & 4;
  bool const c4 = i & 8;

  // your algorithm
}

A bit easier than setting them by hand.

Matthieu M.