¿Es posible convertir la matriz C# double[,,] a double[] sin hacer una copia?

StackOverflow https://stackoverflow.com/questions/96054

  •  01-07-2019
  •  | 
  •  

Pregunta

Tengo enormes conjuntos de números en 3D en mi aplicación .NET.Necesito convertirlos a una matriz 1D para pasarla a una biblioteca COM.¿Hay alguna manera de convertir la matriz sin hacer una copia de todos los datos?

Puedo hacer la conversión de esta manera, pero luego uso el doble de memoria, lo cual es un problema en mi aplicación:

  double[] result = new double[input.GetLength(0) * input.GetLength(1) * input.GetLength(2)];
  for (i = 0; i < input.GetLength(0); i++) 
    for (j = 0; j < input.GetLength(1); j++) 
      for (k = 0; k < input.GetLength(2); k++) 
        result[i * input.GetLength(1) * input.GetLength(2) + j * input.GetLength(2) + k)] = input[i,j,l];
  return result;
¿Fue útil?

Solución

No creo que la forma en que C# almacena esos datos en la memoria lo haga factible de la misma manera que lo haría una conversión simple en C.¿Por qué no utilizar una matriz 1d para empezar y quizás crear una clase para el tipo para poder acceder a ella en su programa como si fuera una matriz 3d?

Otros consejos

Desafortunadamente, no se garantiza que las matrices de C# estén en memoria contigua como lo están en lenguajes más cercanos al metal como C.Entonces no.No hay forma de convertir double[,,] en double[] sin una copia elemento por elemento.

Considere abstraer el acceso a los datos con un Apoderado (similar a iteradores/punteros inteligentes en C++).Desafortunadamente, la sintaxis no es tan limpia como la de C++, ya que operator() no está disponible para sobrecargar y operator[] tiene un solo argumento, pero aún así está cerca.

Por supuesto, este nivel adicional de abstracción agrega complejidad y trabajo propio, pero le permitiría realizar cambios mínimos en el código existente que usa objetos double[,,], al mismo tiempo que le permite usar una única matriz double[] para ambos. interop y su cálculo en C#.

class Matrix3
{
    // referece-to-element object
    public struct Matrix3Elem{
        private Matrix3Impl impl;
        private uint dim0, dim1, dim2;
        // other constructors
        Matrix3Elem(Matrix3Impl impl_, uint dim0_, uint dim1_, uint dim2_) {
            impl = impl_; dim0 = dim0_; dim1 = dim1_; dim2 = dim2_;
        }
        public double Value{
            get { return impl.GetAt(dim0,dim1,dim2); }
            set { impl.SetAt(dim0, dim1, dim2, value); }
        }
    }

    // implementation object
    internal class Matrix3Impl
    {
        private double[] data;
        uint dsize0, dsize1, dsize2; // dimension sizes
        // .. Resize() 
        public double GetAt(uint dim0, uint dim1, uint dim2) {
            // .. check bounds
            return data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ];
        }
        public void SetAt(uint dim0, uint dim1, uint dim2, double value) {
            // .. check bounds
            data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ] = value;
        }
    }

    private Matrix3Impl impl;

    public Matrix3Elem Elem(uint dim0, uint dim1, uint dim2){
        return new Matrix2Elem(dim0, dim1, dim2);
    }
    // .. Resize
    // .. GetLength0(), GetLength1(), GetLength1()
}

Y luego usar este tipo para leer y escribir: 'foo[1,2,3]' ahora se escribe como 'foo.Elem(1,2,3).Value', tanto en valores de lectura como en valores de escritura, en lado izquierdo de las expresiones de asignación y valor.

void normalize(Matrix3 m){

    double s = 0;
    for (i = 0; i < input.GetLength0; i++)     
        for (j = 0; j < input.GetLength(1); j++)       
            for (k = 0; k < input.GetLength(2); k++)
    {
        s += m.Elem(i,j,k).Value;
    }
    for (i = 0; i < input.GetLength0; i++)     
        for (j = 0; j < input.GetLength(1); j++)       
            for (k = 0; k < input.GetLength(2); k++)
    {
        m.Elem(i,j,k).Value /= s;
    }
}

Nuevamente, agrega costos de desarrollo, pero comparte datos, eliminando los gastos generales de copia y los costos de desarrollo relacionados con la copia.Es una compensación.

Como solución alternativa, podría crear una clase que mantenga la matriz en una forma unidimensional (¿tal vez incluso más cercana a la forma básica para poder pasarla fácilmente a la biblioteca COM?) y luego sobrecargar el operador [] en esta clase para que sea utilizable. como una matriz multidimensional en su código C#.

Sin conocer los detalles de su biblioteca COM, consideraría la posibilidad de crear una clase de fachada en .Net y exponerla a COM, si es necesario.
Su fachada tomaría un doble [,,] y tendría un indexador que se asignará de [] a [,,].

Editar:Estoy de acuerdo con los puntos planteados en los comentarios, la sugerencia de Loren es mejor.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top