Ordem principal de linha e de coluna

Na computação, ordem principal de linha e ordem principal de coluna são métodos para armazenar arranjos multidimensionais em armazenamento linear, como no caso da memória de acesso aleatório.

Ilustração da diferença entre a ordem principal de linha e de coluna

A diferença entre as ordens reside em quais elementos de um arranjo são contíguos na memória. Na ordem principal de linha, os elementos consecutivos de uma linha residem um ao lado do outro, enquanto o mesmo se aplica a elementos consecutivos de uma coluna na ordem principal de coluna. Enquanto os termos aludem à linhas e colunas de um arranjo bidimensional, ou seja, uma matriz, as ordens podem ser generalizadas para arranjos de qualquer dimensão, observando que os termos pricipal de linha e principal de coluna são equivalentes, respectivamente, a ordens lexicográficas e colexicográficas.

O layout de dados é crítico para a transmissão correta de arranjos entre programas escritos em diferentes linguagens de programação. Ele também é importante para o desempenho ao percorrer um arranjo, porque as CPUs modernas processam dados sequenciais com mais eficiência do que dados não sequenciais. ​Isso se deve principalmente ao armazenamento em cache da CPU, que explora a localidade espacial de referência.[1] Além disso, o acesso contíguo possibilita o uso de instruções SIMD que operam sobre vetores de dados. Em algumas mídias, como fitas ou memórias flash NAND, o acesso sequencial é mais rápido, em ordens de magnitude, do que o acesso não sequencial.[carece de fontes?]

Explicação e exemplo editar

Os termos principal de linha e principal de coluna derivam da terminologia relacionada à ordenação de objetos. Uma maneira geral de ordenar objetos com muitos atributos é primeiro agrupá-los e ordená-los por um atributo e, em seguida, dentro de cada grupo, agrupá-los e ordená-los por outro atributo, etc. Se mais de um atributo participa do pedido, o primeiro seria denominado principal e o último secundário. Se dois atributos participam do pedido, é suficiente nomear apenas o atributo principal.

No caso de arranjos, os índices ao longo de cada dimensão são os atributos. Para matrizes em notação matemática, o primeiro índice indica a linha, e o segundo indica a coluna. Por exemplo, dada uma matriz  ,   está em sua primeira linha e segunda coluna. Esta convenção é transportada para a sintaxe em linguagens de programação,[2] embora, frequentemente, com índices começando em 0 (em vez de 1).[3]

Mesmo que a linha seja indicada no primeiro e a coluna no segundo (do índice), nenhuma ordem de agrupamento entre as dimensões está implícita nisso. A escolha de como agrupar e ordenar os índices, seja pelos métodos principais de linha ou de coluna, é, portanto, uma questão de convenção. A mesma terminologia pode ser aplicada a arranjos dimensionais ainda mais altos. O agrupamento principal de linha começa no índice "mais à esquerda" e o principal de coluna "mais à direita", levando, respectivamente, à ordens lexicográficas e colexicográficas (ou colex).

Por exemplo, o arranjo

 

pode ser armazenado de duas maneiras possíveis:

Endereço Ordem principal de linha Ordem principal de coluna
0    
1    
2    
3    
4    
5    

Diferentes linguagens de programação lidam com isso de maneiras diferentes. Em C, os arranjos multidimensionais são armazenados na ordem principal de linha e os índices do arranjo são escritos primeiro em linha (ordem de acesso lexicográfico):

C: ordem principal de linha (ordem de acesso lexicográfico), indexação baseada em zero
Endereço Acesso Valor
0 A[0][0]  
1 A[0][1]  
2 A[0][2]  
3 A[1][0]  
4 A[1][1]  
5 A[1][2]  

Por outro lado, em Fortran, os arranjos são armazenados na ordem principal de coluna, enquanto os índices do arranjo ainda são escritos, primeiro, em linha (ordem de acesso colexicográfico):

