Julia: nueva sintaxis para transponer

Creado en 15 mar. 2017  ·  103Comentarios  ·  Fuente: JuliaLang/julia

Ahora que .op es generalmente la forma vectorizada de op , es muy confuso que .' signifique transposición en lugar de la forma vectorizada de ' (adjunto, también conocido como ctranspose ). Este número es para discutir sintaxis alternativas para transponer y/o adjuntar.

linear algebra parser

Comentario más útil

Me opongo firmemente a hacer que tr(A) signifique transposición de matriz: todos pensarán que significa traza de matriz: https://en.wikipedia.org/wiki/Trace_ (linear_algebra)

Todos 103 comentarios

Andreas probó Aᵀ (y quizás Aᴴ ) en #19344, pero no fue muy bien recibido. De manera similar, podríamos hacer un juego de palabras con ^ con tipos de exponentes especiales T (y tal vez H ) de modo que A^T se transponga, pero eso también es bastante turbio. No estoy seguro de que haya muchas otras buenas opciones que todavía se parezcan a la notación matemática.

Creo que t(A) podría ser el mejor, pero es desafortunado "robar" otro nombre de una letra.

Moviendo mi comentario del otro tema (no es que solucione nada, pero...):

+1 por usar algo más que .' .

No pude encontrar idiomas con una sintaxis especial para la transposición, excepto APL, que usa el no tan obvio , y Python, que usa *X (que sería confuso para Julia). Varios idiomas usan transpose(X) ; R usa t(X) . Eso no es bonito, pero no es peor que .' . Al menos está menos tentado a usar ' confundiéndolo con .' : queda claro que se trata de operaciones muy diferentes.

Consulte el código de Rosetta . (Por cierto, el ejemplo de Julia en realidad ilustra la transposición conjugada...)

¿Se podría usar una de las otras garrapatas? ` o "

-100 para cambiar el adjunto, ya que es una de las cosas asombrosas que hace que escribir el código de Julia sea tan claro como escribir matemáticas, además, la transposición conjugada es generalmente lo que desea de todos modos, por lo que tiene sentido tener una sintaxis abreviada para ello.

Siempre que tengamos la buena sintaxis para la transposición conjugada, un operador de sufijo para la transposición regular parece en su mayoría innecesario, por lo que me parece bien que sea una llamada de función normal. transpose ya funciona; ¿No podríamos simplemente usar eso? Encuentro el t(x) R-ismo desafortunado, ya que no está claro por el nombre lo que realmente se supone que debe hacer.

Usar una marca diferente sería un poco extraño, por ejemplo, A` puede parecerse mucho a A' dependiendo de la fuente, y A" se parece demasiado a A'' .

Si hacemos el cambio en #20978, entonces una transposición de sufijo en realidad se vuelve más útil de lo que es ahora. por ejemplo, si tiene dos vectores x y y y desea aplicarles f por pares, puede hacerlo, por ejemplo f.(x, y.') ... con #20978 , esto será aplicable a arreglos de tipos arbitrarios.

Honestamente, creo que nuestra mejor opción sigue siendo dejarlo como está. Ninguna de las sugerencias me parece una clara mejora. .' tiene la ventaja de estar familiarizado con Matlab. El . en realidad es algo congruente con la sintaxis de llamada de punto en ejemplos como f.(x, y.') , y sugiere (algo correctamente) que la transposición se "fusiona" (no produce una copia temporal gracias a RowVector y futuras generalizaciones de los mismos).

De hecho, podríamos incluso ir más allá y convertir f.(x, g.(y).') una operación de fusión. es decir, cambiamos la transposición de .' para que sea no recursiva ala #20978 y ampliamos su semántica para incluir la fusión con otras llamadas de puntos anidados. (Si desea la versión sin fusión, llame a transpose ).

Me gusta mucho ese plan, @stevengj.

Un problema: presumiblemente, la macro @. no convierte y' en y.' (ya que eso sería incorrecto). Sin embargo, podría convertir y' en algún tipo de operación conjunta fusionada.

El principal problema es encontrar una forma limpia de hacer que f.(x, g.(y).') tenga una semántica de fusión. Una posibilidad sería transformarlo en f.(x, g.(y.')) y, por lo tanto, en broadcast(x,y -> f(x, g(y)), x, y.') .

Tenga en cuenta que, para que esto funcione correctamente, es posible que debamos restaurar el método alternativo transpose(x) = x , en cuyo caso también podemos dejar que la transposición siga siendo recursiva.

Creo que decidir si la transposición debe ser recursiva o no es ortogonal a si hacemos que participe en la fusión de sintaxis de puntos. La elección de hacerlo no recursivo no está motivada por eso.

@StefanKarpinski , si restaura un respaldo transpose(x) = x , entonces la mayor parte de la motivación para cambiarlo para que no sea recursivo desaparece.

¿Cuál es el problema si se restaura el respaldo pero aún tenemos la transposición no recursiva?

@jebej , la transposición recursiva es más correcta cuando se usa como una operación matemática en operadores lineales. Si no recuerdo mal, la razón principal para hacerlo no recursivo fue que no tuviéramos que definir el respaldo transpose(x) = x , en lugar de generar un MethodError.

Pero no sería terrible tener el respaldo y seguir siendo no recursivo.

Permítanme agregar dos comentarios (revisé la discusión anterior y no los noté, lo siento si omití algo):

  • documentación para permutedims dice Esta es una generalización de la transposición para matrices multidimensionales. transpose , que no lo es.
  • ¿Cómo se supone que se debe hacer una transposición de un vector x=["a", "b"] ? En realidad y=x.' funciona y crea una nueva variable, pero getindex falla. AFAIK tienes que usar reshape(x, 1, :) o mucho más lento hcat(x...) para lograrlo, pero no es natural tener una sintaxis diferente para Vector ( permutedims no funciona aquí ).

¿Cuál es su caso de uso para transponer un vector de cadenas?

Considere el siguiente escenario, por ejemplo:

x = ["$(j+i)" for j in 1:3, i in 1:5]
y = ["$i" for i in 5:9]

y quiero agregar y después de la última fila de x . Y la forma más sencilla es vcat una transposición de y .

Aparece en la práctica cuando se registran datos de texto de forma incremental en Matrix{String} (podría usar Vector{Vector{String}} ), pero a menudo la matriz es más útil (o, de nuevo, hay una pregunta sobre cómo convertir Vector{Vector{String}} a Matrix{String} concatenando verticalmente elementos consecutivos).

Otro caso de uso: la transposición es la forma más sencilla de hacer que dos vectores sean ortogonales entre sí para transmitir una función sobre el producto cartesiano ( f.(v, w.') ).

Punto de datos: Ayer me encontré con una parte confundida por el operador postfix "broadcast-adjoint" y por qué se comporta como una transposición. ¡Mejor!

FWIW, creo firmemente que deberíamos deshacernos de la sintaxis .' . Como alguien más familiarizado con Julia que con Matlab, esperaba que significara adjunto vectorizado y realmente me tropecé cuando no fue así. Julia no es Matlab y no debe estar sujeta a las convenciones de Matlab; si en Julia, un punto significa vectorización de la función adyacente, entonces esto debería ser consistente en todo el lenguaje y no debería tener la horrible excepción aleatoria de que .' formalmente no está relacionado con ' .

Creo que está bien tener transpose sin ninguna notación especial de "marca", ya que la gran mayoría de las veces, se llama en una matriz de números reales, por lo que ' sería equivalente si Realmente quiero ahorrar escribiendo. Si queremos hacer una versión fusionada de la transposición, entonces realmente no creo que .' sea la sintaxis correcta.

Ese es un buen punto. Podría decirse que solo el adjunto necesita una sintaxis supercompacta.

Llamemos a esto transpose y desapruebemos .' . En el futuro, podemos considerar si queremos .' como adjunto puntual o si simplemente queremos dejarlo en desuso permanente para evitar atrapar a los usuarios de Matlab.

Tenga en cuenta que solo agregué los paquetes registrados y encontré más de 600 usos de .' , por lo que no es terriblemente raro. Y con las llamadas de punto / broadcast (que solo en 0.6 comenzó a manejar completamente datos no numéricos), el deseo de transponer perezosamente matrices no numéricas (donde el adjunto tiene menos sentido) probablemente se volverá mucho más común, por lo que el argumento a favor de una sintaxis compacta se fortalece un poco.

Entonces será mejor que desaprobemos .' lo antes posible, antes de que más código quede atrapado en un patrón de uso incorrecto.

¿Porque es malo?

El problema es que .' ahora no significa lo que parece significar como operador punteado.

Como dije anteriormente, porque viola el patrón general de que . significa vectorización, y parece que significa adjunto vectorizado (especialmente para alguien que no está familiarizado con Matlab).

Creo que @stevengj tiene un buen punto: esto está relacionado con el deseo de una transposición simple no recursiva.

Sé que no fue popular, pero estoy empezando a preferir el #19344 de Andreas por . En este punto, preferiría desaprobar el uso de _todos_ los superíndices como identificadores e interpretar _cualquiera_ superíndices finales como operadores de postfijo. Esto también brinda un camino para resolver algunas de las torpezas alrededor literal_pow usando números en superíndice. Sí, sería triste perder χ² y nombres de variables, pero creo que los beneficios superarían las desventajas.

En este punto, preferiría desaprobar el uso de _todos_ los superíndices como identificadores e interpretar _cualquiera_ superíndices finales como operadores de postfijo.

RIP mi código
screenshot from 2017-11-09 22-08-25

En este punto, preferiría desaprobar el uso de todos los superíndices como identificadores.

Realmente no creo que sea necesario, cuando solo queremos T y tal vez un par de cosas más en el futuro.

Una consistencia tonta…

Sí, es un poco inconsistente usar .' para transponer, pero todas las alternativas propuestas hasta ahora parecen ser peores. No es lo peor del mundo decir " .' es una transposición, una excepción a la regla habitual sobre los operadores de punto". Aprendes esto y sigues adelante.

Una cosa a tener en cuenta que puede ayudar con cualquier posible confusión acerca de que .' no es una transmisión de punto es que es un operador de postfijo, mientras que la transmisión de prefijo es op. y el infijo es .op . Entonces podemos decir que . no significa transmisión cuando es sufijo. El otro uso del sufijo . es la búsqueda de campos, y getfield(x, ') no tiene sentido, por lo que es distinto de otros significados.

(Dicho esto, prefiero transpose(x) a mantener .' .)

@stevengj Apuesto a que muchos (quizás la mayoría) de los más de 600 usos de .' en los paquetes registrados que mencionó anteriormente podrían reemplazarse por ' sin costo para la legibilidad, y el código seguiría trabajando.

Posiblemente no sea popular, pero aún podría haber sufijos " y ` ?

usos de .' en los paquetes registrados que mencionó anteriormente podrían reemplazarse por ' sin costo alguno para la legibilidad, y el código continuaría funcionando.

Tenga en cuenta que una vez que #23424 aterriza, podremos usar transpose en matrices de cadenas y así sucesivamente, pero no adjoint . La mejor práctica para el uso de álgebra lineal de x.' probablemente se convertirá en algo como conj(x') (con suerte, esto es perezoso, es decir, gratis). Si bien me encanta usar .' por su tamaño compacto, quizás deshacerse de él obligue a los usuarios de álgebra lineal a usar lo correcto y a los usuarios de matrices de datos a usar transpose deletreado.

todavía podría haber sufijos " y `?

La nueva sintaxis para transpose() parece bastante prematura. En mi humilde opinión, sería mejor desaprobar .' para ser reemplazado como sugiere con conj(x') y transpose según sea necesario.

Tengo la sensación de que .' es tan útil en matlab principalmente debido a la insistencia de matlab en que "todo es una matriz" junto con la falta de reglas de corte coherentes, por lo que a menudo es necesario insertar transposiciones aleatorias en varios lugares para hacer que las cosas funcionen.

Para resumir los argumentos aquí:

  1. .' es ahora el único operador destacado como un operador con puntos que no significa "aplicar un operador sin puntos en todos los elementos"; los nuevos usuarios que no provienen de Matlab encuentran que esto es una trampa sorprendente.

  2. .' ahora es efectivamente ambiguo: ¿quiso decir transpose o quiso decir conj(x') ? En principio, cada uso heredado de .' debe examinarse para determinar si está permutando los índices de una matriz bidimensional o si está haciendo un "adjunto no conjugado".

El primer tema es problemático pero no fatal por sí mismo; el segundo problema es el realmente malo: ya no es una sola operación coherente, sino que se dividirá en dos significados separados.

Acabo de darme cuenta de que si alguna vez cambiamos .' para que signifique "elemento adjunto", entonces conj(x') sería más o menos equivalente a x'.' y conj(x)' sería más o menos x.'' que está muuuy cerca de x.' 😬.

Posiblemente no sea popular, pero aún podría haber sufijos " y `?

Copie y pegue el código en Slack y vea que destruir el resaltado de sintaxis sería...

Ser capaz de transponer cualquier cosa es bueno porque facilita el "producto cruzado" a través del mecanismo de envío y otros casos de uso breves y concisos como ese. El problema de no tener un respaldo fácil para este tipo de cosas es que, invariablemente, el truco que veremos es simplemente definir los respaldos transpose(x) = x (o en los tipos base, así que escribe piratería en los paquetes) para hacer esto tipo de cosas funcionan fácilmente. Eso me hace pensar: ¿por qué Complex no es el extraño? El adjunto de la mayoría de los números es en sí mismo, por lo que el adjunto del complejo es en el que se especializa: ¿no se puede extender eso más allá de los números?

Veo dos cosas muy relacionadas aquí:

1) x' no funciona para tipos que no son números, por lo que queremos una forma de hacerlo fácilmente para otros datos
2) transpose(x) no es tan simple como x.' . Esto es principalmente para los casos de (1), ya que los casos de uso para transponer matrices complejas son mucho más raros.

Pero en lugar de bajar (2), ¿por qué no intentar hacer una solución razonable para (1)?

¿Tal vez una solución razonable es solo una macro que hace que ' signifique transposición en lugar de adjunto?

Pero en lugar de bajar (2), ¿por qué no intentar hacer una solución razonable para (1)?

Ya hemos recorrido ese camino y varios adyacentes. Ha habido una gran cantidad de discusión resultante que quizás alguien más pueda destilar, pero en resumen, no funciona bien. Fundamentalmente, la operación matemática adjoint no tiene sentido en cosas que no son números. Usar ' en no números solo porque le gusta la sintaxis concisa es malo: es el peor tipo de juego de palabras del operador y no debería sorprender que se produzcan cosas malas de este tipo de abuso de significado. La función adjoint solo debe definirse en cosas de las que tiene sentido tomar el adjunto y ' solo debe usarse para indicar eso.

Recuerde que .' como se usa actualmente es fundamentalmente dos operaciones diferentes: transposición de matriz y adjunto no conjugado. El problema de la transposición recursiva destaca el hecho de que estas son operaciones diferentes y que, por lo tanto, necesitamos diferentes formas de expresarlas. La gente matemática parece inflexible en que la operación adjunta no conjugada es (a) importante y (b) diferente del simple intercambio de dimensiones. En particular, para que sea correcto, el adjunto no conjugado debe ser recursivo. Por otro lado, el intercambio de dimensiones de una matriz genérica claramente no debería ser recursivo. Por lo tanto, estas operaciones deben escribirse de manera diferente, y los usos existentes de .' deben desambiguarse para que tengan un significado u otro. Rechazar .' es una forma de forzar esto.

Finalmente, si bien creo firmemente que permutedims(x, (2, 1)) es definitivamente demasiado inconveniente para intercambiar las dimensiones de una matriz 2d, encuentro que el argumento de que transpose(x) es demasiado inconveniente no es convincente. ¿Esta operación es tan común que tener un nombre de función simple y claro para ella es demasiado? ¿En serio? ¿Intercambiar las dimensiones de una matriz es mucho más común o importante que todas las demás cosas en el lenguaje para el que usamos nombres de funciones y sintaxis de llamadas a funciones? La notación de jefe de familia hace que adjoint sea bastante especial, ya que queremos escribir cosas como v'v , v*v' y v'A*v . Es por eso que adjoint obtiene una sintaxis realmente agradable. ¿Pero intercambiar las dimensiones de una matriz? No justifica un operador en mi opinión.

No es un argumento sólido, pero a menudo uso el operador ' para imprimir arreglos más compactos (cuando se usan como contenedores simples), por ejemplo, cuando quiero ver el contenido de algunos vectores al mismo tiempo en mi pantalla ( e invariablemente se frustran cuando falla porque los elementos no se pueden transponer). Así que una sintaxis corta para REPL es definitivamente útil. (Además, esto hace que sea más fácil para las personas acostumbradas a matrices de filas principales, tener una forma simple de "cambiar el orden", en particular cuando se transfieren algoritmos a julia usando matrices 2d; pero definitivamente tampoco es un argumento fuerte). Solo para decir que es una buena sintaxis concisa que no es útil solo para el álgebra lineal.

Había comentado algunas ideas de sintaxis en https://github.com/JuliaLang/julia/pull/19344#issuecomment -261621763, básicamente era:

julia> const ᵀ, ᴴ = transpose, ctranspose;

julia> for op in (ᵀ, ᴴ)
           <strong i="7">@eval</strong> Base.:*(x::AbstractArray{T}, f::typeof($op)) where {T<:Number} = f(x)
       end

julia> A = rand(2, 2)
2×2 Array{Float64,2}:
 0.919332  0.651938
 0.387085  0.16784

julia>  Aᵀ = (A)ᵀ    # variable definition and function application are both available!
2×2 Array{Float64,2}:
 0.919332  0.387085
 0.651938  0.16784

julia> Aᴴ = (A)ᴴ
2×2 Array{Float64,2}:
 0.919332  0.387085
 0.651938  0.16784

Pero sin el truco, por supuesto, solo la idea de que puede haber una especie de "aplicación de función de postfijo" y que exige paréntesis (x)f , las versiones punteadas podrían ser así (x).f ( xf sería un identificador, incluso si f es un símbolo de superíndice).

Este truco de ejemplo solía funcionar en 0.6 pero ahora:

julia> Aᵀ = (A)ᵀ               
ERROR: syntax: invalid operator

julia> Aᵀ = (A)transpose       
2×2 Array{Float64,2}:          
 0.995848  0.549117            
 0.69401   0.908227            

julia> Aᴴ = (A)ᴴ               
ERROR: syntax: invalid operator

julia> Aᴴ = (A)ctranspose      # or adjoint or whatever
2×2 Array{Float64,2}:          
 0.995848  0.549117            
 0.69401   0.908227            

Lo cual es triste, originalmente quería hacer eso para los poderes:

julia> square(n) = n^2; cube(n) = n^3;

julia> Base.:*(n, f::typeof(square)) = f(n)

julia> Base.:*(n, f::typeof(cube)) = f(n)

julia> const ² = square    # why?
syntax: invalid character "²"

julia> const ³ = cube    # why?
syntax: invalid character "³"

Lo cual, ingenuamente, pensé que permitiría una sintaxis como: n² = (n)² y n³ = (n)³ Pero cualquier tipo de identificador numérico tiene prohibido estar en la primera posición, sin embargo, (A)⁻¹ también funcionó, donde ⁻¹ era const ⁻¹ = inv .

Implementé un truco similar para InfixFunctions.jl .

Como usuario, podría hacer un paquete PostfixFunctions.jl y ser feliz con lo que encuentre mejor aquí. Pero actualmente estas restricciones de sintaxis:

  • No se permite el uso de superíndices numéricos al comienzo de un identificador.
  • superíndice x * ᶠ en sufijo (multiplicación implícita en el truco) (x)ᶠ no permitido

Me parece un poco demasiado en mi humilde opinión, me gustaría al menos poder definir identificadores que puedan comenzar con superíndices numéricos, o más en general, solo rechazar caracteres numéricos reales 0-9 con semántica numérica, al comienzo de un identificador, eso sería increíble. 😄

¡Salud!

Ver #10762 para una discusión de otros caracteres numéricos como identificadores.

El otro problema está relacionado con #22089, sufijos de operadores. +ᵀ ahora es un operador válido, que (probablemente accidentalmente) rechazó los identificadores que consisten solo en combinar caracteres en contextos donde se podría esperar un operador. Eso me parece un error. También es un poco extraño que sea un identificador válido pero -ᵀ no hace -(ᵀ) . Sin embargo, ese no es el fin del mundo y, en mi opinión, arreglarlo no valdría la pena perder otros posibles usos de .

Tenga en cuenta que usar .' como operador de transposición de postfijo ni siquiera está en la tabla aquí (a pesar de lo que dice el tema del problema), la consideración es si debemos mantener .' como operador de postfijo para adjunto no conjugado, que sería recursivo. Esto suele ser lo mismo que la transposición, pero generalmente no es la misma operación. Si la gente de álgebra lineal está dispuesta a dejar que .' signifique una transposición de matriz genérica, esa es una historia diferente, pero mi impresión es que no es aceptable.

@Ismael-VC, puedo ver que se permita (x)ᵀ como una sintaxis de función de postfijo para superíndices, ya que ¿qué más significaría? Creo que su propuesta comienza a molestar a las personas de manera incorrecta al permitir que cualquier identificador se aplique como una función en la sintaxis del postfijo. Lo limitaría a superíndices.

@StefanKarpinski , pensé que el consenso era precisamente permitir .' significa transposición de matriz no recursiva y no conjugada (si tenemos este operador), mientras que ' es el conjugado recursivo operación conjunta.

Realmente, realmente odio la idea de usar para un operador de transposición de postfijo. Es demasiado útil para tener un superíndice en nombres de variables, como aᵀa o LᵀDL = ltdlfact(A) . (Además del hecho de que usar solo para un operador, mientras que otros superíndices son válidos en las identificaciones, sería extraño).

Eso no lo entendí en absoluto: pensé que la gente de linalg estaba a favor de mantener a.' tal como está, es decir, significando conj(a)' . Mantener .' pero cambiar su significado a transposición de matriz es bastante diferente; no estoy seguro de cómo me siento al respecto. Estoy de acuerdo en que tener solo como operador de sufijo sería molesto e inconsistente. Sin embargo, me gusta más la propuesta de (a)ᵀ @Ismael-VC, que no impediría usar aᵀ como nombre.

Mi recuerdo de esas discusiones refleja el de Steven. La transposición recursiva, no conjugada, es rara y generalmente bastante extraña. Resumen decente aquí: https://github.com/JuliaLang/julia/issues/20978#issuecomment -316141984.

Creo que todos estamos de acuerdo en que el postfijo ' es adjunto y debería permanecer.
Creo que todos estamos de acuerdo en que el sufijo .' es una sintaxis subóptima.
Creo que la mayoría está de acuerdo en que la transposición no recursiva (estructural) es más útil que una transposición recursiva.

Ok, entonces los puntos en los que todos parecen estar de acuerdo:

  1. Usa a' por adjoint(a)
  2. Use conj(a)' o conj(a') para el adjunto (no) conjugado.

Entonces, el único punto de discusión es cómo escribir la transposición de la matriz:

  • Como a.' o
  • Como transpose(a) o
  • Como (a)ᵀ .

¿Es correcta esta evaluación?

Sí, creo que sí (donde la "transposición de matriz" no es recursiva).

Además, según tengo entendido, todos están de acuerdo en que transpose(a) definitivamente debería ser una sintaxis válida (y no recursiva), y los únicos puntos de desacuerdo son si .' y/o (a)ᵀ debe ser una sintaxis válida alternativa (completamente equivalente).

Enfoque (1) de https://github.com/JuliaLang/julia/issues/20978#issuecomment -315902532, que recibió bastante apoyo (por ejemplo, https://github.com/JuliaLang/julia/issues/20978# issuecomment-316080448), sigue siendo una posibilidad. Tengo una rama que se da cuenta de ese enfoque (introduciendo flip(A) ) que puedo publicar.

Por lo que vale, apoyo desaprobar .' . La confusión y ambigüedad en este hilo es un fuerte argumento para hacerlo en sí mismo. ¡Mejor!

Creo que mientras tengamos el postfijo ' , la gente querrá usarlo para transmitir f sobre un producto cartesiano de vectores con f.(v, w') . Y la gente querrá usarlo para remodelar un vector de cadenas en un vector de fila de encabezados para una estructura similar a una tabla. Por lo tanto, es convincente para mí tener un reemplazo simple y fácil de usar al que podamos dirigirlos.

Aquí hay una opción que no hemos considerado: A*' — un nuevo bigraph. La notación matemática típica podría interpretar esto como conj(A)' , que en realidad es bastante parecido a lo que queremos. Había estado disponible en 0.6, pero en 0.7 permitimos usar * para concatenar caracteres... aunque sigue funcionando.

No creo que el sufijo " y ` estén disponibles debido a que los literales de cadena personalizados analizan más allá del final de una línea. Postfix * por sí mismo tampoco está disponible por la misma razón. Postfix prime A′ es probablemente uno de los identificadores Unicode más utilizados, por lo que es incluso más que Aᵀ .

Honestamente, después de mirar mi código, no uso .' para nada, así que transpose(a) probablemente esté bien.

Tenga en cuenta que solo agregué los paquetes registrados y encontré más de 600 usos de .', por lo que no es terriblemente raro.

¿Se revisó este lugar para ver si .' no se usó donde ' hubiera estado bien? Estoy empezando a pensar que eso podría ser cierto la mayoría de las veces. De lo contrario, el único lugar donde he visto un uso legítimo de .' fue antes de que las etiquetas Plots.jl permitieran un vector (en su lugar, querían un vector de fila de cadenas), pero eso cambió. Para los códigos en los que realmente necesito esto a menudo, creo que comenzaría a hacer T = transpose localmente, o lanzaría una macro para cambiar ' a transpose .

<strong i="17">@transpose</strong> A = A'*A*B'*B*C'*C

estaría bien conmigo para ese caso raro.

la gente querrá usarlo para transmitir f sobre un producto cartesiano de vectores con f.(v, w'). Y la gente querrá usarlo para remodelar un vector de cadenas en un vector de fila de encabezados para una estructura similar a una tabla. Por lo tanto, es convincente para mí tener un reemplazo simple y fácil de usar al que podamos dirigirlos.

Si solo aparece una vez en una declaración, ¿no está bien usar transpose ?

La sintaxis a*' para conjugate-adjoint es bastante buena, aunque realmente no parece que esa sea la operación para la que necesitamos una sintaxis mejor. &a estará disponible pronto y sugiere intercambiar cosas, aunque es bastante diferente de las notaciones tradicionales para esto.

¿Quizás es hora de una encuesta informal?

¿Cómo deberíamos deletrear la transpuesta estructural?

(Más o menos en el orden de la propuesta; aquí no se emiten juicios sobre los nombres de emoji)

  • 👍: A.' — solo cambia el significado, mantén la sintaxis igual
  • 👎: transpose(A) — sin sintaxis especial
  • 😄: t(A) o tr(A) — sin sintaxis especial, pero exporta un nombre más corto
  • 🎉: Aᵀ — con solo y tal vez uno o dos superíndices en mayúsculas especiales de los identificadores
  • 😕: (A)ᵀ — con todos los superíndices separados de los identificadores que se comportan como operadores de sufijos
  • ❤️: A*' — pasa por alto ese valle inquietante, significa una transposición estructural
  • Si prefieres &A , lanza un 🎉 en la publicación de Stefan inmediatamente arriba (nos quedamos sin emoji)

De hecho, las discusiones de LinAlg hablaron sobre regalar .’ al uso de transposición no recursiva, ya que conj(x’) es relativamente poco común. Sin embargo es una sintaxis matemática y realmente debería tomar el significado matemático (si es que lo tiene).

Me opongo firmemente a hacer que tr(A) signifique transposición de matriz: todos pensarán que significa traza de matriz: https://en.wikipedia.org/wiki/Trace_ (linear_algebra)

Si no descarta los superíndices como identificador (lo que probablemente deba considerarse seriamente antes de 1.0), entonces ᵀ(A) también es una posibilidad.

En relación con la sugerencia (A)ᵀ , mis disculpas por descarrilar un poco esta discusión con el siguiente comentario:

Nunca me ha importado mucho tener disponible como operador unario, especialmente porque de todos modos terminarás escribiendo √(...) tan pronto como quieras aplicarlo a una variable que es más que un uno o varios personajes. Además, siempre he encontrado que la diferencia de funcionamiento entre y √a es muy artificial. Probablemente tenga sentido si conoce las clases de Unicode, etc., pero para cualquier otra persona esto debe parecer absurdo. Claro que es útil tener como un nombre de variable válido, pero de manera similar √a podría ser un nombre de variable útil para almacenar la raíz cuadrada de a si necesita usarlo varias veces. veces. O expresiones más complicadas como a²b y su raíz cuadrada a√b , donde el primero es un identificador válido y el segundo no. Sobre todo, me gusta la consistencia.

Entonces, por consistencia, me gusta la propuesta de tener operadores de sufijo cuando se usan paréntesis (A)ᵀ , (a)² , en combinación con la eliminación del operador unario Unicode (y sus parientes) para que también se puede usar en identificadores (mientras aún se puede acceder a ella como una llamada de función normal √(a) ).

Estoy 100% de acuerdo con lo que dijo @Jutho y lo he pensado en varias ocasiones. ¿Te importaría abrir un problema, @Jutho? Propuesta: permitir en nombres de identificadores, requerir √(x) para llamar como op.

siguiente pregunta -> ¿qué pasa con 2 |> √ ?

Hablemos de en otro hilo, pero en resumen 2 |> √ significa √(2) .

Otra alternativa, que no requeriría cambios en el analizador y sería fácil de escribir, sería A^T para la transposición (definiendo T como un tipo singleton con un método ^ ). … oh, veo que @mbauman también tuvo esta idea. Es un poco feo, pero no más que A.' .

No tengo experiencia, pero estoy muy interesado en el resultado de esta discusión, ya que probablemente escribirá miles de líneas que contienen expresiones matriciales en el curso de mi trabajo.

transpose(A) # with no special syntax está ganando la votación anterior, pero es doloroso para mis ojos y dedos.

En python, el uso común es probablemente con numpy y muchas cosas que se parecen a las siguientes y no son tan malas:

import numpy as np
# define matrix X of n columns, with m rows of observations
error = X.dot(Theta.T) - Y
gradient = (1 / m) * (X.dot(Theta.T) - Y).T.dot(X)

No me gustaría tener que hacer:

grad = 1/m * transpose(X * transpose(Theta) - Y)) * X

Cambia totalmente la concepción mental de la transposición de la convención en la que se ha asentado la notación matemática, que es un significante posfijo, generalmente Aᵀ o Aᵗ .

Personalmente, estoy muy contento con A' que funciona en Julia v.0.6, antes de que lo tomara adjunto. ¿Se usa adjunto con mucha frecuencia?

Aquí están mis comentarios en una tabla:

Aᵀ or Aᵗ    if the world won't accept unicode operators, let them use transpose(A)
A'          close to math notation, easy to type and *especially* easy to read
A^'         this could signal `^` not to be parsed as Exponentiation.
A.'         conflicts with dotted operator syntax, but at face value OK
A^T or A^t  these are pretty good, but what if variable `T` is meant to be an exponent? 
A.T         same as numpy, same dotted operator collision
t(A)        nesting reverses semantics, 3 keystrokes and two of them with shift key.
transpose(A) with no special syntax     # please don't do this.

Personalmente, estoy muy contento con A' que funciona en Julia v.0.6, antes de que lo tomara adjunto. ¿Se usa adjunto con mucha frecuencia?

No entiendo, A' siempre ha sido el adjunto de A . Solíamos llamar a la función subyacente ctranspose para la transposición conjugada, pero le cambiamos el nombre al término equivalente adjoint sin cambios en la funcionalidad.

Si está haciendo álgebra lineal, es mucho más probable que desee una transposición conjugada de todos modos, por lo que escribirá A' en lugar de transpose(A) . La popularidad de no definir una sintaxis especial para transposiciones no conjugadas se debe (presumiblemente) en parte al hecho de que en realidad no es tan común que la mayoría de los usos algebraicos lineales deseen la transposición no conjugada.

Si estás haciendo álgebra lineal, entonces...

Si tu herramienta es un martillo entonces... :)

... tienes que pensar en la posibilidad de que Julia pueda convertirse en un lenguaje de programación general.

Tal vez no, tal vez siga siendo jerga de álgebra lineal, que es una posibilidad que tienen que pensar los programadores como yo. :)

@mahiki , eres un ejemplo de NumPy:

import numpy as np
# define matrix X of n columns, with m rows of observations
error = X.dot(Theta.T) - Y
gradient = (1 / m) * (X.dot(Theta.T) - Y).T.dot(X)

se escribiría literalmente en Julia como:

