开发者

3D sparse matrix implementation?

I've found a qui开发者_运维技巧te good sparse matrix implementation for c# over http://www.blackbeltcoder.com/Articles/algorithms/creating-a-sparse-matrix-in-net.

But as i work in 3d coordinate-system, i need a sparse-matrix implementation that i can use to map the 3d-coordinate system.

Details: I'm storing large amounts of primitive shapes data in memory like cubes. I do have large amounts of them (around 30 million) and i've lots of null (zero) entries around. Given that my each entry costs 1-bytes of entry, i'd like to implement a sparse-matrix so that i can fairly save memory space.

Note: Fast access to matrix cells is a fairly important factor for me, so i'd be trading speed over memory consumption.


A very simple solution which I just made is this:

public class Sparse3DMatrix<T>
{
    Dictionary<Tuple<int,int,int>, T> values = new Dictionary<Tuple<int, int, int>, T>();

    public T this[int x, int y, int z]
    {
        get { return values[new Tuple<int, int, int>(x, y, z)]; }
        set { values[new Tuple<int, int, int>(x, y, z)] = value; }
    }

    public bool ContainsKey(int x, int y, int z)
    {
        return values.ContainsKey(new Tuple<int, int, int>(x, y, z));
    }
}

usage:

var test = new Sparse3DMatrix<float>();
test[1, 1, 1] = 1f;
Console.WriteLine(test[1, 1, 1]);

It could be extended with methods like those his version have, and with checks for x, y, z values etc.

I'm sure someone have something to say about its performance. It will be a decent implementation unless you really need something it for high-performance. It depends on the hash-code implementation of Tuple and your specific usage. If we assume the hashes are good, we will have O(1) lookup time. If you know you will have a lot of elements, you could use new Dictionary<...>(initial capacity) to avoid unnecessary resizing when added items.

Unlike his, this only have a single Dictionary with all the items. His version have dictionaries of dictionaries. The benefit of his, is if you have to scan over an entire row, you can just iterate the second-level dictionary (this will not help you is you want to scan over columns) which is faster than individual lookup of the items. But having a single dictionary means smaller memory usage - especially when you have few items per row.


Lasse Espeholt's solution is practical but it can be improved by removing elements when they are "zeroed" or nulled. If you don't do this matrix or array can lose sparsity. Here is an alternative solution that assumes if an element of some type has not been inserted that it is the default of that type. For example, for double that means 0.0 and for string that means null.

public class Sparse3DArray<T>
{
  private Dictionary<Tuple<int, int, int>, T> data = new Dictionary<Tuple<int, int, int>, T>();

  public int Nnz { get { return data.Count; } }

  public T this[int x, int y, int z]
  {
    get
    {
      var key = new Tuple<int, int, int>(x, y, z);
      T value;
      data.TryGetValue(key, out value);
      return value;
    }

    set
    {
      var key = new Tuple<int, int, int>(x, y, z);
      if (null == value)
        data.Remove(key);
      else if (value.Equals(default(T)))
        data.Remove(key);
      else
       data[key] = value;
     }
   }
}


The fact that you're working in a 3D coordinate system doesn't change whether or not you can use this data structure. A matrix for a 3D space can be contained using a sparse matrix the same as a 2D matrix; it's just the entries that change.

You'd use a sparse matrix for large matricies with lots of zero entries. This is typical in discrete representations of problems in physics that come from finite difference and finite element methods. They have bands of non-zero entries clustered around the diagonal; entries outside the diagonal band are usually zero. A sparse matrix won't store these; decompositions like LU and QR have to be written to know how to deal with the sparsity.

These matricies can describe problems in either 2D or 3D spaces.

I believe you're incorrect if you think you need another data structure.


Why not use a KD-Tree or a similar data structure (such as an Octtree)? There are great c++ implementations, for instance: FLANN


I would use a Dictionary, but rather than use a Tuple<int, int, int> for the key, you can use a single long as the key and use it to store the coordinates (provided they are shorts). This will reduce your memory footprint and might even improve performance.

private Dictionary<long, T> data = new Dictionary<long, T>();
private long GetKey(short x, short y, short z)
{
   return (x * 10000 + y) * 10000 + z;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