Fortran: ordem principal de coluna (ordem de acesso colexicográfico), indexação baseada em um
Endereço Acesso Valor
1 A(1,1)  
2 A(2,1)  
3 A(1,2)  
4 A(2,2)  
5 A(1,3)  
6 A(2,3)  

Observe como o uso de A[i][j] com indexação de várias etapas (como em C) em vez de uma notação neutra como A(i,j) (como em Fortran), quase que inevitavelmente, implica em ordem principal de linha por razões sintáticas, por assim dizer, porque pode ser reescrito como (A[i])[j],e a parte da linha, A[i], pode até mesmo ser atribuída à uma variável intermediária que é, então, indexada em uma expressão separada. Nenhuma outra implicação deve ser assumida. Por exemplo, Fortran não é principal de coluna simplesmente "por causa" de sua notação e mesmo a implicação acima poderia ser intencionalmente contornada em uma nova linguagem.

Para usar a ordem principal de coluna em um ambiente de ordem principal de linha (ou vice-versa), por qualquer motivo, uma solução alternativa é atribuir funções não convencionais aos índices (usando o primeiro índice para a coluna e o segundo índice para a linha) e outra é contornar a sintaxe da linguagem computando explicitamente as posições em um arranjo unidimensional. Obviamente, o desvio da convenção provavelmente incorre em um custo que aumenta o grau de interação necessária com os recursos da linguagem e outros códigos, não apenas na forma de maior vulnerabilidade à erros (esquecendo também de inverter a ordem de multiplicação da matriz, revertendo para a convenção durante manutenção de código, etc.) mas também na forma de ter que reorganizar ativamente os elementos (todos os quais devem ser "pesados" em relação à qualquer propósito original, como aumentar o desempenho). A execução do loop por linha é preferível em linguagens principais de linha, como C, e vice-versa para linguagens principais de coluna.

Linguagens de programação e bibliotecas editar

Linguagens de programação ou suas bibliotecas padrão que oferecem suporte a arranjos multidimensionais, normalmente, têm uma ordem de armazenamento principal de linha ou coluna nativa para esses arranjos.

A ordem principal de linha é usada em C/C++/Objective-C (para arranjos de estilo C), PL/I,[4] Pascal​[5], Speakeasy[carece de fontes?], SAS[6] e Rasdaman[7].

A ordem principal de coluna é usada em Fortran, MATLAB,[8] GNU Octave, S-PLUS,[9] R,[10] Julia,[11] e Scilab.[12]

Nem principal de linha nem de coluna editar

Uma alternativa típica para armazenamento de arranjo densa é usar vetores Iliffe, que normalmente armazena elementos na mesma linha de forma contígua (como a ordem principal de linha), mas não as próprias linhas. Eles são usados em (ordenados por idade): Java[13], C#/CLI/.Net, Scala[14] e Swift.

Ainda menos denso é usar listas de listas, por exemplo, em Python [15] e na Wolfram do Mathematica'"[16].

Uma abordagem alternativa usa tabelas de tabelas, por exemplo, em Lua[17].

Bibliotecas externas editar

O suporte para arranjos multidimensionais também pode ser fornecido por bibliotecas externas, que podem até mesmo suportar ordenações arbitrárias, em que cada dimensão tem um valor de passo e principal de linha ou de coluna são apenas duas interpretações resultantes possíveis.

A ordem principal de linha é o padrão em NumPy [18] (para Python).

A ordem principal de coluna é o padrão em Eigen [19] e Armadillo (ambas para C++).

