Encontrar compensación que minimiza la diferencia cuadrada entre dos vectores de diferentes tamaños -- ++ campo con performance campo con memoization camp codereview Relacionados El problema

Find offset that minimizes squared difference between two vectors of different size


2
vote

problema

Español

Estoy trabajando en un proyecto donde el punto de acceso es un código que se supone que debe encontrar un desplazamiento, de modo que las diferencias cuadradas entre un vector de referencia y un vector determinado se vuelva mínimo. La función central es esta:

  #include <vector> #include <map> typedef std::vector<double> vect_d  double sqDiffSum(const vect_d& ref, const vect_d& x,int offset){     size_t scale = ref.size() / x.size(); // ref.size() is always n*x.size()     double sum = 0;     int counter = 0;     for (size_t i=0;i<x.size();i++){         for (size_t j=0;j<scale;j++){             int bin = i*scale + j - offset;             if (bin >= 0 && bin < (int)ref.size()){                 double diff = ref[bin] - x[i];                 sum += diff * diff;                 counter++;             }         }     }     return sum / counter; }   

Esto se llama desde una rutina de minimización, que (por ahora) no quiero cambiar. Varía el <?xml version="1.0" encoding="utf-8" ?> <Items> <Item Name="Coffee" Cost="10" Image="itemCoffee.png" /> <Item Name="Tea" Cost="10" Image="itemTea.png" /> <Item Name="Vada" Cost="10" Image="itemVada.png" /> </Items> 0 para obtener el mínimo <?xml version="1.0" encoding="utf-8" ?> <Items> <Item Name="Coffee" Cost="10" Image="itemCoffee.png" /> <Item Name="Tea" Cost="10" Image="itemTea.png" /> <Item Name="Vada" Cost="10" Image="itemVada.png" /> </Items> 1 . Sé que probablemente podría hacer la tarea más rápido usando un FFT, pero por ahora quiero ver cuánto puedo salir del enfoque actual. Ya podría hacerlo más rápido (aproximadamente x2.5) agregando alguna memorización:

  <?xml version="1.0" encoding="utf-8" ?> <Items>       <Item Name="Coffee"             Cost="10"             Image="itemCoffee.png" />       <Item Name="Tea"             Cost="10"             Image="itemTea.png" />       <Item Name="Vada"             Cost="10"             Image="itemVada.png" />   </Items> 2  

Sin embargo, sigue siendo demasiado lento. Hay varios puntos que, en principio, podía optimizar, pero para cada uno tengo mis dudas, ya sea que traiga algún beneficio:

  • El vector de referencia <?xml version="1.0" encoding="utf-8" ?> <Items> <Item Name="Coffee" Cost="10" Image="itemCoffee.png" /> <Item Name="Tea" Cost="10" Image="itemTea.png" /> <Item Name="Vada" Cost="10" Image="itemVada.png" /> </Items> 3 es siempre el mismo, por lo que podría evitar pasarlo en absoluto.

  • El tamaño de los vectores es siempre el mismo, por lo que, en realidad, no es necesario que <?xml version="1.0" encoding="utf-8" ?> <Items> <Item Name="Coffee" Cost="10" Image="itemCoffee.png" /> <Item Name="Tea" Cost="10" Image="itemTea.png" /> <Item Name="Vada" Cost="10" Image="itemVada.png" /> </Items> 4 , pero si es posible, me gustaría evitar las matrices de estilo C y no espero demasiado Mejora al no usar vectores aquí.

  • El bucle más íntimo tiene algunas ramas, que podrían evitarse

¿Hay algo que viene a la mente para que esto sea más eficiente? ¿Se supone que los puntos anteriores no valen realmente cambiar mal?

Tenga en cuenta que esto es pre-C ++ 11.

Original en ingles

I am working on a project where the hotspot is some code that is supposed to find an offset, such that the squared differences between a reference vector and a given vector becomes minimal. The core function is this:

#include <vector> #include <map> typedef std::vector<double> vect_d  double sqDiffSum(const vect_d& ref, const vect_d& x,int offset){     size_t scale = ref.size() / x.size(); // ref.size() is always n*x.size()     double sum = 0;     int counter = 0;     for (size_t i=0;i<x.size();i++){         for (size_t j=0;j<scale;j++){             int bin = i*scale + j - offset;             if (bin >= 0 && bin < (int)ref.size()){                 double diff = ref[bin] - x[i];                 sum += diff * diff;                 counter++;             }         }     }     return sum / counter; } 

This is called from some minimization routine, that (for now) I dont want to change. It varies the offset to get the minimum sqDiffSum. I know that I could probably do the task faster by using a FFT, but for now I want to see how much I can get out of the current approach. I could already make it faster (roughly x2.5) by adding some memoization:

double callSqDiffSum(const vect_d& ref, const vect_d& x,int offset,bool firstCall){     static std::map<int,double> memo;     if (firstCall){ memo.clear(); }     else {         std::map<int,double>::iterator found = memo.find(offset);         if (found != memo.end()){             return found->second;         }     }         double result = sqDiffSum(ref,x,offset);     memo[offset] = result;     return result; } 

