2

I'm working on a research problem out of curiosity, and I don't know how to program the logic that I've in mind. Let me explain it to you:

I've four vectors, say for example,

v1 = 1 1 1 1
v2 = 2 2 2 2
v3 = 3 3 3 3
v4 = 4 4 4 4

I want to add them combination-wise. That is,

v12 = v1+v2
v13 = v1+v3
v14 = v1+v4
v23 = v2+v3
v24 = v2+v4
v34 = v3+v4

Till this step it is just fine. The problem/trick is now, at the end of each iteration I give the obtained vectors into a black box function, and it returns only a few of the vectors, say v12, v13 and v34. Now, I want to add each of these vectors one vector from v1, v2, v3, v4 which it hasn't added before. For example, v3 and v4 hasn't been added to v12, so I want to create v123 and v124. Similarly for all the vectors like,

v12 should become:
v123 = v12+v3
v124 = v12+v4

v13 should become:
v132 // This should not occur because I already have v123
v134 = v13+v4;

v14,v23 and v24 cannot be considered because it was deleted in the black box function so all we have in our hands to work with is v12,v13 and v34.

v34 should become:
v341 // Cannot occur because we have 134
v342 = v34+v2

It is important that I do not do it all in one step at the start. Like for example, I can do (4 choose 3) 4C3 and finish it off, but I want to do it step by step at each iteration.

How do do it when the black box function is included?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0x0
  • 2,915
  • 5
  • 40
  • 67
  • 1
    just to clarify, when you say add, you mean combine rather than sum of values right? so v1+v2 => 11112222 – Nim Jan 04 '11 at 23:23
  • I actually mean adding the values like v12 = 3333. Like doing it with the plus operator in C++ to add two vectors. – 0x0 Jan 04 '11 at 23:27
  • 1
    In other words, this "vector" is really more like a `std::valarray`. – Rob Kennedy Jan 04 '11 at 23:53
  • @rob: I'm not familiar with `valarray`. This is the first time I'm hearing it. Sorry. – 0x0 Jan 04 '11 at 23:56
  • 1
    Don't worry about that, @Sunil. I hardly ever see it used by *anyone*. Using it would make your addition operations easier, and it might also make it easier for people to understand your question, but I don't think it ultimately affects your question at all. You just need to keep track of which values you've combined; *how* you combine them (whether by addition, concatenation, or whatever) doesn't matter. – Rob Kennedy Jan 05 '11 at 00:31
  • I would definitely look into `std::valarray`. It's more the mathematical vector you seem to require here and the syntax is pretty easy too. Ignorance of the Standard Library is not good `;)` – rubenvb Jan 05 '11 at 17:37
  • sure. I'm starting to learn and this forum has introduces me to a lot of new things. :-) – 0x0 Jan 05 '11 at 18:47
  • Can you retitle the question? There's no way this is helpful for any kind of search. – Larry Gritz Jan 05 '11 at 19:23
  • @larry: Any suggestions ? Its a logic that I'm working on. It doesn't pertain to any questions/discussions in the literature. I'll be happy to reframe it. :) – 0x0 Jan 05 '11 at 22:44

1 Answers1

2

Okay, here goes, this probably could be made more efficient, but I think this does what you need.

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <set>
#include <map>

using namespace std;

typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef vector<pair<s_t, v_t> > b_t;

// this inserts a new entry into the map with the provided key
// the value_type (vector) is generated by adding the entries in each vector
// NOTE: the first vector is passed by value (so we get a copy in the function)
// the second vector (passed by ref) is then added to it.
void insert_entry(m_t& dest, s_t& key, v_t vdest, v_t const& v2)
{
  v_t::const_iterator it2(v2.begin());
  // there is no global operator+ for vector, so you have to do something like below
  for(v_t::iterator it(vdest.begin()), end(vdest.end()); it != end && (*(it++) += *(it2++)););
  // this is just debug
  cout << "new key: " << key.size() << " : ";
  copy(key.begin(), key.end(), ostream_iterator<int>(cout, " "));
  cout << endl;
  cout << "vec: ";
  copy(vdest.begin(), vdest.end(), ostream_iterator<int>(cout, " "));
  // actual insert in to map
  // for example, key may be set<1, 2> and value is vector <3, 3, 3, 3>
  dest.insert(dest.end(), make_pair(key, vdest));
  cout << "size of dest: " << dest.size() << endl;
}