Um caso especial seria o OpenGL (e o OpenGL ES) para processamento gráfico. Uma vez que "tratamentos matemáticos recentes de álgebra linear e campos relacionados invariavelmente tratam vetores como colunas", o designer Mark Segal decidiu substituir isso pela convenção do predecessor IRIS GL (que era escrever vetores como linhas). Para compatibilidade, matrizes de transformação ainda seriam armazenadas em principal de vetor (o mesmo que principal de linha) em vez de ordem principal de coordenada (o mesmo que principal de coluna) e ele então usou o truque "[para] dizer que matrizes em OpenGL são armazenadas em ordem principal de coluna". [20] Isso era realmente relevante apenas para apresentação, porque a multiplicação da matriz era baseada em pilha e ainda podia ser interpretada como pós-multiplicação mas a realidade vazou através da API baseada em C porque os elementos individuais seriam acessados como M[vetor][coordenada] ou, efetivamente, como M[coluna][linha] (que infelizmente confundiu a convenção que o designer procurou adotar) e isso foi até preservado na OpenGL Shading Language que foi adicionada posteriormente (embora isso também possibilite acessar coordenadas por nome, por exemplo, M[vetor].y). Como resultado, muitos desenvolvedores agora simplesmente declararão que ter a coluna como o primeiro índice é a definição principal de coluna, embora este claramente não seja o caso com uma linguagem principal de coluna real como o Fortran.

Torch (para Lua) mudou a ordem padrão de principal de coluna[21] para principal de linha[22].

Transposição editar

Como a troca dos índices de um arranjo é a essência da transposição de arranjo, um arranjo armazenado como principal de linha, mas lido como principal de coluna (ou vice-versa), aparecerá transposto (desde que a matriz seja quadrada). Como realizar esse rearranjo na memória costuma ser uma operação cara, alguns sistemas oferecem opções para especificar matrizes individuais como sendo armazenadas transpostas. O programador deve, então, decidir se reorganiza ou não os elementos na memória, com base no uso real (incluindo o número de vezes que o arranjo é reutilizado em um cálculo).

Por exemplo, as funções BLAS recebem sinalizadores que indicam quais arranjos são transpostos[23].

Cálculo de endereço em geral editar

O conceito se generaliza para arranjos com mais de duas dimensões.

Para um arranjo d-dimensional   com dimensões Nk (k=1...d), um determinado elemento deste arranjo é especificado por uma tupla   de índices d (base zero)  .

Na ordem principal de linha , a última dimensão é contígua, de modo que o deslocamento da memória deste elemento é dado por:

 

Na ordem principal de coluna , a primeira dimensão é contígua, de modo que o deslocamento da memória deste elemento é dado por:

 

onde o produto vazio é o elemento de identidade multiplicativo, ou seja, .

Para uma determinada ordem, o "dar passos longos" na dimensão k é dado pelo valor de multiplicação entre parênteses antes do índice n k nos somatórios do lado direito acima.

De forma mais geral, há "d!" ordens possíveis para um determinada arranjo, uma para cada permutação de dimensões (com principal de linha e ordem de coluna apenas 2 casos especiais), embora as listas de valores de passo não sejam necessariamente permutações entre si, por exemplo, no exemplo 2 por 3 acima, os avanços são (3,1) para principal de linha e (1,2) para principal de coluna.

Ver também editar

