2014-10-02 11 views
12

mam dość ciężki funkcję w Matlabnajczystszym sposobem buforować wyniki funkcji w Matlab

funkcję [out] = f (IN1, IN2 IN3)

który nazywa się dość często z te same parametry. Funkcja jest deterministyczna, więc dla podanych parametrów wejściowych jej wynik będzie zawsze taki sam.

Jaki byłby najprostszy sposób przechowywania wyników obliczonych danych wejściowych w funkcji tak, że gdyby funkcja została ponownie wywołana z tym samym wyjściem, byłaby w stanie szybko odpowiedzieć?


jest trwałe zmienna który odwzorowuje (używając containers.Map lub jakiś inna klasa) wejście ustawiony rezultacie droga?


(Każda metoda, która wymaga zapisywania danych na dysku jest wykluczone w mojej aplikacji).

+0

zobaczyć http://stackoverflow.com/questions/9284130/caching-matlab-function-results-to-file – marsei

+0

Widziałem, że (i zasugerował to w pytaniu), ale Problem polega na tym, że nie mogę znaleźć rozsądnego sposobu na spakowanie 3 argumentów wejściowych, aby pasował do tej klasy. –

+0

jakiego typu są twoje trzy wejścia? czy to są skalary? wektor? matryce? jaki jest ich normalny zakres wartości? Ile wartości chcesz przechowywać w pamięci podręcznej? – Shai

Odpowiedz

5

Trwała mapa jest rzeczywiście dobrym sposobem na wdrożenie wyników z pamięci podręcznej. Korzyści, które mogę wymyślić:

  • Nie ma potrzeby stosowania funkcji mieszania dla każdego typu danych.
  • Macierze Matlab są kopiowane w zapisie, co może zapewnić pewną wydajność pamięci.
  • Jeśli użycie pamięci jest problemem, można kontrolować liczbę wyników w pamięci podręcznej.

Istnieje przesyłanie plików wymiany, A multidimensional map class David Young, pochodzi z funkcją memoize() robi dokładnie to. Jego implementacja wykorzystuje nieco inny mechanizm (odwołanie do zmiennej lokalnej), ale idea jest prawie taka sama. W porównaniu z trwałą mapą wewnątrz każdej funkcji, ta funkcja memoize() umożliwia pamiętanie istniejącej funkcji bez modyfikacji. I jak zauważył Oleg, użycie DataHash (lub odpowiednika) może jeszcze bardziej zmniejszyć zużycie pamięci.

PS: Użyłem klasy MapN w sposób rozległy i jest całkiem niezawodny. Właściwie przesłałem raport o błędzie, a autor natychmiast go naprawił.

+0

Dodanie DataHash do 'memoize()' powinno zmniejszyć ślad pamięci. – Oleg

+0

To jest bardzo dobry punkt i na pewno prawda. Wyłączenie wydajności polega na tym, że funkcja mieszająca będzie musiała być oceniona na wszystkich wejściach na każde połączenie. Domyślam się, że będzie szybciej zależy od konkretnego przypadku użycia i wydajności funkcji skrótu. – xmo

6

Poniżej jest pomysł dla klasy CacheableFunction

  • Wydaje się wszystkie odpowiedzi do głównego pytania są skierowane w tym samym kierunku - trwałe Mapa jest drogą konsensusu do wyników cache, i zrobić to zbyt .
  • Jeśli dane wejściowe są tablicami, należy je wprowadzić do łańcucha lub skalaru, który będzie używany jako klucz mapy. Istnieje wiele sposobów na mieszanie twoich 3 tablic wejściowych z kluczem, użyłem DataHash w moim poniższym rozwiązaniu.
  • Zdecydowałem się uczynić z niego klasę, a nie funkcję taką jak memoize, aby wejściowa funkcja mieszająca mogła być dynamicznie określona jednorazowo, a nie na stałe.
  • W zależności od formy wydruku używa również dzip/dunzip, aby zmniejszyć ślad zapisanych wyników.
  • Potencjalne udoskonalenie: sprytny sposób decydowania, które elementy usunąć z trwałej mapy, gdy jej ślad pamięci osiąga pewien limit.

definicja klasy

classdef CacheableFunction < handle 
    properties 
     exeFun 
     hashFun 
     cacheMap 
     nOutputs 
     zipOutput 
    end 

    methods 
     function obj = CacheableFunction(exeFun, hashFun, nOutputs) 
      obj.exeFun = exeFun; 
      obj.hashFun = hashFun; 
      obj.cacheMap = containers.Map; 
      obj.nOutputs = nOutputs; 
      obj.zipOutput = []; 
     end 

     function [result] = evaluate(obj, varargin) 

      thisKey = obj.hashFun(varargin); 

      if isKey(obj.cacheMap, thisKey) 
       if obj.zipOutput 
        result = cellfun(@(x) dunzip(x), obj.cacheMap(thisKey), 'UniformOutput', false); 
       else 
        result = obj.cacheMap(thisKey); 
       end 
      else 
       [result{1:obj.nOutputs}] = obj.exeFun(varargin); 

       if isempty(obj.zipOutput) 
        obj.zipCheck(result); 
       end 

       if obj.zipOutput 
        obj.cacheMap(thisKey) = cellfun(@(x) dzip(x), result, 'UniformOutput', false); 
       else 
        obj.cacheMap(thisKey) = result; 
       end 
      end 
     end 


     function [] = zipCheck(obj,C) 
      obj.zipOutput = all(cellfun(@(x) isreal(x) & ~issparse(x) & any(strcmpi(class(x), ... 
       {'double','single','logical','char','int8','uint8',... 
       'int16','uint16','int32','uint32','int64','uint64'})), C)); 
     end 

    end 
end 

Testowanie go ...

function [] = test_caching_perf() 

A = CacheableFunction(@(x) long_annoying_function(x{:}), @(x) DataHash(x), 3); 

B = rand(50, 50); 
C = rand(50, 50); 
D = rand(50, 50); 

tic; 
myOutput = A.evaluate(B, C, D); 
toc 

tic; 
myOutput2 = A.evaluate(B, C, D); 
toc 

cellfun(@(x, y) all(x(:) == y(:)), myOutput, myOutput2) 

end 

function [A, B, C] = long_annoying_function(A, B, C) 

    for ii = 1:5000000 
     A = A+1; 
     B = B+2; 
     C = C+3; 
    end 
end 

a wyniki

>> test_caching_perf 
Elapsed time is 16.781889 seconds. 
Elapsed time is 0.011116 seconds. 
ans = 
    1  1  1 
+0

Wybierane przez ciebie konwencje nazewnictwa są nieco niezgrabne, a opis na początku nieco gęsty, w przeciwnym razie ta odpowiedź zasługiwałaby na więcej uwagi. – Oleg

Powiązane problemy