Julia: nova sintaxe para transposição

Criado em 15 mar. 2017  ·  103Comentários  ·  Fonte: JuliaLang/julia

Agora que .op é geralmente a forma vetorizada de op , é muito confuso que .' signifique transpor em vez da forma vetorizada de ' (adjoint, também conhecido como ctranspose ). Esta edição é para discutir sintaxes alternativas para transposição e/ou adjunção.

linear algebra parser

Comentários muito úteis

Opor-se fortemente a fazer tr(A) transpor matriz média - todo mundo vai pensar que significa traço de matriz: https://en.wikipedia.org/wiki/Trace_ (linear_algebra)

Todos 103 comentários

Andreas tentou Aᵀ (e talvez Aᴴ ) em #19344, mas não foi muito bem recebido. Da mesma forma, poderíamos trocar ^ com tipos de expoentes especiais T (e talvez H ) de modo que A^T seja transposto, mas isso também é bastante obscuro. Não tenho certeza se existem muitas outras boas opções que ainda se parecem com notação matemática.

Eu meio que acho que t(A) pode ser o melhor, mas é lamentável "roubar" outro nome de uma letra.

Movendo meu comentário do outro problema (não que resolva alguma coisa, mas ...):

+1 por usar algo diferente de .' .

Não consegui encontrar linguagens com uma sintaxe especial para transposição, exceto para APL que usa o não tão óbvio , e Python que usa *X (o que seria confuso para Julia). Vários idiomas usam transpose(X) ; R usa t(X) . Isso não é bonito, mas não é pior do que .' . Pelo menos você fica menos tentado a usar ' confundindo-o com .' : ficaria claro que essas são operações muito diferentes.

Veja o código Rosetta . (BTW, o exemplo de Julia realmente ilustra a transposição conjugada ...)

Um dos outros ticks poderia ser usado? ` ou "

-100 para alterar adjoint, já que é uma das coisas incríveis que torna escrever código Julia tão claro quanto escrever matemática, mais a transposição conjugada geralmente é o que você quer de qualquer maneira, então faz sentido ter uma sintaxe abreviada para isso.

Contanto que tenhamos a sintaxe legal para transposição conjugada, um operador pós-fixado para transposição regular parece desnecessário, então apenas ter uma chamada de função regular parece bom para mim. transpose já funciona; não poderíamos simplesmente usar isso? Acho o t(x) R-ismo infeliz, pois não está claro pelo nome o que ele realmente deveria fazer.

Usar um tick diferente seria meio estranho, por exemplo, A` pode se parecer muito com A' dependendo da fonte, e A" se parece muito com A'' .

Se fizermos a alteração em #20978, então uma transposição pós-fixada se tornará mais útil do que é agora. por exemplo, se você tem dois vetores x e y e deseja aplicar f aos pares, você pode fazer, por exemplo f.(x, y.') ... com #20978 , isso será aplicável a arrays de tipos arbitrários.

Honestamente, acho que nossa melhor opção ainda é deixar como está. Nenhuma das sugestões parece ser uma melhoria clara para mim. .' tem a vantagem da familiaridade com o Matlab. O . na verdade é um pouco congruente com a sintaxe de chamada de ponto em exemplos como f.(x, y.') , e sugere (um pouco corretamente) que a transposição "se funde" (não produz uma cópia temporária graças a RowVector e futuras generalizações).