Referências

  1. «Cache memory» [Memória cache]. Peter Lars Dordal (em inglês). Consultado em 5 de maio de 2021 
  2. «Arrays and formatted I/O» [E/S formatadas e matrizes]. FORTRAN Tutorial (em inglês). Consultado em 5 de maio de 2021 
  3. «Why numbering should start at zero?» [Por que a numeração deve começar do zero?]. E. W. Dijkstra archive (em inglês). Consultado em 4 de maio de 2021 
  4. «Language reference version 4 release 3» [Referência de linguagem versão 4 liberação 3] (PDF) (em inglês). IBM. Consultado em 6 de maio de 2021. Os valores iniciais especificados para um arranjo são atribuídos a elementos sucessivos da arranjo na ordem principal de linha (o subscrito final varia mais rapidamente). [ligação inativa] 
  5. «ISO/IEC 7185:1990(E)» (PDF) (em inglês). Consultado em 6 de maio de 2021. Um tipo de arranjo que especifica uma sequência de dois ou mais tipos de índice deve ser uma notação abreviada para um tipo de arranjo especificado para ter como seu tipo de índice o primeiro tipo de índice na sequência e ter um tipo de componente que é um tipo de arranjo especificando a sequência de tipos de índice sem o primeiro tipo de índice na sequência e especificando o mesmo tipo de componente da especificação original. 
  6. «SAS® 9.4 language reference: Concepts, sixth edition» [Referência de linguagem SAS® 9.4: Conceitos, sexta edição] (PDF) (em inglês). SAS Institute Inc. 6 de setembro de 2017. p. 573. Consultado em 6 de maio de 2021. Da direita para a esquerda, a dimensão mais à direita representa as colunas e a próxima dimensão representa as linhas. O SAS coloca as variáveis em um arranjo multidimensional, preenchendo todas as linhas em ordem, começando no canto superior esquerdo do arranjo (conhecido como ordem principal de linha). 
  7. «Internal array representation in rasdaman» [Representação de arranjo interno em rasdaman]. rasdaman.org (em inglês). Consultado em 6 de maio de 2021 
  8. «MATLAB Data storage» [Armazenamento de dados MATLAB]. Documentação MATLAB. Mathworks.co.uk. Consultado em 6 de maio de 2021 
  9. Spiegelhalter et al. (2003, p. 17): Spiegelhalter, David; Thomas, Andrew; Best, Nicky; Lunn, Dave (janeiro de 2003), «Formatação de dados: formato S-Plus», WinBUGS user manual [Manual do usuário WinBUGS] (PDF) (em inglês) versão 1.4 ed. , Cambridge, Reino Unido: Unidade de bioestatística MRC, Instituto de saúde pública, arquivado do original (PDF) em 18 de maio de 2003 
  10. «An introduction to R - section 5.1: Arrays» [Uma introdução ao R - seção 5.1: Arranjos] (em inglês). Consultado em 6 de maio de 2021 
  11. «Multi-dimensional arrays» [Arranjos multidimensionais]. Julia (em inglês). Consultado em 6 de maio de 2021 
  12. «FFTs with multidimensional data» [FFTs com dados multidimensionais]. Scilab Wiki (em inglês). Consultado em 6 de maio de 2021. Como o Scilab armazena arranjos no formato principal de coluna, os elementos de uma coluna são adjacentes (ou seja, uma separação de 1) no formato linear. 
  13. «Java language specification» [Especificação da linguagem Java] (em inglês). Oracle. Consultado em 6 de maio de 2021 
  14. «object array» [arranjo de objetos]. Scala standard library (em inglês). Consultado em 6 de maio de 2021 
  15. «The Python standard library: 8. Data types» [A biblioteca padrão Python: 8. Tipos de dados] (em inglês). Consultado em 6 de maio de 2021 
  16. «Vectors and matrices» [Vetores e matrizes]. Wolfram (em inglês). Consultado em 6 de maio de 2021 
  17. «11.2 – Matrices and multi-dimensional arrays» [11.2 - Matrizes e arranjos multidimensionais] (em inglês). Consultado em 6 de maio de 2021 
  18. «The N-dimensional array (ndarray)» [O arranjo n-dimensional (ndarray)]. SciPy.org (em inglês). Consultado em 6 de maio de 2021 
  19. «Eigen: Storage orders» [Eigen: Ordens de armazenamento]. eigen.tuxfamily.org (em inglês). Consultado em 6 de maio de 2021. Se a ordem de armazenamento não for especificada, o padrão do Eigen é armazenar a entrada em principal de coluna 
  20. «Column vectors versus row vectors» [Vetores de coluna versus vetores de linha] (em inglês). Consultado em 6 de maio de 2021 
  21. «Tensor» (em inglês). Consultado em 6 de maio de 2021 
  22. «Tensor». Torch Package Reference Manual (em inglês). Consultado em 6 de maio de 2021 
  23. «BLAS (basic linear algebra subprograms)» [BLAS (subprogramas básicos de álgebra linear)] (em inglês). Consultado em 6 de maio de 2021 

Fontes editar