É possível converter o array C # double [] para double [] sem fazer uma cópia

Eu tenho enormes matrizes 3D de números no meu aplicativo .NET. Eu preciso convertê-los para uma matriz 1D para passá-lo para uma biblioteca COM. Existe uma maneira de converter a matriz sem fazer uma cópia de todos os dados?

Eu posso fazer a conversão assim, mas então eu uso duas vezes a quantidade de memória que é um problema na minha aplicação:

  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
adicionado
Visualizações: 6

5 Respostas

Infelizmente, não é garantido que os arrays C# estejam na memória contígua, como em linguagens mais próximas do metal, como C. Portanto, não. Não há como converter double [] para double [] sem uma cópia elemento por elemento.

0
adicionado

Sem saber detalhes de sua biblioteca COM, eu iria olhar para criar uma classe de fachada no .net e expondo a COM, se necessário.
Sua fachada tomaria um duplo [] e teria um indexador que mapearia de [] para [].

Edit: Concordo com os pontos feitos nos comentários, a sugestão de Lorens é melhor.

0
adicionado
Eu não sou capaz de alterar a biblioteca COM.
adicionado o autor Hallgrim, fonte
Isso não vai funcionar. COM precisará para ter o array literal double []. Se qualquer coisa, você quereria criar uma classe de .NET que fez o duplo [] agir como um duplo [].
adicionado o autor Jonathan Rupp, fonte

Como solução alternativa, você poderia criar uma classe que mantenha a matriz em uma forma dimensional (talvez até mais próxima da forma bare metal para que você possa transmiti-la facilmente à biblioteca COM?) E sobrecarregar o operador desta classe para torná-la utilizável. como um array multidimensional no seu código C #.

0
adicionado

Eu não acredito que o modo como o C# armazena esses dados na memória tornaria viável da mesma maneira que um simples elenco em C faria. Por que não usar uma matriz 1d para começar e talvez criar uma classe para o tipo, para que você possa acessá-la em seu programa como se fosse uma matriz 3D?

0
adicionado

Considere abstrair o acesso aos dados com um Proxy (semelhante aos iteradores/smart-pointers em C ++) . Infelizmente, a sintaxe não é tão limpa quanto C ++ como operator() não disponível para sobrecarga e operator [] é single-arg, mas ainda está próximo.

Naturalmente, esse nível extra de abstração adiciona complexidade e trabalho próprio, mas permitiria que você fizesse alterações mínimas no código existente que usa objetos double [], permitindo que você use um único array [] duplo para ambos interoperabilidade e sua computação in-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()
}

E, em seguida, usando esse tipo para ler e escrever - 'foo [1,2,3]' agora é escrito como 'foo.Elem (1,2,3) .Value', em valores de leitura e valores de escrita, em lado esquerdo das expressões de atribuição e 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;
    }
}

Mais uma vez, adicionamos custos de desenvolvimento, mas compartilhamos dados, removendo a sobrecarga de cópia e copiando os custos de desenvolvimento relacionados. É uma troca.

0
adicionado