Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Growing a Hashmap of vectors in Matlab

I have a need for hashmap-like functionality in Matlab, where the hashmap maps vectors to other vectors, and the number of vectors (ranging in the hundreds of thousands) is not known beforehand.

I tried Matlab's inbuilt Containers.Map, but that doesn't accept vectors as keys. Then I tried java.util.HashMap:

>> map = java.util.HashMap;
>> map.put(1:3,zeros(2,1));
>> map.get(1:3)

 ans =

 []

So for some reason that doesn't seem to work, even though Java's HashMap should be able to map arrays to arrays.

The other option would be to keep two separate matrices, one for the keys and one for the values, and grow them incrementally. But I don't want really want to do that because of the pain in Matlab of growing things incrementally (even with block-size increments etc, e.g. here).

Questions: 1. Why doesn't Java's HashMap work here? 2. Any other approaches?

Thanks.

like image 369
Matt Avatar asked Oct 09 '12 17:10

Matt


2 Answers

Here is a kludge that does what you want . . .

map = java.util.HashMap;    
key = java.util.Vector;

matKey = 1:3;
for nn=1:numel(matKey)  
    key.add(matKey(nn));
end

map.put(key,zeros(2,1));
map.get(key)

..it is a starting point anyway.

like image 61
learnvst Avatar answered Sep 22 '22 16:09

learnvst


I compared containers.Map with char keys (thanks to Andrew Janke) to java.util.HashMap with a wrapper object as key (as in this post, also thanks to Andrew Janke, and thanks to Rasman for pointing it out):

numvec = 10^5;
S = round(rand(numvec,10)*40);

matmap = containers.Map();
%pick a random vector
idx = ceil(rand()*numvec);
s1 = S(idx,:);

%put it in the map
matmap(char(s1)) = zeros(1,4);
for i=1:5*10^5

  if i==10^3 tic; end %allow some time for getting up to speed before timing

  %pick a random vector and put it in the map
  idx = ceil(rand()*numvec);
  s2 = S(idx,:);
  matmap(char(s2)) = zeros(1,4);

  %retrieve value of previous vector
  v = matmap(char(s1));

  %modify it randomly and put it back
  v( ceil(rand()*4) ) = rand();
  matmap(char(s1)) = v;

  s1 = s2;
end
toc

javaaddpath('/Test/bin');
import test.ArrayKey;
javmap = java.util.HashMap;

idx = ceil(rand()*numvec);
s1 = S(idx,:);

%also convert value to ArrayKey so we can retrieve it by ref -- saves a put
%operation
javmap.put(ArrayKey(s1), ArrayKey(zeros(1,4)));
for i=1:5*10^5

  if i==10^3 tic; end

  idx = ceil(rand()*numvec);
  s2 = S(idx,:);
  javmap.put(ArrayKey(s2), ArrayKey(zeros(1,4)));
  v = javmap.get(ArrayKey(s1));
  v.x( ceil(rand()*4) ) = rand();
  s1 = s2;
end
toc

Result:

>> testmaps
Elapsed time is 58.600282 seconds.
Elapsed time is 97.617556 seconds.

containers.Map is the winner.


Edit: I reran the test for numvec = 10^6 and everything else the same. containers.Map approach ran in 59 seconds. HashMap approach wasn't finished after 5 minutes and caused Matlab to become unresponsive.


Edit2: I also tried pre-allocating two separate matrices and find keys using ismember. Performance was worse than HashMap.

like image 31
Matt Avatar answered Sep 22 '22 16:09

Matt