Este posibil să convertiți matricea C # dublă [] pentru a dubla [] fără a face o copie

Am matrice mari de numere 3D în aplicația .NET. Trebuie să le convertesc într-o matrice 1D pentru al transmite într-o bibliotecă COM. Există o modalitate de a converti matricele fără a face o copie a tuturor datelor?

Pot face această conversie, dar apoi folosesc de două ori cantitatea de memorie care este o problemă în cererea mea:

  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

5 răspunsuri

Din păcate, matricele C# nu sunt garantate că sunt în memorie contiguă ca și cum ar fi în limbile apropiate de metal, cum ar fi C. Deci, nu. Nu există nicio modalitate de a converti dublu [] pentru a dubla [] fără o copie element-cu-element.

0
adăugat

Fără cunoașterea detaliilor bibliotecii dvs. COM, m-aș uita la crearea unei clase de fațadă în .Net și expunerea la COM, dacă este necesar.
Fața ta va avea un dublu [] și va avea un indexer care va hărți de la [] la [].

Editați: Sunt de acord cu punctele din comentarii, sugestia Lorens este mai bună.

0
adăugat
Acest lucru nu va funcționa. COM va avea nevoie de pentru a avea matricea literală dublă []. Dacă doriți, creați o clasă .NET care a făcut dublul [] să acționeze ca un dublu [].
adăugat autor Jonathan Rupp, sursa

Ca soluție, puteți face o clasă care să păstreze matricele într-o formă dimensională (poate chiar mai aproape de forma metalică goală, astfel încât să puteți trece cu ușurință în biblioteca COM?) Și apoi să supraîncărcați operatorul [] din această clasă pentru ao face utilizabilă ca o matrice multidimensională în codul tău C #.

0
adăugat

Nu cred că modul în care C# stochează acele date în memorie ar face posibilă în același mod în care ar fi o distribuție simplă în C. De ce să nu folosiți o matrice 1d pentru a începe și, probabil, să faceți o clasă pentru tipul, astfel încât să puteți accesa în programul dvs. ca și cum ar fi o matrice 3d?

0
adăugat

Luați în considerare abstractizarea accesului la date cu un Proxy (similar cu iteratorii/indicatorii inteligenți în C ++) . Din păcate, sintaxa nu este la fel de curată ca C ++ ca operatorul (), care nu este disponibil pentru suprasarcină, iar operatorul [] este un singur arg, dar încă aproape.

Desigur, acest nivel suplimentar de abstractizare adaugă complexitatea și activitatea proprie, dar vă va permite să efectuați modificări minime ale codului existent care utilizează obiecte duble [], permițându-vă să folosiți o singură matrice dublă [] pentru ambele interop și calculul dvs. în 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()
}

Apoi, folosind acest tip atât pentru citire cât și pentru scriere - "foo [1,2,3]" este acum scris ca "foo.Elem (1,2,3) .Value", atât în ​​valorile citirii, cât și în valorile de scriere, pe partea stângă a expresiilor de atribuire și valori.

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;
    }
}

Din nou, au fost adăugate costuri de dezvoltare, dar au fost împărțite date, eliminându-se cheltuielile generale de copiere și costurile de dezvoltare aferente. E un compromis.

0
adăugat