Es posible convertir C # double [] array a double [] sin hacer una copia

Tengo enormes matrices en 3D de números en mi aplicación .NET. Necesito convertirlos a una matriz 1D para pasarlos 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 la cantidad de memoria que 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;
0
agregado
Puntos de vista: 1

5 Respuestas

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

0
agregado

Sin conocer los detalles de su biblioteca COM, me gustaría crear una clase de fachada en .Net y exponerla a COM, si es necesario.
Su fachada tomaría un doble [] y un indexador que se correlacionará desde [] a [].

Editar: Estoy de acuerdo con los puntos que se hicieron en los comentarios, la sugerencia de Lorens es mejor.

0
agregado
No puedo cambiar la biblioteca COM.
agregado el autor Hallgrim, fuente
Esto no funcionará COM necesitará para tener la matriz literal doble []. En todo caso, querrá crear una clase .NET que haga que el doble [] actúe como un doble [].
agregado el autor Jonathan Rupp, fuente

Como solución alternativa, puede crear una clase que mantenga la matriz en una forma dimensional (tal vez incluso en forma más cercana al metal desnudo para que pueda pasarla fácilmente a la biblioteca COM) y luego sobrecargar al operador [] en esta clase para que sea utilizable como una matriz multidimensional en tu código C #.

0
agregado

No creo que la forma en que C# almacene esos datos en la memoria lo haga factible de la misma manera que lo haría un elenco simple en C. ¿Por qué no utilizar una matriz 1d para comenzar y tal vez crear una clase para el tipo para que pueda acceder a ella en su programa como si fuera una matriz 3D?

0
agregado

Considere la posibilidad de abstraer el acceso a los datos con un Proxy (similar a iterators/smart-pointers en C ++) . Desafortunadamente, la sintaxis no es tan limpia como C ++ ya que el operador() no está disponible para sobrecargar y el operador [] es de un solo arg, pero aún está cerca.

Por supuesto, este nivel extra de abstracción agrega complejidad y trabajo propio, pero le permite hacer cambios mínimos al código existente que usa objetos dobles [], mientras que le permite usar una sola matriz doble [] para ambos interoperabilidad 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, usando 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 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, se agregaron costos de desarrollo, pero se comparten datos, se eliminan los gastos indirectos de copiado y se copian los costos de desarrollo relacionados. Es una compensación.

0
agregado