// This function generates all unique combinations of a given size and inserts them into 
// the main map
void gen_comb(size_t cmb, b_t const& base, m_t& dest)
{
  typedef m_t::iterator m_it;

  cout << "combination size: " << cmb << endl;

  // Now calculate our starting vector key size, a "key" is imply a combination of
  // vectors, e.g. v12, v23 v14 etc. in this case key size = 2 (i.e. two vectors)
  // If we need to generate combinations of size 3 (cmb=3), then we start with all
  // vectors of key size = 2 (v12, v23, v14 etc.) and add all the base (v1, v2 v3) to it
  size_t s_ksz = cmb - 1; // search key size
  cout << "search size: " << s_ksz << endl;
  // now iterate through all entries in the map
  for(m_it it(dest.begin()); it != dest.end(); ++it)
  {
    // Aha, the key size matches what we require (for example, to generate v123, we
    // need v12 (key size == 2) first
    if (it->first.size() == s_ksz)
    {
      // Now iterate through all base vectors (v1, v2, v3, v4)
      for(b_t::const_iterator v_it(base.begin()), v_end(base.end()); v_it != v_end; ++v_it)
      {
        // new key, start with the main key from map, e.g. set<1, 2>
        s_t nk(it->first.begin(), it->first.end());
        // Add the base key set<3>, reason I do it this way is that, in case you
        // that base vectors should be other than size 1 (else insert(*((*v_it)->first.begin())) should work just fine.
        nk.insert(v_it->first.begin(), v_it->first.end());
        // check if this key exists, this is the main check, this tests whether our map
        // already has a key with the same vectors (for example, set<1,2,3> == set<2,3,1> - internally set is ordered)
        m_it k_e = dest.find(nk);
        // If the key (combination of vectors) does not exist, then insert a new entry
        if (k_e == dest.end())
        {
          // new key
          insert_entry(dest, nk, it->second, v_it->second);
        }
      }
    }
  }
}

void trim(size_t depth, m_t& dest)
{
  for(m_t::iterator it(dest.begin()); it != dest.end();)
  {
    if (it->first.size() == depth && (rand() % 2))
    {
      cout << "removing key: " << depth << " : ";
      copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
      cout << endl;
      dest.erase(it++);
    }
    else
      ++it;
  }
}

int main(void)
{
  // combination map
  m_t dest;

  // this is the set of bases
  b_t bases;
  int max_i = 4;
  for(int i = 1; i <= max_i; ++i)
  {
    v_t v(4, i);
    s_t k;
    k.insert(i);
    bases.push_back(make_pair(k, v));
  }

  // for the start, push in the bases
  dest.insert(bases.begin(), bases.end());

  // for each combination size, generate a new set of vectors and then trim that set.
  for (size_t cmb = 1; cmb <= static_cast<size_t>(max_i); ++cmb)
  {
    if (cmb > 1) gen_comb(cmb, bases, dest);
    trim(cmb, dest); // randomly remove some entries...
  }


  return 0;
}

NOTES:

  1. the trim function models your black box which removes some entries from the main map with a given key size (same size as the most recently generated combinations)
  2. I'm not sure about the validity of iterating through the map and inserting new entries (i.e. how it impacts the iterator, it appears to work, but I think there may be something subtle that I am missing - it's far too late at night to think about that right now!)
  3. Performance, may not be ideal, as you need to iterate through all keys to find the search size (for combination).
  4. assumes that all vectors have the same size (but this can be fixed trivially)
  5. If you take out the debug, you'll see that the actual code is quite small..
  6. The order of the combination is not preserved - not sure if this is necessary for you

