Boost logo

Boost :

From: Janek Kozicki (janek_listy_at_[hidden])
Date: 2006-11-22 16:06:29


Since I can't stop thinking about that, I'll try to describe the most
difficult data structure that I have here. Maybe you will have some
suggestions. And maybe it will help me to sort the thing out.

In my program I am calculating bodies collisions and other
kind of interactions. This is a physical simualtion stuff.

I have a container (an easier one) with bodies where each body has an
integer ID number. And the bodies can interact together, there are
various kinds of interaction. And I need to store those interactions
in a container. The keys are:

- interaction type: each polymorphic interaction type stored in this
  container is a different kind of interaction. Sometimes I need to
  interate over all interactions of selected type, thus it becomes
  one of the keys.
  This is an integer.

- a set of interacting bodies: any number of bodies can interact. Two
  or more bodies, but very rarely as much as four.
  - Sometimes I need to iterate over all interactions which
    involve a selected body or,
  - check if an interaction of given type between bodies 1, 2 and 3
    already exists, then get it, or add it, if it didn't exist.
  This is a list of integer values (IDs of bodies).

If I had only two-body interaction of single type then this could ba
a (sparse) two dimensional symmetric matrix. Boost.Graph library
treats two-body interaction as a graph edge, and the container used is
std::vector<std::set<T> > > which works well for that.

An example content of this container could be:

   interaction Type IDs of bodies involved
+---------------------+--------------------------------------
| | (2,3) (2,3,4) (8,11,12,15) (13,14)
+---------------------+--------------------------------------
| ElasticContact | X X X
+---------------------+--------------------------------------
| MagneticInteraction | X X X
+---------------------+--------------------------------------
| .
| .
| .

The 'X' means that there is an instance present.

One solution (a bit of pseudocode) could be:

multi_index_container<
  interaction*,
  indexed_by<
     ordered_non_unique<member<interaction*,int,&interaction::type> >

     ordered_unique <member<interaction*,std::set<int>,&interaction::bodies> >
     // non_unique in fact. But uniqe with respect to &interaction::type.
     // That's why it's pseudocode

>
>;

But how to make this and get a reasonable performance?

And how to make that std::set<int> working? :) (or maybe
tr1::hash_set<int>, if there is one)

How to iterate over all interactions involving a body with ID 3 of type 1 ?

For example I could use lazy deletion (only sets the field as
unused), with cleaning invoked from time to time.

Performance priorities (from most important, to least important):

A)iterating over all elements with the same &interaction::type must
  be constant access time.

B)finding if there is an interaction between (1,2,3) - great if it
  was constant time (N-dimensional matrix gives that), I guess that log(O)
  is the best we can have.

C)deleting and adding an interaction, again I guess that constant
time is not possible.

D)iterating over all interactions involving a body with given ID is
used less often so can be a bit slower.

If you have any insights I'd appreciate that :)

-- 
Janek Kozicki                                                         |

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk