En la programación de computadoras , el corte de matriz es una operación que extrae un subconjunto de elementos de una matriz y los empaqueta como otra matriz, posiblemente en una dimensión diferente a la original.
Ejemplos comunes de corte de matriz son extraer una subcadena de una cadena de caracteres, la " ell " en "h ell o", extraer una fila o columna de una matriz bidimensional o extraer un vector de una matriz .
Dependiendo del lenguaje de programación , se puede hacer un segmento de matriz a partir de elementos no consecutivos. También, dependiendo del idioma, los elementos de la nueva matriz pueden tener un alias (es decir, compartir memoria con) los de la matriz original.
Detalles
Para matrices "unidimensionales" (de índice único) (vectores, secuencia, cadenas, etc.), la operación de corte más común es la extracción de cero o más elementos consecutivos. Por lo tanto, si tenemos un vector que contiene elementos (2, 5, 7, 3, 8, 6, 4, 1), y queremos crear un segmento de matriz desde el tercer al sexto elemento, obtenemos (7, 3, 8, 6). En los lenguajes de programación que utilizan un esquema de indexación basado en 0, el segmento sería del índice 2 al 5 .
Reducir el rango de cualquier índice a un solo valor elimina efectivamente ese índice. Esta función se puede utilizar, por ejemplo, para extraer cortes unidimensionales (vectores: en 3D, filas, columnas y tubos [1] ) o cortes bidimensionales (matrices rectangulares) de una matriz tridimensional. Sin embargo, dado que el rango se puede especificar en tiempo de ejecución, los lenguajes con verificación de tipo pueden requerir una notación explícita (en tiempo de compilación) para eliminar realmente los índices triviales.
El corte general de la matriz se puede implementar (esté o no integrado en el lenguaje) haciendo referencia a cada matriz a través de un vector o descriptor de droga , un registro que contiene la dirección del primer elemento de la matriz, y luego el rango de cada índice y el coeficiente correspondiente en la fórmula de indexación. Esta técnica también permite la transposición inmediata de matrices , inversión de índices, submuestreo, etc. Para lenguajes como C , donde los índices siempre comienzan en cero, el vector dope de una matriz con d índices tiene al menos 1 + 2 d parámetros. Para lenguajes que permiten límites inferiores arbitrarios para índices, como Pascal , el vector dope necesita entradas de 1 + 3 d .
Si la abstracción de la matriz no admite índices negativos verdaderos (como, por ejemplo, las matrices de Ada y Pascal lo hacen), a veces se utilizan índices negativos para los límites de la división para una dimensión determinada para especificar un desplazamiento desde el final de la matriz en esa dimensión. En los esquemas basados en 1, -1 generalmente indicaría el penúltimo elemento, mientras que en un sistema basado en 0, significaría el último elemento.
Historia
El concepto de segmentación se conocía seguramente incluso antes de la invención de los compiladores . El corte como característica del lenguaje probablemente comenzó con FORTRAN (1957), más como consecuencia de una verificación de rango y tipo inexistente que por diseño. El concepto también fue aludido en el informe preliminar de la IAL (ALGOL 58) en el sentido de que la sintaxis permitía que uno o más índices de un elemento de matriz (o, para el caso, de una llamada a procedimiento) se omitieran cuando se usaba como un valor real. parámetro.
El APL de Kenneth Iverson (1957) tenía un corte de matriz multidimensional muy flexible, lo que contribuyó mucho al poder expresivo y la popularidad del lenguaje.
ALGOL 68 (1968) introdujo funciones integrales de corte y recorte de matrices multidimensionales.
Se han incorporado funciones de corte de matrices en varios lenguajes modernos, como Ada 2005 , Cobra , D , Fortran 90 , Go , Rust , Julia , MATLAB , Perl , Python , S-Lang , Windows PowerShell y los lenguajes matemáticos / estadísticos GNU Octave , S y R .
Cronología del corte en varios lenguajes de programación.
1966: Fortran 66
Los programadores de Fortran 66 solo pudieron aprovechar el corte de matrices por fila, y solo al pasar esa fila a una subrutina :
IMPRESIÓN DE SUBRUTINA V ( VEC , LEN ) IMPRESIÓN DE VEC REAL ( * ) IMPRESIÓN * , ( VEC ( I ), I = 1 , LEN ) FIN PARÁMETRO PRINCIPAL DEL PROGRAMA ( LEN = 3 ) MATRIZ REAL ( LEN , LEN ) MATRIZ DE DATOS / 1 , 1 , 1 , 2 , 4 , 8 , 3 , 9 , 27 / CALL PRINT V ( MATRIX ( 1 , 2 ), LEN ) END
Resultado:
2.000000 4.000000 8.000000
Tenga en cuenta que no hay un vector dope en FORTRAN 66, por lo tanto, la longitud del segmento también debe pasarse como un argumento, o algún otro medio, al archivo SUBROUTINE
. Pascal y C de la década de 1970 tenían restricciones similares.
1968: Algol 68
El informe final de Algol68 contiene un ejemplo temprano de corte, los cortes se especifican en el formulario:
[límite inferior: límite superior] ¢ para computadoras con juegos de caracteres extendidos ¢
o:
(LÍMITE INFERIOR ... LÍMITE SUPERIOR) # PARA COMPUTADORAS CON SÓLO CARACTERES DE 6 BITS. #
Ambos límites son inclusivos y se pueden omitir, en cuyo caso se establecen de forma predeterminada en los límites de la matriz declarados. Ni la función de zancada ni los alias de cortes diagonales forman parte del informe revisado.
Ejemplos:
[3, 3] real a: = ((1, 1, 1), (2, 4, 8), (3, 9, 27)); # declaración de una matriz variable # [,] real c = ((1, 1, 1), (2, 4, 8), (3, 9, 27)); # matriz constante, el tamaño está implícito #
ref [] fila real: = a [2,]; # alias / ref a un segmento de fila # ref [] real col2 = a [, 2]; # alias permanente / referencia a la segunda columna #
imprimir ((a [:, 2], nueva línea)); # segmento de la segunda columna # print ((a [1⌈a,:], nueva línea)); # último segmento de fila # print ((a [:, 2⌈a], nueva línea)); # segmento de la última columna # print ((a [: 2,: 2], nueva línea)); # "rebanada" de la submatriz 2 por 2 principal #
+1.0000 10 +0 +4.0000 10 +0 +9.0000 10 +0+3.0000 10 +0 +9.0000 10 +0 +2.7000 10 +1+1.0000 10 +0 +8.0000 10 +0 +2.7000 10 +1+1.0000 10 +0 +1.0000 10 +0 +2.0000 10 +0 +4.0000 10 +0
1970: MATLAB
> A = round ( rand ( 3 , 4 , 5 ) * 10 ) % 3x4x5 matriz tridimensional o cúbica > A (:, :, 3 ) % matriz bidimensional 3x4 a lo largo de la primera y segunda dimensionesans = 8 3 5 7 8 9 1 4 4 4 2 5> A (:, 2 : 3 , 3 ) % 3x2 matriz bidimensional a lo largo de la primera y segunda dimensionesans = 3 5 9 1 4 2> A ( 2 : end , :, 3 ) % 2x4 matriz bidimensional usando la palabra clave 'end'; funciona con GNU Octave 3.2.4ans = 6 1 4 6 10 1 3 1> Un ( 1 , :, 3 ) % matriz unidimensional a lo largo de la segunda dimensiónans = 8 3 5 7> A ( 1 , 2 , 3 ) % valor único ans = 3
1976: S / R
Las matrices en S y GNU R siempre se basan en uno, por lo que los índices de un nuevo segmento comenzarán con uno para cada dimensión, independientemente de los índices anteriores. Las dimensiones con una longitud de uno se eliminarán (a menos que drop = FALSE). Se conservarán los nombres de dimensión (si están presentes).
> A <- array ( 1 : 60 , dim = c ( 3 , 4 , 5 )) # 3x4x5 tridimensional o cúbico array > A [, , 3 ] # 3x4 matriz de dos dimensiones a lo largo de las dimensiones primera y segunda [, 1 ] [, 2] [, 3] [, 4] [1,] 25 28 31 34 [2,] 26 29 32 35 [3,] 27 30 33 36 > A [, 2 : 3 , 3 , drop = FALSE ] # 3x2x1 subconjunto de matriz cúbica (dimensiones conservadas),, 1 [, 1] [, 2] [1,] 28 31 [2,] 29 32 [3,] 30 33 > A [, 2 , 3 ] # matriz unidimensional a lo largo de la primera dimensión [1] 28 29 30 > A [ 1 , 2 , 3 ] # valor único [1] 28
1977: Fortran 77
El estándar Fortran 77 introdujo la capacidad de cortar y concatenar cadenas:
IMPRESIÓN PRINCIPAL DEL PROGRAMA * , 'ABCDE' ( 2 : 4 ) FIN
Produce:
BCD
Tales cadenas podrían pasarse por referencia a otra subrutina, la longitud también se pasaría de forma transparente a la subrutina como una especie de vector de dope corto .
IMPRESIÓN DE SUBRUTINA S ( STR ) CARÁCTER * ( * ) IMPRESIÓN DE STR * , STR END PROGRAMA LLAMADA PRINCIPAL IMPRESIÓN S ( 'ABCDE' ( 2 : 4 )) FIN
Nuevamente produce:
BCD
1979: Sinclair BASIC ZX80 / 81 / Espectro
La ROM estándar del ZX80 / 81 / Spectrum ofrece BASIC con la capacidad de cortar y concatenar cadenas:
en la parte del comando (x TO y) que indica el corte de matriz necesario, el valor de xey se puede omitir, lo que da el significado de usar todas las celdas de matriz encadenadas (FROM x TO end) o (begin TO y). Con matrices multidimensionales, el corte solo es posible con la última dimensión de nivel.
10 LET a $ = "ABCDE" ( 2 to 4 ) 20 PRINT a $
Produce:
BCD
10 LET a $ = "ABCDE" 20 LET b $ = a $ ( 4 TO ) + a $ ( 2 TO 3 ) + a $ ( 1 ) 30 PRINT b $
Produce:
DEBCA
1983: Ada 83 y superior
Ada 83 admite cortes para todos los tipos de matrices. Al igual que Fortran 77, tales matrices podrían pasarse por referencia a otra subrutina, la longitud también se pasaría de forma transparente a la subrutina como una especie de vector de dope corto .
con Text_IO ; procedimiento Main is Text : String : = "ABCDE" ; comenzar Text_IO . Put_Line ( Texto ( 2 .. 4 )); end Main ;
Produce:
BCD
Nota: Dado que en Ada los índices se basan en n, el término Text (2 .. 4)
dará como resultado una matriz con el índice base de 2.
La definición de Text_IO.Put_Line
es:
el paquete Ada.Text_IO es procedimiento Put_Line ( Item : in String );
La definición de String
es:
paquete estándar es subtipo Positivo es Integer rango 1 .. Integer ' Last ; tipo Cadena es una matriz ( rango positivo <>) de carácter ; Paquete de pragma ( cadena );
Ada apoya índices negativos verdaderos, ya type History_Data_Array is array (-6000 .. 2010) of History_Data;
que no otorga un significado especial a los índices negativos. En el ejemplo anterior, el término Some_History_Data (-30 .. 30)
dividiría History_Data
del 31 a. C. al 30 d . C. (dado que no hubo año cero, el año número 0 en realidad se refiere al 1 a . C. ).
1987: Perl
Si tenemos
@a = ( 2 , 5 , 7 , 3 , 8 , 6 , 4 );
como arriba, entonces los primeros 3 elementos, los 3 elementos del medio y los últimos 3 elementos serían:
@a [ 0 .. 2 ]; # (2, 5, 7) @a [ 2 .. 4 ]; # (7, 3, 8) @a [ - 3 ..- 1 ]; # (8, 6, 4)
Perl admite índices de lista negativos. El índice -1 es el último elemento, -2 el penúltimo elemento, etc. Además, Perl admite la división basada en expresiones, por ejemplo:
@a [ 3 .. $ # a ]; # 4to elemento hasta el final (3, 8, 6, 4) @a [ grep { ! ( $ _ % 3 ) } ( 0 ... $ # a ) ]; # 1er, 4to y 7mo elemento (2,3,4) @a [ grep { ! (( $ _ + 1 ) % 3 ) } ( 0 .. $ # a ) ]; # cada tercer elemento (7,6)
1991: Python
Si tiene la siguiente lista:
>>> números = [ 1 , 3 , 5 , 7 , 8 , 13 , 20 ]
Entonces es posible cortar usando una notación similar a la recuperación de elementos:
>>> números [ 3 ] # sin división 7 >>> números [: 3 ] # desde el índice 0 (incluido) hasta el índice 3 (exclusivo) [1, 3, 5] >>> números [ 1 : 5 ] [3 , 5, 7, 8] >>> números [ - 3 :] [8, 13, 20]
Tenga en cuenta que Python permite índices de lista negativos. El índice -1 representa el último elemento, -2 el penúltimo elemento, etc. Python también permite una propiedad de paso agregando dos puntos adicionales y un valor. Por ejemplo:
>>> números [ 3 :] [7, 8, 13, 20] >>> números [ 3 ::] # == números [3:] [7, 8, 13, 20] >>> números [:: 3 ] # comenzando en el índice 0 y obteniendo cada tercer elemento [1, 7, 20] >>> nums [ 1 : 5 : 2 ] # desde el índice 1 hasta el índice 5 y obteniendo cada segundo elemento [3, 7]
La sintaxis stride ( nums[1:5:2]
) se introdujo en la segunda mitad de la década de 1990, como resultado de solicitudes presentadas por usuarios científicos en Python "matrix-SIG" (grupo de interés especial). [2]
La semántica de Slice difiere potencialmente según el objeto; Se puede introducir nueva semántica cuando el operador sobrecarga al operador de indexación. Con las listas estándar de Python (que son matrices dinámicas ), cada segmento es una copia. Las secciones de matrices NumPy , por el contrario, son vistas en el mismo búfer subyacente.
1992: Fortran 90 y superior
En Fortran 90, las rebanadas se especifican en el formulario
lower_bound : upper_bound [: zancada ]
Ambos límites son inclusivos y se pueden omitir, en cuyo caso se establecen de forma predeterminada en los límites de la matriz declarados. Stride tiene el valor predeterminado 1. Ejemplo:
real , dimensión ( m , n ) :: a ! declaración de una matriz imprimir * , a (:, 2 ) ! segunda columna imprimir * , a ( m , :) ! última fila de impresión * , una (: 10 , : 10 ) ! submatriz principal de 10 por 10
1994: Analytica
Cada dimensión de un valor de matriz en Analytica se identifica mediante una variable de índice. Al dividir o subíndice, la sintaxis identifica las dimensiones sobre las que está dividiendo o subíndice al nombrar la dimensión. Como:
Índice I: = 1..5 {Definición de un índice numérico}Índice J: = ['A', 'B', 'C'] {Definición de un índice con valores de texto}Variable X: = Matriz (I, J, [[10, 20, 30], [1, 2, 3], ....]) {Definición de un valor 2D}X [I = 1, J = 'B'] -> 20 {Subíndice para obtener un valor único}X [I = 1] -> Array (J, [10, 20, 30]) {Corta una matriz 1D. }X [J = 2] -> Array (I, [20, 2, ....]) {Corta una matriz 1D sobre la otra dimensión. }X [I = 1..3] {Divida los primeros cuatro elementos sobre I con todos los elementos sobre J}
Nombrar índices en la segmentación y subíndice es similar a nombrar parámetros en llamadas a funciones en lugar de depender de una secuencia fija de parámetros. Una ventaja de nombrar índices en la división es que el programador no tiene que recordar la secuencia de índices en una matriz multidimensional. Una ventaja más profunda es que las expresiones se generalizan de forma automática y segura sin requerir una reescritura cuando cambia el número de dimensiones de X.
1998: S-Lang
La división de matrices se introdujo en la versión 1.0. Las versiones anteriores no admitían esta función.
Suponga que A es una matriz 1-d como
A = [1:50]; % A = [1, 2, 3, ... 49, 50]
Entonces se puede crear una matriz B de los primeros 5 elementos de A usando
B = A [[: 4]];
De manera similar, B puede asignarse a una matriz de los últimos 5 elementos de A a través de:
B = A [[- 5:]];
Otros ejemplos de corte en 1 d incluyen:
A [-1]% El último elemento de A A [*]% Todos los elementos de A A [[:: 2]]% Todos los elementos pares de A A [[1 :: 2]]% Todos los elementos impares de A A [[- 1 :: - 2]]% Todos los elementos pares en orden inverso A [[[0: 3], [10:14]]]% Elementos 0-3 y 10-14
El corte de matrices de dimensiones superiores funciona de manera similar:
A [-1, *]% La última fila de A Una matriz [[1: 5], [2: 7]]% 2d con las filas 1-5 y las columnas 2-7 A [[5: 1: -1], [2: 7]]% Igual que arriba, excepto que las filas están invertidas
Los índices de matriz también pueden ser matrices de números enteros. Por ejemplo, suponga que I = [0:9]
es una matriz de 10 enteros. Entonces A[I]
es equivalente a una matriz de los primeros 10 elementos de A
. Un ejemplo práctico de esto es una operación de clasificación como:
I = ordenación_matriz (A); % Obtener una lista de índices de clasificación B = A [I]; % B es la versión ordenada de A C = A [ordenación_matriz (A)]; % Igual que el anterior pero más conciso.
1999: D
Considere la matriz:
int [] a = [ 2 , 5 , 7 , 3 , 8 , 6 , 4 , 1 ];
Saca una rebanada de ella:
int [] b = a [ 2 .. 5 ];
y el contenido de b
será [7, 3, 8]
. El primer índice del segmento es inclusivo, el segundo es exclusivo.
auto c = a [$ - 4 .. $ - 2 ];
significa que la matriz dinámica c
ahora contiene [8, 6]
porque dentro de [] el $
símbolo se refiere a la longitud de la matriz.
Los segmentos de la matriz D tienen un alias de la matriz original, por lo que:
b [ 2 ] = 10 ;
significa que a
ahora tiene el contenido [2, 5, 7, 3, 10, 6, 4, 1]
. Para crear una copia de los datos de la matriz, en lugar de solo un alias, haga lo siguiente:
auto b = a [ 2 .. 5 ]. dup ;
A diferencia de Python, los límites del segmento D no se saturan, por lo que el código equivalente a este código de Python es un error en D:
>>> d = [ 10 , 20 , 30 ] >>> d [ 1 : 5 ] [20, 30]
2004: SuperCollider
El lenguaje de programación SuperCollider implementa algunos conceptos de J / APL . El corte se ve de la siguiente manera:
a = [ 3 , 1 , 5 , 7 ] // asigna una matriz a la variable a a [ 0 .. 1 ] // devuelve los dos primeros elementos de a a [.. 1 ] // devuelve los dos primeros elementos de a: el cero se puede omitir a [ 2 ..] // devuelve el elemento 3 hasta el último a [[ 0 , 3 ]] // devuelve el primer y cuarto elemento de una [[ 0 , 3 ]] = [ 100 , 200 ] // reemplaza el primer y cuarto elemento de a a [ 2 ..] = [ 100 , 200 ] // reemplaza los dos últimos elementos de a// asigna una matriz multidimensional a la variable a a = [[ 0 , 1 , 2 , 3 , 4 ], [ 5 , 6 , 7 , 8 , 9 ], [ 10 , 11 , 12 , 13 , 14 ], [ 15 , 16 , 17 , 18 , 19 ]]; a . rebanada ( 2 , 3 ); // toma un corte con coordenadas 2 y 3 (devuelve 13) a . rebanada ( cero , 3 ); // toma un corte ortogonal (devuelve [3, 8, 13, 18])
2005: pescado
Las matrices en fish siempre se basan en uno, por lo que los índices de un nuevo segmento comenzarán con uno , independientemente de los índices anteriores.
> set A ( seq 3 2 11 ) # $ A es una matriz con los valores 3, 5, 7, 9, 11 > echo $ A [( seq 2 )] # Imprime los dos primeros elementos de $ A 3 5 > set B $ A [ 1 2 ] # $ B contiene el primer y segundo elemento de $ A, es decir, 3, 5 > conjunto -e A [ $ B ] ; echo $ A # Borra el tercer y quinto elemento de $ A, imprime $ A 3 5 9
2006: Cobra
Cobra admite el corte al estilo Python. Si tienes una lista
nums = [ 1 , 3 , 5 , 7 , 8 , 13 , 20 ]
entonces los primeros 3 elementos, los 3 elementos del medio y los últimos 3 elementos serían:
nums [: 3 ] # es igual a [1, 3, 5] nums [ 2 : 5 ] # es igual a [5, 7, 8] nums [ - 3 :] # es igual a [8, 13, 20]
Cobra también admite la sintaxis de estilo de corte para 'bucles for numéricos':
para i en 2 : 5 imprimir i # imprime 2, 3, 4para j en 3 imprimir j # imprime 0, 1, 2
2006: Windows PowerShell
Las matrices están basadas en cero en PowerShell y se pueden definir mediante el operador de coma:
PS> $ a = 2 , 5 , 7 , 3 , 8 , 6 , 4 , 1 PS> # Imprime los dos primeros elementos de $ a: PS> " $ ( $ a [ 0 , 1 ]) " 2 5 PS> # Saque una porción usando el operador de rango: PS> " $ ( $ a [ 2 .. 5 ]) " 7 3 8 6 PS> # Obtenga los últimos 3 elementos: PS> " $ ( $ a [- 3 ..- 1 ]) " 6 4 1 PS> # Devuelve el contenido de la matriz en orden inverso: PS> " $ ( $ a [( $ a . Longitud - 1 ) .. 0 ]) " # La longitud es una propiedad de System.Object [] 1 4 6 8 3 7 5 2
2009: ir
Go admite la sintaxis de estilo Python para segmentar (excepto que no se admiten índices negativos). Las matrices y las rodajas se pueden cortar. Si tienes una rebanada
nums : = [] int { 1 , 3 , 5 , 7 , 8 , 13 , 20 }
entonces los primeros 3 elementos, los 3 del medio, los últimos 3 elementos y una copia de todo el corte serían:
nums [: 3 ] // igual a [] int {1, 3, 5} nums [ 2 : 5 ] // igual a [] int {5, 7, 8} nums [ 4 :] // igual a [] int {8 , 13, 20} nums [:] // es igual a [] int {1, 3, 5, 7, 8, 13, 20}
Los sectores en Go son tipos de referencia, lo que significa que diferentes sectores pueden hacer referencia a la misma matriz subyacente.
2010: Cilk Plus
Cilk Plus admite la sintaxis para la división de matrices como una extensión de C y C ++.
array_base [ lower_bound : length [ : stride ]] *
El corte Cilk Plus tiene el siguiente aspecto:
A [ : ] // Todo el vector A B [ 2 : 6 ] // Elementos 2 a 7 del vector B C [ : ] [ 5 ] // Columna 5 de la matriz C D [ 0 : 3 : 2 ] // Elementos 0, 2, 4 del vector D
El corte de matriz de Cilk Plus se diferencia del de Fortran en dos aspectos:
- el segundo parámetro es la longitud (número de elementos en el segmento) en lugar del límite superior, para ser coherente con las bibliotecas C estándar;
- cortar nunca produce un temporal y, por lo tanto, nunca necesita asignar memoria. Se requiere que las asignaciones no se superpongan o que se superpongan perfectamente, de lo contrario, el resultado no está definido.
2012: Julia
El corte de matriz de Julia es como el de MATLAB , pero usa corchetes. Ejemplo:
julia> x = rand ( 4 , 3 ) 4x3 Array {Float64,2}: 0.323877 0.186253 0.600605 0.404664 0.894781 0.0955007 0.223562 0.18859 0.120011 0.149316 0.779823 0.0690126julia> x [ : , 2 ] # obtiene la segunda columna. Matriz de 4 elementos {Float64,1}: 0.186253 0.894781 0.18859 0.779823Julia> x [ 1 , : ] # reciben la primera fila. Matriz 1x3 {Float64,2}: 0.323877 0.186253 0.600605julia> x [ 1 : 2 , 2 : 3 ] # obtiene la submatriz que abarca las filas 1,2 y las columnas 2,3 2x2 Array {Float64,2}: 0.186253 0.600605 0.894781 0.0955007
Ver también
- Comparación de lenguajes de programación (matriz) #Slicing
Referencias
- ^ Zhang, Zemin; Aeron, Shuchin (15 de marzo de 2017). "Finalización exacta del tensor usando t-SVD" . Transacciones IEEE sobre procesamiento de señales . Instituto de Ingenieros Eléctricos y Electrónicos (IEEE). 65 (6): 1511-1526. doi : 10.1109 / tsp.2016.2639466 . ISSN 1053-587X .
- ^ Millman, K. Jarrod; Aivazis, Michael (2011). "Python para científicos e ingenieros" . Computación en Ciencias e Ingeniería . 13 (2): 9-12.