Na verdade, poderíamos ir mais longe e fazer f.(x, g.(y).') uma operação de fusão. ou seja, alteramos .' transpose para ser não recursiva ala #20978 e estendemos sua semântica para incluir a fusão com outras chamadas de ponto aninhadas. (Se você quiser a versão sem fusão, você chamaria transpose .)

Eu gosto muito desse plano, @stevengj.

Uma ruga: presumivelmente a macro @. não transforma y' em y.' (já que isso seria errado). Poderia, no entanto, transformar y' em algum tipo de operação adjunta fundida.

O principal problema é encontrar uma maneira limpa de fazer f.(x, g.(y).') ter uma semântica de fusão. Uma possibilidade seria transformá-lo em f.(x, g.(y.')) e, portanto, em broadcast(x,y -> f(x, g(y)), x, y.') ?

Observe que, para que isso funcione corretamente, podemos precisar restaurar o método de fallback transpose(x) = x , caso em que podemos deixar a transposição permanecer recursiva.

Acho que decidir se a transposição deve ser recursiva ou não é ortogonal para que ela participe da fusão de sintaxe de ponto. A escolha de torná-lo não recursivo não é motivada por isso.

@StefanKarpinski , se restaurar um fallback transpose(x) = x , a maior parte da motivação para alterá-lo para não recursivo desaparece.

Qual é o problema se o fallback for restaurado, mas ainda tivermos a transposição não recursiva?

@jebej , a transposição recursiva é mais correta quando usada como uma operação matemática em operadores lineares. Se bem me lembro, o principal motivo para torná-lo não recursivo foi para que não tenhamos que definir o fallback transpose(x) = x , em vez de lançar um MethodError.

Mas não seria terrível ter o fallback, mas ainda ser não recursivo.

Deixe-me adicionar dois comentários (dei uma olhada na discussão anterior e não os notei - desculpe se omiti algo):

  • documentação para permutedims diz Esta é uma generalização de transposição para arrays multidimensionais. transpose , o que não é.
  • Como se deve fazer uma transposição de um vetor x=["a", "b"] ? Na verdade y=x.' funciona e cria uma nova variável, mas getindex falha nela. AFAIK terá de usar reshape(x, 1, :) ou hcat(x...) muito mais lento para o conseguir mas não é natural ter uma sintaxe diferente para Vector ( permutedims não funciona aqui ).

Qual é o seu caso de uso para transpor um vetor de strings?

Considere o seguinte cenário, por exemplo:

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

e quero acrescentar y após a última linha de x . E a maneira mais simples é vcat uma transposição de y .

Aparece na prática ao registrar dados de texto incrementalmente em um Matrix{String} (eu poderia usar Vector{Vector{String}} ), mas geralmente a matriz é mais útil (ou, novamente, há uma pergunta como converter Vector{Vector{String}} a Matrix{String} concatenando verticalmente elementos consecutivos).

Outro caso de uso: a transposição é a maneira mais simples de tornar dois vetores ortogonais entre si para transmitir uma função sobre o produto cartesiano ( f.(v, w.') ).

Ponto de dados: Ontem eu encontrei uma parte confusa com o operador postfix "broadcast-adjoint" e por que ele se comporta como transpose. Melhor!

FWIW, eu sinto fortemente que devemos nos livrar da sintaxe .' . Como alguém mais familiarizado com Julia do que com Matlab, eu esperava que isso significasse adjunto vetorizado e fiquei realmente tropeçado quando isso não aconteceu. Julia não é Matlab e não deve ser limitada pelas convenções do Matlab - se em Julia, um ponto significa vetorização da função adjacente, então isso deve ser consistente em toda a linguagem e não deve ter aleatoriamente a única exceção horrível que .' não está formalmente relacionado a ' .

Eu acho que é bom ter apenas transpose sem nenhuma notação especial de "tick", já que na grande maioria das vezes, é chamado em uma matriz de números reais, então ' seria equivalente se você realmente deseja economizar digitação. Se quisermos fazer uma versão de fusão de transpose, então eu realmente não acho que .' seja a sintaxe correta.

Este é um bom ponto. Indiscutivelmente, apenas o adjunto precisa de uma sintaxe super compacta.

Vamos apenas chamar isso de transpose e descontinuar .' . No futuro, podemos considerar se queremos .' como adjunto pontual ou se queremos apenas deixá-lo obsoleto para evitar prender usuários do Matlab.

Observe que eu apenas grepped os pacotes registrados e encontrei mais de 600 usos de .' , então não é muito raro. E com chamadas de ponto / broadcast (que somente na versão 0.6 começou a lidar totalmente com dados não numéricos), o desejo de transpor preguiçosamente arrays não numéricos (onde adjunto faz menos sentido) provavelmente se tornará muito mais comum, então o argumento para uma sintaxe compacta é um pouco fortalecido.

Então é melhor descontinuar .' o mais rápido possível, antes que mais código fique preso em um padrão de uso ruim.

Por que é ruim?

O problema é que .' agora não significa o que parece significar como operador pontilhado.

Como eu disse acima, porque viola o padrão geral de que . significa vetorização e parece que significa adjunto vetorizado (especialmente para alguém que não está familiarizado com o Matlab).

Acho que @stevengj faz um bom argumento – isso está ligado ao desejo de uma transposição não recursiva simples.

Eu sei que foi impopular, mas estou começando a preferir o #19344 de Andreas por . Neste ponto, eu prefiro depreciar o uso de _all_ sobrescritos como identificadores e interpretar _qualquer_ sobrescritos à direita como operadores pós-fixados. Isso também fornece um caminho para resolver alguns dos kludginess em torno de literal_pow usando números sobrescritos. Sim, seria triste perder χ² e nomes de variáveis, mas acho que os benefícios superariam as desvantagens.

Neste ponto, eu prefiro depreciar o uso de _all_ sobrescritos como identificadores e interpretar _qualquer_ sobrescritos à direita como operadores pós-fixados.

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

Neste ponto, eu seria a favor de descontinuar o uso de todos os sobrescritos como identificadores

Eu realmente não acho que isso seria necessário, quando queremos apenas T e talvez algumas outras coisas no futuro.

Uma consistência tola…

Sim, é um pouco inconsistente usar .' para transposição, mas todas as alternativas propostas até agora parecem ser piores. Não é a pior coisa do mundo dizer " .' é transposição, uma exceção à regra usual sobre operadores de ponto." Você aprende isso e segue em frente.

Uma coisa a notar que pode ajudar com qualquer confusão potencial sobre .' não ser uma transmissão de ponto é que é um operador pós-fixado, enquanto a transmissão de prefixo é op. e infixa é .op . Então podemos dizer que . não significa broadcast quando é postfix. O outro uso do postfix . é pesquisa de campo, e getfield(x, ') não faz sentido, então é diferente de outros significados.

(Dito isso, sou a favor transpose(x) a manter .' .)

@stevengj Aposto que muitos (talvez a maioria) dos mais de 600 usos de .' nos pacotes registrados que você mencionou acima poderiam ser substituídos por ' sem nenhum custo para a legibilidade e o código continuaria a trabalhar.

Possivelmente não é popular, mas ainda pode haver postfix " e ` ?

usos de .' nos pacotes registrados que você mencionou acima poderia ser substituído por ' sem nenhum custo para a legibilidade, e o código continuaria funcionando.

Observe que quando #23424 chegar, poderemos usar transpose em arrays de strings e assim por diante, mas não adjoint . A melhor prática para o uso de álgebra linear de x.' provavelmente se tornará algo como conj(x') (espero que isso seja preguiçoso, ou seja, gratuito). Embora eu adore usar .' por sua compacidade, talvez se livrar dele forçará os usuários de álgebra linear a usar a coisa correta e os usuários de matrizes de dados a usar transpose .

ainda pode haver postfix " e `?

A nova sintaxe para transpose() parece bastante prematura. IMHO, seria melhor apenas depreciar .' para ser substituído como você sugere por conj(x') e transpose conforme necessário.

Tenho a sensação de que .' é tão útil no matlab principalmente por causa da insistência do matlab de que "tudo é uma matriz", juntamente com a falta de regras de fatiamento coerentes, de modo que você geralmente precisa inserir transposições aleatórias em vários lugares para fazer as coisas funcionarem.

Para resumir os argumentos aqui:

  1. .' agora é o único destaque como um operador pontilhado que não significa "aplicar operador undotted elementwise"; novos usuários que não vêm do Matlab acham isso uma armadilha surpreendente.

  2. .' agora é efetivamente ambíguo: você quis dizer transpose ou você quis dizer conj(x') ? Em princípio, todo uso legado de .' deve ser verificado para determinar se está permutando os índices de uma matriz bidimensional ou se está fazendo um "adjunto não conjugado".

A primeira questão é problemática, mas não fatal por si só; a segunda questão é a realmente ruim – esta não é mais uma única operação coerente, mas será dividida em dois significados separados.

Acabei de notar que se alguma vez alterássemos .' para significar "adjunto elementar", então conj(x') seria aproximadamente equivalente a x'.' e conj(x)' seria aproximadamente x.'' que é tão perto de x.' 😬.