EDIT: Okay now base is a vector which contains a pair for the key<->vector relationship - this is constant. Initially it is added to the map, and the gen_comb function is skipped for the initial state, trim is still called to remove some entries. Next iteration uses the same search algorithm, but the combination is with the constant set of bases.

Nim
  • 33,299
  • 2
  • 62
  • 101
  • you forgot `#include `. That's why I got so many errors. :-) – 0x0 Jan 05 '11 at 01:20
  • i think this logic is perfect but I'm still trying to understand it. Some more comments will be very helpful. Thanks – 0x0 Jan 05 '11 at 01:29
  • @Nim: I've one small concern. Here your trim function takes both key and vector pair (i.e. the entire map) and trims it together but my black box function takes as input a 2d vector and outputs trimmed 2d vector (deletes certain vectors inside the vector). I can transform the independent 1d vectors in your program to 2d vectors but how can I maintain the match then ? Please help me out. I'm finding it difficult to maintain the match after the black box function is done. Thanks a lot. – 0x0 Jan 05 '11 at 03:59
  • 1
    @Sunil, oops codepad didn't complain, anyways will edit for more comments. Presumably you cannot modify the function to take the map? hmm, this makes it tricky - the blackbox function, does it take a vector (of vectors) where they size of the key is same (i.e. all vectors only of key size 2, then 3, then 4 etc.)? Also, does it trim positionally or all vectors that are the same (for example, v23 == v14)? – Nim Jan 05 '11 at 08:34
  • The logic that you have presented is perfect. The function is of the type `vector > black_box(vector< vector > )`. The key size is the same. vectors of key size 2 , then 3 and so on. It trims row-wise. say I give a 2dvector of size 10 (10 rows) and it gives me output of something like a 2d vector of size 5. – 0x0 Jan 05 '11 at 14:53
  • Hi Nim, I got to access the black box function and I changed it so that it accepts the map and returns the map. So that problem is solved. The last concern is that I've to the black box fn takes in the base vectors too. like it takes v1,v2,v3 and v4 ans gives as output say v1 and v4. On this I want to generate vectors like v12,v13,v14,v42,v43. i.e. I want the program to have a backup of base vectors and work from the first iteration. – 0x0 Jan 05 '11 at 16:06
  • 1
    If you change the for loop such that `cmb=1`, add an `if` around the `gen_comb` so it doesn't bother generating combinations if `cmb==1`, then you can still call your black box function with the map that contains only the base arrays, and this should work. – Nim Jan 05 '11 at 16:18
  • I mean, I tried it as it is the simplest thing but at the first iteration it removes the vectors say v2,v3 and v4. The remaining vector is v1. Now in the second iteration it does not produce v12,v13,v14. Could you please try it and let me know. I greatly appreciate you time and help. Thanks – 0x0 Jan 05 '11 at 16:40
  • If I take out the trim function everything works fine as you say but the trim function is needed from the first iteration. – 0x0 Jan 05 '11 at 16:43
  • Thank you very very much. You have been a great help. – 0x0 Jan 05 '11 at 17:54
  • @Nim : Sorry for disturbing you again but there is bug that I'm unable to fix in this code. Given two vectors v1 <4,4,0,4,3,2> and v2 <5,5,0,5,2,1>, which happens to have zero at the same position, the addition of these two vectors results in <9,9,0,4,3,2>. After encountering zero in the same position it just outputs the first vector. Would you be able to tell why ? – 0x0 Jan 19 '11 at 20:04
  • @Nim: I kind of need you help. Is there a way to offer extra points to you? I can give some and I'd highly appreciate your help here. – 0x0 Jan 21 '11 at 03:45
  • Hi Sunil, sorry, been a little tied up with day job... how did you end up with the 0 in the vector? May be you can provide your base vector so I can replicate the issue... – Nim Jan 21 '11 at 08:44