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

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

  •  01-07-2019
  •  | 
  •  

Pergunta

Eu tenho grandes matrizes 3D de números em meu aplicativo .NET. Eu preciso convertê-los em 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 o dobro do ammount de memória, que é um problema em meu aplicativo:

  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;
Foi útil?

Solução

Eu não acredito que o # lojas caminho C que os dados na memória tornaria viável da mesma forma um elenco simples em C faria. Por que não usar uma matriz 1d para começar e talvez fazer uma classe para o tipo que você possa acessá-lo em seu programa como se fosse uma matriz 3d?

Outras dicas

Infelizmente, C matrizes # não são garantidos para a memória contígua como eles estão em línguas aproximar-to-the-metal como C. Assim, não. Não há nenhuma maneira de converter double [,,] para duplicar [] sem uma cópia elemento por elemento.

Considere abstrair acesso aos dados com um Proxy (semelhante ao iterators / smart-ponteiros em C ++). Infelizmente, a sintaxe não é tão limpo como C ++ como operador () não disponível para a sobrecarga e o operador [] é único-arg, mas ainda próximo.

É claro, este nível extra de abstração adiciona complexidade e obra de seu próprio, mas seria permitir que você faça alterações mínimas no código existente que usa double [,,] objetos, permitindo que você use um único double [] matriz para ambos interoperabilidade e sua in-C # computação.

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, usar esse tipo de ler e escrever - 'foo [1,2,3]' está agora escrito como 'foo.Elem (1,2,3) .Value', em ambos os valores de leitura e escrita valores, no 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;
    }
}

Os custos de desenvolvimento Novamente, adicionados, mas compartilha dados, removendo copiar sobrecarga e copiando os custos developtment relacionados. É uma troca.

Como alternativa, você poderia fazer uma classe que mantém a matriz de uma forma dimensional (talvez até mais perto de descobrir forma de metal para que possa passá-lo facilmente para a biblioteca COM?) E, em seguida, operador de sobrecarga [] sobre esta classe para torná-lo utilizável como uma matriz multidimensional em seu código C #.

Sem saber detalhes de sua biblioteca COM, eu olhar para a criação de uma classe de fachada em .Net e expô-lo a COM, se necessário.
Sua fachada levaria um duplo [,,] e têm um indexador que irá mapear a partir de [] para [,,].

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top