Possivelmente não é popular, mas ainda pode haver postfix " e `?

Copie colando o código no Slack e vendo que destruir o realce da sintaxe seria ...

Ser capaz de transpor qualquer coisa é bom porque facilita o "produto cruzado" por meio do mecanismo de despacho e outros casos de uso curtos e concisos como esse. O problema de não ter um fallback fácil para esse tipo de coisa é que invariavelmente o hack que veremos é apenas definir fallbacks transpose(x) = x (ou em tipos Base, então pirataria de tipos em pacotes) para fazer isso tipo de coisa funciona facilmente. Isso me faz pensar: por que Complex não é o estranho? Adjunto da maioria dos números é ele mesmo, então adjunto do complexo é aquele em que se especializar: isso não pode ser estendido além dos números?

Eu vejo duas coisas muito relacionadas aqui:

1) x' não funciona para tipos não numéricos, então queremos uma maneira de fazer isso facilmente para outros dados
2) transpose(x) não é tão simples quanto x.' . Isto é principalmente para os casos de (1), uma vez que os casos de uso para transposição de matrizes complexas são muito mais raros.

Mas em vez de diminuir (2), por que não tentar fazer uma correção razoável para (1)?

Talvez uma correção razoável seja apenas uma macro que faça ' significar transpor em vez de adjunto?

Mas em vez de diminuir (2), por que não tentar fazer uma correção razoável para (1)?

Já percorremos esse caminho e vários adjacentes a ele. Houve uma grande quantidade de discussão resultante que talvez outra pessoa possa destilar, mas em resumo, não funciona bem. Fundamentalmente, a operação matemática adjoint não faz sentido em coisas que não são números. Usar ' em não números só porque você gosta da sintaxe concisa é ruim – é o pior tipo de trocadilho de operador e não deveria ser surpresa que coisas ruins resultem desse tipo de abuso de significado. A função adjoint deve ser definida apenas em coisas que faz sentido usar o adjunto e ' deve ser usado apenas para significar isso.

Lembre-se que .' como usado atualmente é fundamentalmente duas operações diferentes: transposição de array e adjunto não conjugado. O problema de transposição recursiva destaca o fato de que essas são operações diferentes e que, portanto, precisamos de maneiras diferentes de expressá-las. O pessoal da matemática parece inflexível que a operação adjunta não conjugada é (a) importante e (b) diferente da simples troca de dimensões. Em particular, para ser correto, o adjunto não conjugado deve ser recursivo. Por outro lado, a troca de dimensões de uma matriz genérica claramente não deve ser recursiva. Portanto, essas operações precisam ser escritas de maneira diferente, e os usos existentes de .' precisam ser desambiguados como tendo um significado ou outro. Descontinuar .' é uma maneira de forçar isso.

Finalmente, embora eu sinta fortemente que permutedims(x, (2, 1)) é definitivamente muito inconveniente para trocar as dimensões de uma matriz 2d, acho o argumento de que transpose(x) é muito inconveniente pouco convincente. Essa operação é tão comum que ter um nome de função simples e claro para ela é demais? Mesmo? A troca das dimensões de uma matriz é muito mais comum ou importante do que todas as outras coisas na linguagem para as quais usamos nomes de funções e sintaxe de chamada de função? A notação de Householder torna adjoint bastante especial, pois queremos escrever coisas como v'v , v*v' e v'A*v . É por isso que adjoint fica com uma sintaxe muito boa. Mas trocar as dimensões de um array? Não garante um operador na minha opinião.

Não é um argumento forte, mas costumo usar o operador ' para imprimir arrays de forma mais compacta (quando usado como contêineres simples), por exemplo, quando quero ver o conteúdo de alguns vetores ao mesmo tempo na tela ( e invariavelmente fica frustrado quando falha porque os elementos não podem ser transpostos). Portanto, uma sintaxe curta para o REPL é definitivamente útil. (Além disso, isso torna mais fácil para as pessoas acostumadas a arrays de linha principal, ter uma maneira simples de "mudar a ordem", em particular ao portar algoritmos para julia usando arrays 2d; mas definitivamente também não é um argumento forte). Apenas para dizer que é uma boa sintaxe concisa que não é útil apenas para algebristas lineares.

Eu havia comentado algumas ideias de sintaxe em https://github.com/JuliaLang/julia/pull/19344#issuecomment -261621763, basicamente 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

Mas sem o hack, é claro, apenas a ideia de que pode haver uma espécie de "aplicação de função postfix" e que exige parênteses (x)f , versões pontilhadas podem ser assim (x).f ( xf seria um identificador, mesmo com f sendo um símbolo sobrescrito).

Este exemplo de hack costumava funcionar no 0.6, mas agora:

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            

O que é triste, eu originalmente queria fazer isso para 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 "³"

O que eu ingenuamente pensei que permitiria sintaxe como: n² = (n)² e n³ = (n)³ Mas qualquer tipo de identificador numérico é proibido de estar na primeira posição, porém (A)⁻¹ também funcionou, onde ⁻¹ era const ⁻¹ = inv .

Eu implementei um hack semelhante para InfixFunctions.jl .

Como usuário, eu poderia simplesmente fazer um pacote PostfixFunctions.jl e ficar feliz com o que você encontrar de melhor aqui. Mas atualmente essas restrições de sintaxe:

  • não é permitido usar superíndices numéricos no início de um identificador
  • superindex x * ᶠ no postfix (multiplicação implícita no hack) (x)ᶠ não permitido

Parece um pouco demais para mim IMHO, eu gostaria de pelo menos ser capaz de definir identificadores que podem começar com sobrescritos numéricos, ou mais geralmente, apenas desabilitar caracteres numéricos reais 0-9 com semântica numérica, no início de um identificador, isso seria incrível. 😄

Saúde!

Veja #10762 para alguma discussão de outros caracteres numéricos como identificadores.

O outro problema está relacionado ao #22089, sufixos de operador. +ᵀ agora é um operador válido, que (provavelmente acidentalmente) não permite identificadores que consistem apenas em combinar caracteres em contextos em que um operador pode ser esperado. Isso me parece um bug. Também é um pouco estranho que seja um identificador válido, mas -ᵀ não faça -(ᵀ) . No entanto, isso não é o fim do mundo, e a IMO corrigi-lo não valeria a pena perder outros usos possíveis de .

Observe que usar .' como um operador de transposição pós-fixado não está na mesa aqui (apesar do que o assunto do problema diz), a consideração é realmente se devemos manter .' como um operador pós-fixado para adjunto não conjugado, que seria recursivo. Isso acontece muitas vezes ser o mesmo que transposição, mas geralmente não é a mesma operação. Se o pessoal da álgebra linear está disposto a deixar .' significar transposição de matriz genérica, essa é uma história diferente, mas minha impressão é que isso não é aceitável.

@Ismael-VC, posso ver permitir (x)ᵀ como uma sintaxe de função pós-fixada para sobrescritos - pois o que mais isso significaria? Eu acho que onde sua proposta começa a incomodar as pessoas da maneira errada é permitir que qualquer identificador seja aplicado como uma função na sintaxe do postfix. Eu limitaria a sobrescritos.

@StefanKarpinski , eu pensei que o consenso era precisamente permitir .' significar transposição de matriz não recursiva e não conjugada (se tivermos esse operador), enquanto ' é o conjugado recursivo operação conjunta.

Eu realmente odeio a ideia de usar para um operador de transposição postfix. É muito útil ter como sobrescrito em nomes de variáveis, como aᵀa ou LᵀDL = ltdlfact(A) . (Além do fato de que usar apenas para um operador enquanto outros sobrescritos são válidos em identificadores seria estranho.)

Esse não era o meu entendimento – eu achava que as pessoas linalg eram a favor de manter a.' como está, ou seja, significando conj(a)' . Manter .' mas mudar seu significado para array transpose é bem diferente – não tenho certeza de como me sinto sobre isso. Concordo que ter apenas como operador postfix seria irritante e inconsistente. Gosto bastante da proposta (a)ᵀ do @Ismael-VC, no entanto, que não impediria o uso aᵀ como nome.

Minha memória dessas discussões reflete a de Steven. A transposição recursiva e não conjugada é rara e geralmente muito estranha. Resumo decente aqui: https://github.com/JuliaLang/julia/issues/20978#issuecomment -316141984.

Acho que todos concordamos que o postfix ' é adjunto e deve permanecer.
Acho que todos concordamos que o postfix .' é uma sintaxe abaixo do ideal.
Acho que a maioria concorda que a transposição não recursiva (estrutural) é mais útil do que uma transposição recursiva.

Ok, então os pontos que todos parecem concordar:

  1. Use a' por adjoint(a)
  2. Use conj(a)' ou conj(a') para o adjunto (não-)conjugado.

Portanto, o único ponto de discórdia é como escrever a transposição de matriz:

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

Esta avaliação está correta?

Sim, acho que sim (onde a "transposição de matriz" não é recursiva).

Além disso, pelo que entendi, todos concordam que transpose(a) deve definitivamente ser uma sintaxe válida (e não recursiva), e os únicos pontos de desacordo são se .' e/ou (a)ᵀ deve ser uma sintaxe válida alternativa (completamente equivalente).

Abordagem (1) de https://github.com/JuliaLang/julia/issues/20978#issuecomment -315902532, que recebeu um bom suporte (por exemplo, https://github.com/JuliaLang/julia/issues/20978# issuecomment-316080448), continua a ser uma possibilidade. Eu tenho uma filial realizando essa abordagem (introduzindo flip(A) ) que posso postar.

Pelo que vale, eu apoio a depreciação .' . A confusão e ambiguidade neste segmento é um forte argumento para fazê-lo em si. Melhor!

Acredito que enquanto tivermos o postfix ' , as pessoas vão querer usá-lo para transmitir f sobre um produto cartesiano de vetores com f.(v, w') . E as pessoas vão querer usá-lo para remodelar um vetor de strings em um vetor de linha de cabeçalhos para uma estrutura semelhante a uma tabela. Portanto, é atraente para mim ter um substituto simples e fácil de usar para o qual possamos direcioná-los.

Aqui está uma opção que não consideramos: A*' — um novo bigraph. A notação matemática típica pode interpretar isso como conj(A)' , que na verdade é bem próximo do que queremos. Ele estava disponível na versão 0.6, mas na versão 0.7 permitimos o uso * para concatenar caracteres.

Não acredito que o postfix " e ` estejam disponíveis devido à análise de literais de string personalizados além do final de uma linha. Postfix * por si só também não está disponível pelo mesmo motivo. Postfix prime A′ é provavelmente um dos identificadores unicode mais usados, então é ainda mais fora do que Aᵀ .

Honestamente, depois de olhar para o meu código, eu não uso .' , então transpose(a) provavelmente está bem.

Observe que eu apenas grepped os pacotes registrados e encontrei mais de 600 usos de .', então não é muito raro.

Este local foi verificado para ver se .' não foi usado onde ' estaria bem? Estou começando a pensar que isso pode ser verdade mais frequentemente do que não. Caso contrário, o único lugar onde eu vi um uso legítimo de .' foi antes que os rótulos Plots.jl permitissem um vetor (em vez disso, queria um vetor de linha de strings), mas isso foi alterado. Para códigos em que eu realmente preciso disso com frequência, acho que começaria a fazer T = transpose localmente ou lançaria uma macro para alterar ' para transpose .

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

estaria bem comigo para esse caso raro.

as pessoas vão querer usá-lo para transmitir f sobre um produto cartesiano de vetores com f.(v, w'). E as pessoas vão querer usá-lo para remodelar um vetor de strings em um vetor de linha de cabeçalhos para uma estrutura semelhante a uma tabela. Portanto, é atraente para mim ter um substituto simples e fácil de usar para o qual possamos direcioná-los.

Se ele aparecer apenas uma vez em uma declaração, não há problema em usar apenas transpose ?

A sintaxe a*' para conjugate-adjoint é bem legal, embora não pareça ser essa a operação para a qual precisamos de uma sintaxe melhor. &a estará disponível em breve e sugere a troca de coisas, embora seja bem diferente das notações tradicionais para isso.

Talvez seja hora de uma pesquisa de palha?

Como devemos soletrar a transposição estrutural?

(aproximadamente na ordem da proposta; sem julgamentos sobre os nomes dos emojis aqui)

  • 👍: A.' — apenas mude o significado, mantenha a sintaxe a mesma
  • 👎: transpose(A) — sem sintaxe especial
  • 😄: t(A) ou tr(A) — sem sintaxe especial, mas exporta um nome mais curto
  • 🎉: Aᵀ — com apenas e talvez um ou dois sobrescritos em caixa especial de identificadores
  • 😕: (A)ᵀ — com todos os sobrescritos separados dos identificadores se comportando como operadores postfix
  • ❤️: A*' — passe por cima daquele vale estranho, significa uma transposição estrutural
  • Se você preferir &A , dê um 🎉 no post de Stefan imediatamente acima (estamos sem emojis)

As discussões do LinAlg realmente falaram sobre presentear .’ para uso de transposição não recursiva, já que conj(x’) é relativamente incomum. No entanto é uma sintaxe matemática e realmente deve ter o significado matemático (se houver).

Opor-se fortemente a fazer tr(A) transpor matriz média - todo mundo vai pensar que significa traço de matriz: https://en.wikipedia.org/wiki/Trace_ (linear_algebra)

Se não descontinuar sobrescritos como identificador (que provavelmente deve ser considerado seriamente antes de 1.0), então ᵀ(A) também é uma possibilidade.

Em relação à sugestão (A)ᵀ , minhas desculpas por inviabilizar um pouco esta discussão com a seguinte observação:

Eu nunca me importei muito em ter disponível como operador unário, especialmente porque você vai acabar digitando √(...) assim que você quiser aplicá-lo a uma variável que é mais do que um um ou alguns caracteres. Além disso, sempre achei a diferença de funcionamento entre e √a muito artificial. Provavelmente faz sentido se você souber sobre classes Unicode etc, mas para qualquer outra pessoa isso deve parecer absurdo. Claro que é útil ter como um nome de variável válido, mas da mesma forma √a pode ser um nome de variável útil para armazenar a raiz quadrada de a se você precisar usá-lo vários vezes. Ou expressões mais complicadas como a²b e sua raiz quadrada a√b , onde o primeiro é um identificador válido e o último não. Acima de tudo, gosto de consistência.

Portanto, para consistência, gosto da proposta de ter operadores postfix ao usar parênteses (A)ᵀ , (a)² , em combinação com a remoção do operador unário Unicode (e seus parentes) para que ele também pode ser usado em identificadores (enquanto ainda acessível como chamada de função normal √(a) ).

Concordo 100% com o que @Jutho disse e pensei em várias ocasiões. Você se importaria de abrir um problema, @Jutho? Proposta: permitir em nomes de identificadores, exigir √(x) para chamar como op.

próxima pergunta -> e 2 |> √ ?

Vamos discutir em outro tópico, mas resumindo 2 |> √ significa √(2) .

Outra alternativa, que não exigiria alterações no analisador e seria fácil de digitar, seria A^T para transposição (definindo T como um tipo singleton com um método ^ ). … ah, vejo que @mbauman teve essa ideia também. É um pouco feio, mas não mais que A.' .

Não tenho experiência, mas estou muito interessado no resultado desta discussão, pois provavelmente digitará milhares de linhas contendo expressões de matriz no decorrer do meu trabalho.

transpose(A) # with no special syntax está ganhando a votação acima, mas é doloroso para meus olhos e dedos.

Em python, o uso comum é provavelmente com numpy e muitas coisas que se parecem com o seguinte e não são tão ruins:

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)

Eu não gostaria de ter que fazer:

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

Muda totalmente a concepção mental de transposição da convenção em que se estabeleceu a notação matemática, que é um significante pós-fixo, geralmente Aᵀ ou Aᵗ .

Pessoalmente, estou muito feliz com A' que funciona em Julia v.0.6, antes de ser tomado pelo adjunto. O adjunto é usado com muita frequência?

Aqui estão meus comentários em uma tabela:

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.

Pessoalmente, estou muito feliz com A' que funciona em Julia v.0.6, antes de ser tomado pelo adjunto. O adjunto é usado com muita frequência?

Não entendo, A' sempre foi adjunto de A . Costumávamos chamar a função subjacente ctranspose para transposição conjugada, mas a renomeamos para o termo equivalente adjoint sem alteração na funcionalidade.

Se você estiver fazendo álgebra linear, é muito mais provável que você queira uma transposição conjugada de qualquer maneira, então você estará digitando A' em vez de transpose(A) . A popularidade de não definir uma sintaxe especial para transposições não conjugadas é (presumivelmente) devido em parte ao fato de que não é tão comum para a maioria dos usos algébricos lineares querer a transposição não conjugada.

Se você está fazendo álgebra linear, então ...

Se a sua ferramenta é martelo então... :)

... você tem que pensar na possibilidade de Julia crescer para uma linguagem de programação geral.

Talvez não, talvez continue sendo o jargão da álgebra linear - que é uma possibilidade que tem que pensar em programadores como eu. :)

@mahiki , você é exemplo 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)

seria escrito literalmente em Julia como:

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

ou assumindo que os vetores são linhas nesse exemplo NumPy e seriam colunas em Julia:

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

que parece tão claro e matemático quanto possível. Se seus dados são reais, então adjoint e transpose são a mesma operação, o que pode ser o motivo pelo qual você está usando transpose acima – mas matematicamente adjunto é a operação correta. Como @ararslan disse, X' sempre significou adjoint em Julia (e em Matlab também). Anteriormente, era chamado ctranspose abreviação de " transposição conjugada ", mas esse nome era um nome incorreto, pois a propriedade definidora do operador é que

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

que é a propriedade definidora do adjunto Hermitiano , mas é satisfeita pela transposição conjugada quando A é uma matriz complexa. É por isso que "adjunto" é o termo genérico correto para este operador.

Dito isso, votei acima em transpose(a) e a.' pois acho que seria bom a.' significar transposição estrutural. Funcionaria como esperado e, embora não fosse recursivo e, portanto, não "matematicamente correto" em algum código genérico, fazê-lo funcionar como esperado parece bom o suficiente. E dizer às pessoas para considerar o uso conj(a') em código genérico parece uma coisa de educação, em vez de algo que realmente precisamos atingir as pessoas na cabeça.

@mahiki Se por algum motivo você realmente precisar usar transpose em vez de adjoint muitas vezes em seu código, então você pode definir uma macro mais curta como @t que alias transpose (embora eu saiba que esta solução não é ideal, especialmente se você estiver escrevendo seu código com outras pessoas).

você tem que pensar na possibilidade de Julia crescer para uma linguagem de programação geral.

@Liso77 Já é. Como apenas um dos muitos exemplos, o Nanosoldier executa um servidor web que escuta eventos do GitHub e executa benchmarks de desempenho sob demanda, tudo em Julia. Isso é uma digressão, porém, e eu não quero que este tópico saia do tópico.

Se você estiver transpondo uma matriz de algum tipo com dados não numéricos - que é um caso de uso totalmente válido - a notação de transposição matemática na verdade parece um trocadilho ruim. Nesse caso, acho que seria melhor ser mais explícito sobre o que você está pedindo, por exemplo, transpose (ou até permutedims , dependendo de suas necessidades específicas).

Se você estiver transpondo uma matriz de algum tipo com dados não numéricos - que é um caso de uso totalmente válido - a notação de transposição matemática na verdade parece um trocadilho ruim.

Como A.' não é realmente "notação de transposição matemática" no sentido usual, não vejo que isso seja um argumento a favor ou contra.

Eu acho que @ararslan não está argumentando contra o .' existente, mas sim contra a introdução de uma sintaxe T sobrescrito. Eu tendo a concordar - se você quer dizer o conceito de álgebra linear de adjunto, então você deve usar ' (mesmo que sua matriz seja real). E se você tem uma matriz de dados não numéricos, então é perfeitamente legítimo permutar os dois índices, mas essa operação não é realmente a "transposição" como costumamos pensar, e usar a notação matemática T sobrescrito é provavelmente mais confundir do que esclarecer. A única situação em que uma notação T sobrescrito seria realmente apropriada é se você tiver uma matriz numérica cujos índices você deseja permutar, mas você realmente não deseja o operador linear adjunto. Tais situações certamente existem, mas podem ser muito raras para justificar a introdução de uma nova sintaxe.

... mas esta operação não é realmente a "transposição" como costumamos pensar, ...

Se isso é tão incomum, por que ararslan e muitos outros votam na ortografia da transposição estrutural como transpose(A) ?

Obrigado @StefanKarpinski @ararslan @ttparker. Eu tive que voltar ao meu texto de álgebra linear e redescobrir o adjunto, está bem lá. Eu tirei isso antes da Análise Complexa, provavelmente por isso não tomei conhecimento disso.

Eu amo poder fazer isso
gradient = (1/m) * (X'Θ - Y) * X'

Minha confusão decorre do uso generalizado adjoint 'transpose' (como um T sobrescrito ) em documentos de referência, artigos, livros didáticos, etc. no exemplo de aparência limpa de @StefanKarpinski acima. Isso ocorre porque adjunto e transposto são equivalentes em ℝ (certo?) . atualização: sim

Agora, minha notação favorita para transposição é simplesmente o que for logicamente consistente. Claramente .' não é por causa de conflito com a sintaxe do operador pontilhado, e não tenho objeção a transpose(A) sem sintaxe especial, já que nenhuma sintaxe especial sã parece disponível, exceto por um sobrescrito unicode.

Eu gosto da solução @ttparker se eu me encontrar escrevendo muita transposição, macro @t que alias transpose .

Mais uma vez, errei ao afirmar:

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

Obrigado por levar meus comentários a sério, apesar da minha pouca facilidade com matemática de nível de pós-graduação.

(Do discurso .)

Eu gostaria que ' fosse um operador post-fix que mapeia f' para '(f) onde Base.:'(x::AbstractMatrix) = adjoint(x) e o usuário é livre para adicionar outros métodos que tenham nada a ver com adjuntos. (Por exemplo, algumas pessoas podem gostar de f' para se referir a df/dt.)

Com os sufixos de operador introduzidos na versão 0.7, seria natural que f'ᵃ mapeasse para 'ᵃ(f) , e assim por diante, permitindo ao usuário definir seus próprios operadores pós-fixados. Isso tornaria possível ter Base.:'ᵀ(x::AbstractMatrix) = transpose(x) e Base.:'⁻¹(x::Union{AbstractMatrix,Number}) = inv(x) , etc.

Escrever A'ᵀ talvez não seja tão limpo quanto Aᵀ , mas não exigiria depreciar nomes de variáveis ​​terminando em .

À primeira vista, parece que pode ser um recurso ininterrupto. É um compromisso muito inteligente. Eu gosto disso.

Parece-me razoável. A parte mais difícil é encontrar um nome para a função ' —a sintaxe de prefixo não funciona neste caso.

A parte mais difícil é criar um nome para a função '

apostrophe ? Pode ser literal demais...

É possível fazer a sintaxe de prefixo funcionar (por exemplo, com uma sintaxe (')(A) explícita?)? Caso contrário, isso é um problema, pois quebraria a regra if-you-can-define-the-symbol-name-then-you-can-override-its-syntax introduzida por https://github.com/JuliaLang /julia/pull/26380.

Edit: parece estar disponível:

julia> (')(A)


ERROR: syntax: incomplete: invalid character literal

julia> (')(A) = 2


ERROR: syntax: incomplete: invalid character literal

Infelizmente ' é um dos caracteres mais difíceis de usar como nome identificador, pois introduz um tipo diferente de átomo (caracteres), que tem precedência muito alta (igual à precedência dos próprios identificadores). Por exemplo, (')' é uma aplicação de ' para si mesmo, ou um parêntese aberto seguido por um literal ')' ?

Uma opção que não é prática a curto prazo é declarar que os literais de caracteres não valem ' e usar uma macro de string como c"_" .

Que tal se ' for analisado como um identificador quando precedido por ponto e vírgula, para que Base.:' funcione?

Claro que (@__MODULE__).:'(x) = function_body pode ser um pouco complicado de escrever, mas (x)' = function_body deve funcionar da mesma forma. Edit: Não, já que (x)' deve mapear para chamar o ' em Base . Definir uma função ' no módulo atual seria complicado, mas também não haveria motivo para fazê-lo.

Ou que tal deixar '' analisar como o identificador ' quando, de outra forma, seria analisado como um literal de caractere vazio (que atualmente é um erro de nível de análise). Da mesma forma, ''ᵃ seria analisado como o identificador 'ᵃ , etc.

Tudo o que não é atualmente um erro de sintaxe ainda seria analisado como antes (por exemplo 2'' é postfix ' aplicado duas vezes a 2 ), mas 2*'' agora analisar como duas vezes ' .

Parece confuso que teríamos a'' === a mas ''(a) === a' . Parece melhor usar Base.apostrophe como o nome (ou algo assim).

Seria melhor dividir essa discussão em um novo problema do Github, já que é sobre a sintaxe ' que não está diretamente relacionada à transposição de matrizes?

Existe uma maneira automatizada de dividir os problemas ou devo simplesmente abrir um novo e linkar para a discussão aqui?

Esta última

A única situação em que uma notação T sobrescrito seria realmente apropriada é se você tiver uma matriz numérica cujos índices você deseja permutar, mas você realmente não deseja o operador linear adjunto. Tais situações certamente existem, mas podem ser muito raras para justificar a introdução de uma nova sintaxe.

Acho que estou muito atrasado para a discussão, mas gostaria de apontar um uso que acho que vale a pena mencionar: Aplicando a diferenciação de etapas complexas a uma função de valor real que tem transpose dentro de isto. (Pessoalmente, descobri que precisava .' no MATLAB e na Julia por esse motivo específico.)

Vou dar um exemplo com múltiplas ocorrências de transpose (talvez eu pudesse evitar fazer dessa forma?)

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

O ponto é que f e Df devem ser definidos usando transpose e não devem usar o adjunto.

Eu não acho que o método do passo complexo seja super relevante em Julia. Não é um truque/solução alternativa para obter diferenciação automática nos casos em que uma linguagem suporta números complexos internos eficientes, mas um tipo de número Dual equivalentemente eficiente não pode ser definido? Esse não é o caso da Julia, que tem bibliotecas de diferenciação automática muito boas.

Eu concordo em usar números duplos em vez do método de etapas complexas e isso é um ponto muito bom que você está fazendo (eu pessoalmente já substituí todas as minhas avaliações do método de etapas complexas por números duplos em Julia). No entanto, acho que este ainda é um caso de uso válido, para fins de demonstração, truques de ensino (veja, por exemplo, Nick Higham falando sobre o método de etapas complexas em Julia Con 2018 ) e portabilidade (em outras palavras, me preocupo que A versão do MATLAB do código acima usando números complexos seria mais limpa).

Vindo do mundo dos engenheiros e possivelmente físicos que usam arrays complexos mais do que arrays reais, não ter um operador de transposição é um pouco chato. (A representação fasorial complexa para uma dependência de tempo harmônico é onipresente em nosso campo.) Eu pessoalmente preferiria a sintaxe numpy de xH e xT, embora minha única consideração seja a concisão.

A densidade do operador de transposição em relação à transposição Hermitiana é de cerca de 1 para 1 no meu código. Portanto, a transposição não conjugada é igualmente importante para mim. Muito do uso de transposição é para criar produtos externos e dimensionar matrizes corretamente para interface com outro código ou para multiplicação de matrizes.

Pretendo por enquanto simplesmente fornecer uma função de macro ou um caractere para a operação, porém qual é o equivalente adequado à antiga funcionalidade, transpose() ou permutedims()?

transpose destina-se à álgebra linear e é recursiva, e permutedims é para arranjo não recursivo de dados de qualquer tipo.

É interessante você dizer que usa transposição tanto quanto adjunta. Eu costumava ser o mesmo, mas principalmente porque tendia a cometer erros onde meus dados eram reais, então tendia a transpor, mas na verdade o adjunto era a operação correta (generalizado para o caso complexo - adjunto era a operação certa para o meu algoritmo). Existem (muitas) exceções válidas, é claro.

Em tudo relacionado à eletrodinâmica, você geralmente usa vetores do tipo espaço e deseja usar operações vetoriais em R^n (tipicamente n=3), ou seja, transpose em particular, mesmo que seus vetores sejam de valor complexo porque você fiz uma transformada de Fourier. Parece que @mattcbro está falando sobre esse tipo de aplicativo.

Dito isto, ao ler sobre discussões de sintaxe, muitas vezes penso que para mim, pessoalmente, não poderia imaginar que uma sintaxe um pouco mais detalhada é o que diminui minha velocidade ou eficiência de programação. Pensar no algoritmo em si e na maneira mais natural/eficiente de implementá-lo leva muito mais tempo.

Em tudo relacionado à eletrodinâmica, você geralmente usa vetores do tipo espaço e deseja usar operações vetoriais em R^n (tipicamente n=3), ou seja, transpor em particular, mesmo que seus vetores sejam de valor complexo porque você pegou um Fourier transformar.

Não necessariamente. Muitas vezes você quer quantidades médias no tempo das amplitudes de Fourier, nesse caso você usa o produto escalar complexo, por exemplo, ½ℜ[𝐄*×𝐇] é o fluxo de Poynting médio no tempo dos componentes complexos de Fourier e ¼ε₀|𝐄|² é um densidade de energia de vácuo média no tempo. Por outro lado, como o operador de Maxwell é (normalmente) um operador simétrico complexo ("recíproco"), você geralmente usa um "produto interno" não conjugado para álgebra (de dimensão infinita) nos campos 𝐄(𝐱) etc. todo o espaço.

Isso é verdade, eu tinha a palavra muitas vezes na primeira frase, mas a removi aparentemente :-).

Bem, se você quiser ir lá, as quantidades eletromagnéticas são ainda mais concisamente escritas em uma formulação algébrica de Clifford, geralmente chamada de álgebra geométrica. Essas álgebras possuem múltiplos automorfismos e antiautomorfismos que desempenham um papel crítico na formulação da teoria, especialmente quando se trata de problemas de espalhamento.

Essas álgebras normalmente têm uma representação de matriz concisa e esses morfismos são frequentemente facilmente calculados por meio de transposição complexa, transposição Hermitiana e conjugação.

No entanto, como afirmei anteriormente, meu principal uso de transposição é geralmente organizar meus arrays para interagir com outros arrays, outro código e fazer com que a multiplicação de matrizes funcione contra a dimensão correta de um array achatado.

Eu pessoalmente favoreceria a sintaxe numpy de xH e xT

Fácil de implementar agora em 1.0 e deve 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 

Isso é surpreendentemente fácil e meio legal. A desvantagem parece ser que os usos ortogonais de getproperty não se compõem. Portanto, qualquer pessoa que implemente getproperty em seu tipo de matriz específico precisará implementar o comportamento genérico manualmente.

usos ortogonais de getproperty não compõem

Hmm. Gostaria de saber se isso implica que xT "deveria" ter sido reduzido para getproperty(x, Val(:T)) . Eu estremeço ao pensar no que isso faria com o pobre compilador.

Tenho certeza de que todos têm sua opinião - mas para mim é quase um recurso que é difícil construir uma interface genérica fora da sintaxe de ponto. Não me entenda mal, é um recurso realmente ótimo e maravilhoso para definir estruturas semelhantes a tuplas nomeadas e assim por diante.

(Também é possível adicionar uma camada de expedição Val aos seus tipos com bastante facilidade).

O código do @c42f funciona como um encanto. Infelizmente para mim, estou tentando escrever código que funcione nas versões 0.64 e superiores, o que me obriga a usar transpose ou minha própria função definida T(A) = transpose(A). Talvez uma macro fosse um pouco mais limpa e um pouco mais eficiente.

Para ser claro, não estou sugerindo que definir esse getproperty particular seja uma boa ideia para o código do usuário. É provável que acabe com as coisas a longo prazo ;-) Embora talvez um dia tenhamos uma boa noção das consequências de que poderíamos ter x.T definido em Base .

Mas em um sentido geral, eu me pergunto por que esse tipo de uso de propriedade para definir "getters" em interfaces genéricas é realmente ruim. Por exemplo, funções getter de campo genéricas atualmente têm um enorme problema de namespace que é simplesmente resolvido pelo uso criterioso de getproperty . É muito melhor escrever x.A do que MyModule.A(x) , algum nome de função mais feio como get_my_A(x) , ou exportar o nome extremamente genérico A de um usuário módulo. O único problema que eu vejo é a capacidade esperada de substituir o significado de .B para subtipos independentemente de .A ser definido genericamente em um supertipo. Daí o comentário meio sério sobre Val .

Ideia engraçada:

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

O personagem parece um T , mas na verdade é um ' com uma barra sobre ele. Não tenho certeza se é sério...

screen shot 2018-09-10 at 11 29 56

Sim, parece que no GitHub para mim também. Mas é um overbar. Copie e cole no meu terminal mostra:

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

Inteligente e fofo demais. Eu ainda gosto da combinação de personagens, e acho que 'ᵀ é legal.

-100 para alterar adjoint, já que é uma das coisas incríveis que torna escrever código Julia tão claro quanto escrever matemática, mais a transposição conjugada geralmente é o que você quer de qualquer maneira, então faz sentido ter uma sintaxe abreviada para isso.

Há uma certa arrogância em uma afirmação como essa. Considere que uma proporção finita de desenvolvedores explicitamente _não_ quer adjoint() mas _precisa_ transpose() .

Caso e ponto para nós trabalhando com cálculos simbólicos para modelar o operador ' padrão faria, por exemplo, o pseudo-inverso (A'*A)\(A *b) ou uma forma quadrática v'*A*v retornar erroneamente resultados longos e complexos que não podem ser reduzidos.

Talvez a solução seja algum tipo de diretiva de compilador declarando o significado de ' .

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

omus picture omus  ·  3Comentários

iamed2 picture iamed2  ·  3Comentários

TotalVerb picture TotalVerb  ·  3Comentários

dpsanders picture dpsanders  ·  3Comentários

Keno picture Keno  ·  3Comentários