error = X*Θ' - Y
gradient = (1/m) * (X*Θ' - Y)' * X

o suponiendo que los vectores son filas en ese ejemplo de NumPy y serían columnas en Julia:

error = X'Θ - Y
gradient = (1/m) * (X'Θ - Y) * X'

que parece tan claro y matemático como parece. Si sus datos son reales, entonces adjuntar y transponer son la misma operación, que puede ser la razón por la que está usando la transposición anterior, pero matemáticamente adjunta es la operación correcta. Como dijo @ararslan , X' siempre ha significado adjoint en Julia (y también en Matlab). Anteriormente se llamaba ctranspose abreviatura de " transposición conjugada ", pero ese nombre era inapropiado ya que la propiedad definitoria del operador es que

dot(A*x, y) == dot(x, A'y)

que es la propiedad definitoria del adjunto hermitiano pero resulta que se cumple con la transpuesta conjugada cuando A es una matriz compleja. Es por eso que "adjunto" es el término genérico correcto para este operador.

Dicho todo esto, voté arriba tanto por transpose(a) como a.' ya que creo que estaría bien que a.' significara transposición estructural. Funcionaría como se esperaba, y aunque no sería recursivo y, por lo tanto, no sería "matemáticamente correcto" en algún código genérico, parece suficiente que funcione como se esperaba. Y decirle a la gente que considere usar conj(a') en código genérico parece más una cuestión de educación que algo con lo que realmente necesitamos golpear a la gente en la cabeza.

@mahiki Si por alguna razón realmente necesita usar transpose en lugar de adjoint muchas veces en su código, entonces podría definir una macro más corta como @t alias transpose (aunque sé que esta solución no es ideal, especialmente si estás escribiendo tu código con otras personas).

tienes que pensar en la posibilidad de que Julia pueda convertirse en un lenguaje de programación general.

@Liso77 Ya lo es. Solo como uno de los muchos ejemplos, Nanosoldier ejecuta un servidor web que escucha los eventos de GitHub y ejecuta puntos de referencia de rendimiento a pedido, todo en Julia. Sin embargo, eso es una digresión, y no quiero que este hilo se salga del tema.

Si está transponiendo una matriz de algún tipo con datos no numéricos, que es un caso de uso completamente válido, la notación de transposición matemática en realidad parece un mal juego de palabras. En ese caso, creo que sería mejor ser más explícito sobre lo que está pidiendo, por ejemplo, transpose (o incluso permutedims , dependiendo de sus necesidades específicas).

Si está transponiendo una matriz de algún tipo con datos no numéricos, que es un caso de uso completamente válido, la notación de transposición matemática en realidad parece un mal juego de palabras.

Dado que A.' no es realmente una "notación de transposición matemática" en el sentido habitual, no veo que este sea un argumento a favor o en contra.

Creo que @ararslan no está argumentando en contra del .' existente, sino en contra de la introducción de una sintaxis de superíndice-T. Tiendo a estar de acuerdo: si te refieres al concepto de álgebra lineal de adjunto, entonces deberías usar ' (incluso si tu matriz resulta ser real). Y si tiene una matriz de datos no numéricos, entonces, por supuesto, es perfectamente legítimo permutar los dos índices, pero esta operación no es realmente la "transposición" como solemos pensar, y usar la notación matemática de superíndice-T es probablemente sea más probable que confunda que que aclare. La única situación en la que una notación de superíndice-T sería realmente apropiada es si tiene una matriz numérica cuyos índices desea permutar, pero realmente no desea el operador lineal adjunto. Tales situaciones ciertamente existen, pero pueden ser demasiado raras para justificar la introducción de una nueva sintaxis.

... pero esta operación no es realmente la "transposición" como solemos pensar, ...

Si esto es tan inusual, ¿por qué ararslan y muchos otros votan por la transposición estructural ortográfica como transpose(A) ?

Gracias @StefanKarpinski @ararslan @ttparker. Tuve que volver a mi texto de álgebra lineal y redescubrir el adjunto, está ahí bien. Tomé eso antes de Complex Analysis, probablemente por qué no lo noté.

me encanta poder hacer esto
gradient = (1/m) * (X'Θ - Y) * X'

Mi confusión proviene del uso generalizado de 'transponer' (como un superíndice T) en documentos de referencia, artículos, libros de texto, etc., por ejemplo, las notas de la conferencia stanford CS229 de Andrew Ng , donde el código de Julia correspondiente usaría adjoint como en el ejemplo limpio de @StefanKarpinski arriba. Esto se debe a que adjunto y transpuesto son equivalentes en ℝ (¿verdad?) . actualización: sí

Ahora, mi notación favorita para la transposición es simplemente lo que sea lógicamente consistente. Claramente .' no se debe a un conflicto con la sintaxis del operador punteado, y no tengo ninguna objeción a transpose(A) sin una sintaxis especial, ya que no parece estar disponible una sintaxis especial sana, excepto por un superíndice Unicode.

Me gusta la solución @ttparker si me encuentro escribiendo mucha transposición, macro @t que alias transpose .

Una vez más, me equivoqué al decir:

transpose(A) with no special syntax # please don't do this.

Gracias por tomar mis comentarios en serio a pesar de mi poca facilidad con las matemáticas de nivel de posgrado.

(Del discurso .)

Me gustaría que ' sea un operador de arreglo posterior que asigne f' a '(f) donde Base.:'(x::AbstractMatrix) = adjoint(x) y el usuario es libre de agregar otros métodos que tengan nada que ver con los adjuntos. (Por ejemplo, a algunas personas les puede gustar f' para referirse a df/dt).

Con los sufijos de operadores introducidos en 0.7, entonces sería natural que f'ᵃ se asignara a 'ᵃ(f) , y así sucesivamente, lo que permitiría al usuario definir sus propios operadores de sufijos. Esto haría posible tener Base.:'ᵀ(x::AbstractMatrix) = transpose(x) y Base.:'⁻¹(x::Union{AbstractMatrix,Number}) = inv(x) , etc.

Escribir A'ᵀ quizás no sea tan limpio como Aᵀ , pero no requeriría desaprobar los nombres de variables que terminan en .

A primera vista, parece que podría ser una característica que no se rompa. Es un compromiso muy inteligente. Me gusta.

Me parece razonable. La parte más difícil es encontrar un nombre para la función ' ; la sintaxis de prefijo no funciona en este caso.

La parte más difícil es pensar en un nombre para la función '

apostrophe ? Puede que sea demasiado literal...

¿Es posible hacer que la sintaxis de prefijos funcione (por ejemplo, con una sintaxis explícita (')(A) ?)? Si no, entonces eso es un problema, ya que rompería la regla si-puedes-definir-el-nombre-del-símbolo-entonces-puedes-anular-su-sintaxis introducida por https://github.com/JuliaLang /julia/tirar/26380.

Editar: parece estar disponible:

julia> (')(A)


ERROR: syntax: incomplete: invalid character literal

julia> (')(A) = 2


ERROR: syntax: incomplete: invalid character literal

Desafortunadamente ' es uno de los caracteres más difíciles de usar como nombre de identificador, ya que introduce un tipo diferente de átomo (caracteres), que tiene una precedencia muy alta (igual a la precedencia de los propios identificadores). Por ejemplo, ¿es (')' una aplicación de ' a sí mismo, o un paréntesis abierto seguido de un literal ')' ?

Una opción que no es práctica a corto plazo es declarar que los caracteres literales no valen ' y usar una macro de cadena como c"_" en su lugar.

¿Qué tal si ' se analiza como un identificador cuando está precedido por un punto y dos puntos, de modo que Base.:' funcione?

Por supuesto (@__MODULE__).:'(x) = function_body puede ser un poco engorroso de escribir, pero (x)' = function_body debería funcionar igual. Editar: No, ya que (x)' debería asignarse a llamar a ' en Base . Definir una función ' en el módulo actual sería engorroso, pero tampoco habría ninguna razón para hacerlo.

O qué tal dejar que '' se analice como el identificador ' cuando, de lo contrario, se habría analizado como un carácter literal vacío (que actualmente es un error de nivel de análisis). Del mismo modo, ''ᵃ se analizaría como el identificador 'ᵃ , etc.

Todo lo que actualmente no es un error de sintaxis aún se analizaría como antes (por ejemplo 2'' es el postfijo ' aplicado dos veces a 2 ), pero 2*'' ahora analizar como dos veces ' .

Parece confuso que tendríamos a'' === a pero ''(a) === a' . Parece mejor usar Base.apostrophe como nombre (o algo así).

¿Sería mejor dividir esta discusión en un nuevo problema de Github, ya que se trata de una sintaxis de ' que no está directamente relacionada con la transposición de matriz?

¿Existe una forma automatizada de dividir los problemas, o simplemente debería abrir uno nuevo y vincular a la discusión aquí?

Este último

La única situación en la que una notación de superíndice-T sería realmente apropiada es si tiene una matriz numérica cuyos índices desea permutar, pero realmente no desea el operador lineal adjunto. Tales situaciones ciertamente existen, pero pueden ser demasiado raras para justificar la introducción de una nueva sintaxis.

Supongo que llegué demasiado tarde para la discusión, pero me gustaría señalar un uso que creo que vale la pena mencionar: aplicar la diferenciación de pasos complejos a una función de valor real que tiene transpose dentro de eso. (Personalmente descubrí que necesitaba .' en MATLAB y julia por este motivo en particular).

Daré un ejemplo con múltiples apariciones de transpose (¿tal vez podría evitar hacerlo de esta manera?)

using LinearAlgebra

# f : Rⁿ → R
#     x  ↦ f(x) = xᵀ * x / 2
f(x) = 0.5 * transpose(x) * x

# Fréchet derivative of f
# Df : Rⁿ → L(Rⁿ, R)
#      x  ↦ Df(x) : Rⁿ → R (linear, so expressed via multiplication)
#                   h  ↦ Df(x)(h) = Df(x) * h
Df(x) = transpose(x) 

# Complex-step method version of Df
function CSDf(x) 
    out = zeros(eltype(x), 1, length(x))
        for i = 1:length(x)
        x2 = copy(x) .+ 0im
        h = x[i] * 1e-50
        x2[i] += im * h
        out[i] = imag(f(x2)) / h
    end
    return out
end

# 2nd Fréchet derivative
# D2f : Rⁿ → L(Rⁿ ⊗ Rⁿ, R)
#       x  ↦ D2f(x) : Rⁿ ⊗ Rⁿ → R (linear, so expressed via multiplication)
#                     h₁ ⊗ h₂ ↦ D2f(x)(h₁ ⊗ h₂) = h₁ᵀ * D2f(x) * h₂
D2f(x) = Matrix{eltype(x)}(I, length(x), length(x))

# Complex-step method version of D2f
function CSD2f(x)
    out = zeros(eltype(x), length(x), length(x))
    for i = 1:length(x)
        x2 = copy(x) .+ 0im
        h = x[i] * 1e-50
        x2[i] += im * h
        out[i, :] .= transpose(imag(Df(x2)) / h)
    end
    return out
end 

# Test on random vector x of size n
n = 5
x = rand(n)
Df(x) ≈ CSDf(x)
D2f(x) ≈ CSD2f(x)

# test that the 1st derivative is correct Fréchet derivative
xϵ = √eps(norm(x))
for i = 1:10
    h = xϵ * randn(n) # random small y
    println(norm(f(x + h) - f(x) - Df(x) * h) / norm(h)) # Fréchet check
end

# test that the 2nd derivative is correct 2nd Fréchet derivative
for i = 1:10
    h₁ = randn(n) # random h₁
    h₂ = xϵ * randn(n) # random small h₂
    println(norm(Df(x + h₂) * h₁ - Df(x) * h₁ - transpose(h₁) * D2f(x) * h₂) / norm(h₂)) # Fréchet check
end
# Because f is quadratic, we can even check that f is equal to its Taylor expansion
h = rand(n)
f(x + h) ≈ f(x) + Df(x) * h + 0.5 * transpose(h) * D2f(x) * h

El punto es que f y Df deben definirse usando transpose y no deben usar el adjunto.

No creo que el método de pasos complejos sea muy relevante en julia. ¿No es un buen truco/solución para obtener una diferenciación automática en los casos en que un idioma admite números complejos integrados eficientes, pero no se puede definir un tipo de número Dual equivalentemente eficiente? Ese no es el caso en julia, que tiene muy buenas bibliotecas de diferenciación automática.

Estoy de acuerdo con el uso de números duales en lugar del método de pasos complejos y ese es un punto muy bueno que está haciendo (personalmente, ya he reemplazado todas mis evaluaciones del método de pasos complejos con números duales en julia). Sin embargo, creo que este sigue siendo un caso de uso válido, con fines de demostración, trucos de enseñanza (ver, por ejemplo, Nick Higham hablando sobre el método de pasos complejos en Julia Con 2018 ) y portabilidad (en otras palabras, me preocupa que La versión de MATLAB del código anterior usando números complejos sería más limpia).

Viniendo del mundo de los ingenieros y posiblemente de los físicos que usan matrices complejas más que matrices reales, no tener un operador de transposición es un poco molesto. (La representación fasorial compleja para una dependencia armónica del tiempo es omnipresente en nuestro campo). Personalmente, preferiría la sintaxis numpy de xH y xT, aunque mi única consideración es la concisión.

La densidad del operador de transposición en relación con la transposición de Hermitian es de aproximadamente 1 a 1 en mi código. Entonces, la transposición no conjugada es igualmente importante para mí. Gran parte del uso de la transposición es para crear productos externos y dimensionar matrices correctamente para interactuar con otro código o para la multiplicación de matrices.

Por ahora, tengo la intención de simplemente proporcionar una macro o una función de un carácter para la operación, sin embargo, ¿cuál es el equivalente adecuado a la funcionalidad anterior, transpose() o permutedims()?

transpose está diseñado para álgebra lineal y es recursivo, y permutedims es para arreglos no recursivos de datos de cualquier tipo.

Es interesante que digas que usas la transposición tanto como la adjunta. Solía ​​ser el mismo, pero principalmente porque tendía a cometer errores donde mis datos eran reales, así que tendía a transponer, pero en realidad el adjunto era la operación correcta (generalizado al caso complejo: el adjunto era la operación correcta para mi algoritmo). Hay (muchas) excepciones válidas, por supuesto.

En todo lo relacionado con la electrodinámica, a menudo usa vectores espaciales y quiere usar operaciones vectoriales en R^n (típicamente n=3), es decir, transpose en particular, aunque sus vectores tienen valores complejos porque usted He tomado una transformada de Fourier. Parece que @mattcbro está hablando de este tipo de aplicaciones.

Dicho esto, cuando leo sobre las discusiones de sintaxis, a menudo pienso que, personalmente, no puedo imaginar que una sintaxis un poco más detallada sea lo que ralentiza mi velocidad o eficiencia de programación. Pensar en el algoritmo en sí y en la forma más natural/eficiente de implementarlo lleva mucho más tiempo.

En todo lo relacionado con la electrodinámica, a menudo usa vectores espaciales y desea usar operaciones vectoriales en R ^ n (típicamente n = 3), es decir, transponer en particular, aunque sus vectores tienen valores complejos porque ha tomado un Fourier transformar.

No necesariamente. A menudo, desea cantidades promedio en el tiempo de las amplitudes de Fourier, en cuyo caso usa el producto escalar complejo, por ejemplo, ½ℜ[𝐄*×𝐇] es el flujo de Poynting promedio en el tiempo de los componentes complejos de Fourier y ¼ε₀|𝐄|² es un densidad de energía de vacío promedio en el tiempo. Por otro lado, dado que el operador de Maxwell es (típicamente) un operador simétrico complejo ("recíproco"), a menudo se usa un "producto interno" no conjugado para el álgebra (de dimensión infinita) en los campos 𝐄(𝐱), etc. todo el espacio

Eso es cierto, tenía la palabra a menudo en la primera oración, pero aparentemente la eliminé :-).

Bueno, si quieres ir allí, las cantidades electromagnéticas se escriben de manera aún más concisa en una formulación algebraica de Clifford, a menudo llamada álgebra geométrica. Esas álgebras tienen múltiples automorfismos y antiautomorfismos que juegan un papel crítico en la formulación de la teoría, especialmente cuando se consideran problemas de dispersión.

Estas álgebras suelen tener una representación de matriz concisa y esos morfismos a menudo se calculan fácilmente mediante transposición compleja, transposición hermitiana y conjugación.

Sin embargo, como dije anteriormente, mi uso principal de la transposición es a menudo organizar mis arreglos para que interactúen con otros arreglos, otro código y hacer que la multiplicación de matrices funcione con la dimensión correcta de un arreglo aplanado.

Yo personalmente preferiría la sintaxis numpy de xH y xT

Fácil de implementar ahora en 1.0, y debería ser eficiente:

function Base.getproperty(x::AbstractMatrix, name::Symbol)
    if name === :T
        return transpose(x) 
    #elseif name === :H # can also do this, though not sure why we'd want to overload with `'`
    #    return adjoint(x)
    else
        return getfield(x, name)
    end
end 

Esto es sorprendentemente fácil y algo aseado. La desventaja parece ser que los usos ortogonales de getproperty no se componen entre sí. Por lo tanto, cualquiera que implemente getproperty en su tipo de matriz específico deberá implementar el comportamiento genérico a mano.

usos ortogonales de getproperty no componen

Mmm. Me pregunto si eso implica que xT "debería" haberse reducido a getproperty(x, Val(:T)) . Sin embargo, me estremezco al pensar qué le haría eso al pobre compilador.

Estoy seguro de que todos tienen su opinión, pero para mí es casi una característica que es difícil construir una interfaz genérica a partir de la sintaxis de puntos. No me malinterpreten, es una función realmente excelente y maravillosa para definir estructuras tipo tupla con nombre, etc.

(También es posible agregar una capa de despacho Val a sus tipos con bastante facilidad).

El código de @ c42f funciona de maravilla. Desafortunadamente para mí, estoy tratando de escribir un código que funcione en las versiones 0.64 y posteriores, lo que me obliga a usar transponer o mi propia función definida T(A) = transponer(A). Quizás una macro hubiera sido un poco más limpia y un poco más eficiente.

Para ser claros, no estoy sugiriendo que definir este getproperty particular sea una buena idea para el código de usuario. Es probable que rompa las cosas a largo plazo ;-) Aunque quizás algún día tengamos una idea lo suficientemente buena de las consecuencias que podríamos tener x.T definido en Base .

Pero en un sentido general, me pregunto por qué este tipo de uso de propiedad para definir "captadores" en interfaces genéricas es realmente malo. Por ejemplo, las funciones genéricas captadoras de campos actualmente tienen un enorme problema de espacio de nombres que se resuelve simplemente mediante el uso juicioso de getproperty . Es mucho mejor escribir x.A que escribir MyModule.A(x) , un nombre de función feo más largo como get_my_A(x) , o exportar el nombre extremadamente genérico A de un usuario módulo. El único problema, tal como lo veo, es la capacidad esperada de anular el significado de .B para los subtipos independientemente de que .A se defina genéricamente en un supertipo. De ahí el comentario medio serio sobre Val .

Idea divertida:

julia> x'̄
ERROR: syntax: invalid character "̄"

El carácter parece un T pero en realidad es un ' con una barra encima. No estoy seguro si es en serio...

screen shot 2018-09-10 at 11 29 56

Sí, también me parece eso en GitHub. Pero es un overbar. Copiar y pegar en mi terminal muestra:

screen shot 2018-09-10 at 10 31 24 am

Demasiado inteligente y lindo. Sin embargo, todavía me gusta la combinación de caracteres, y creo que 'ᵀ está bien.

-100 para cambiar el adjunto, ya que es una de las cosas asombrosas que hace que escribir el código de Julia sea tan claro como escribir matemáticas, además, la transposición conjugada es generalmente lo que desea de todos modos, por lo que tiene sentido tener una sintaxis abreviada para ello.

Hay una cierta arrogancia en una declaración como esta. Considere que una proporción finita de desarrolladores explícitamente _no_ quiere adjoint() pero _necesita_ transpose() .

Caso y punto para nosotros trabajando con cálculos simbólicos para modelar el operador predeterminado ' haría que, por ejemplo, el pseudo-inverso (A'*A)\(A *b) o una forma cuadrática v'*A*v regresaran erróneamente resultados largos y complejos que no se pueden reducir.

Tal vez la solución sea algún tipo de directiva de compilación que declare el significado de ' .

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

i-apellaniz picture i-apellaniz  ·  3Comentarios

Keno picture Keno  ·  3Comentarios

wilburtownsend picture wilburtownsend  ·  3Comentarios

omus picture omus  ·  3Comentarios

StefanKarpinski picture StefanKarpinski  ·  3Comentarios