However, it is still too slow. There are several points that in principle I could optimize, but for each I have my doubts whether it will bring any benefit:

  • The reference vector ref is actually always the same, thus I could avoid passing it around at all.

  • The size of the vectors is always the same, so actually there is no need for std::vector, but if possible I would like to avoid c-style arrays and I dont expect too much improvement by not using vectors here.

  • The innermost loop has some branching, that could be avoided

Is there anything that comes to your mind to make this more efficient? Is my assumption that the above points are not really worth to change wrong?

Please note that this is pre-C++11.

        
     
     

Lista de respuestas

2
 
vote

Sin cambiar el algoritmo, las únicas cosas que puedo ver al echar un vistazo al ensamblaje de sqDiffSum :

  • LEA x[i] Solo una vez en el bucle externo (I.E const double x_i = x[i] y luego use x_i en su lugar). Obtendrá una pequeña victoria al no tener que buscarla cada vez que ingrese el if .
  • Calcular una vez i * scale - offset en el bucle externo porque este invariante. Pero el último GCC y el clang parecen lo suficientemente inteligentes como para resolver esto por sí mismos.

Además, es posible que desee probar std::unordered_map .

Editar: Siempre que bin >= ref.size() , usted sabe que será para todo el siguiente j . Tal vez incluso reemplaza j por x[i]0 ejecutando (antes del café de la mañana) cuando $ offset & gt; = i cdot scale $ y $ frac {i cdot ref _size} {x _size} + offset & lt; ref _size $

 

Without changing the algorithm, the only things I can see by having a look at the assembly of sqDiffSum:

  • read x[i] only once in the outer loop (i.e const double x_i = x[i] and then use x_i instead). You'll get a small win by not having to fetch it whenever you enter the if.
  • compute once i * scale - offset in the outer loop because this invariant. But latest gcc and clang seem smart enough to figure this out themselves.

Also, you might want to test std::unordered_map.

edit: whenever bin >= ref.size(), you know that it will be for all the next j. Maybe you even replace j by bin running (before morning coffee) when \$offset >= i \cdot scale\$ and \$\frac{i \cdot ref\_size}{x\_size} + offset < ref\_size\$

 
 
 
 

Relacionados problema

2  Compruebe la igualdad para cada subconjunto de una cadena S contra la T objetivo y devuelva un conteo  ( Check the equality for each subset of a string s against the target t and return ) 
Escribí el siguiente código para resolver este problema de código de leet : var numDistinct = function(s, t) { if (!s.length) return +(!t.length); ...

8  Generador de caché de Python  ( Python caching generator ) 
¿Es esta la forma correcta de almacenar en caché a un generador en Python, sin la iteración sobre ella de inmediato (por ejemplo, usando 99887776655443316 s...

5  Levenshtein Distancia con los vectores de Haskell y la memoización  ( Levenshtein distance with haskell vectors and memoization ) 
¿Es la siguiente manera efectiva de implementar la distancia Levenshtein con los vectores de Haskell? n3 En particular, ¿debo usar n4 para construir l...

3  decorador de caché  ( Caching decorator ) 
Se me ocurrió un decorador de caché para funciones puras. ¿Está bien? ¿Podría ser mejor / más simple / más rápido? public class Finder { public List<st...

5  Python: patrón de tarjeta salvaje que coincida con la memoización  ( Python wild card pattern matching with memoization ) 
Aquí está mi opinión sobre el patrón de la tarjeta Wild Tarjeta que coincida con la memoización. Agradecería los comentarios sobre la claridad del Código, a...

1  Implementación ingenua de la memorización automática  ( Naive implementation of automatic memoisation ) 
Escribí el código a (ingenuamente) realizar la memorización automática. Intenté escribirlo en un estilo de programación funcional, y así no hizo uso de ningun...

7  Clase de ayuda para memorizar a DaDeformats Ancho a toda la aplicación  ( Helper class to memoize dateformats application wide ) 
premisa Considere el siguiente método: static String formatMyDate(Date date) { return new SimpleDateFormat("yyyy-MM-dd").format(date); } A menudo...

7  Memoizacion elegante  ( Elegant memoizing ) 
Quería una forma elegante de implementar la memorización. Aquí está lo que he encontrado: JPanel0 Es bastante agradable, pero el mapa débil no está bien...

3  Implementación ingenua de un memoiser de caché menos utilizado (LRU)  ( Naive implementation of a least recently used lru cache memoiser ) 
Escribí código a (ingenuamente) Realizar memoisación de LRU. Intenté escribirlo en un estilo de programación funcional, y así no hizo uso de ninguna variable ...

1  Función de memoiza genérica en Swift  ( Generic memoize function in swift ) 
Necesito realizar un cálculo costoso, como determinar un número de FIBONACCI: /// Calculate the Nth Fibonacci number (inefficiently) func fib(n: Int) -> In...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos