AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79564913
Accepted
Nils Werner
Nils Werner
Asked: 2025-04-10 01:00:03 +0800 CST2025-04-10 01:00:03 +0800 CST 2025-04-10 01:00:03 +0800 CST

A ordem de execução de Eigen unaryExpr() é sempre sequencial?

  • 772

Escrevi uma classe de filtro IIR com um estado de filtro interno e uma função elemento a elemento float filter(float x). Naturalmente, devido ao estado de filtro interno, ela filter()só pode ser chamada nas amostras na ordem em que estão organizadas na sequência.

Se eu agora aplicar essa função a um Eigen Array, como

input.unaryExpr(filter);

a ordem de execução será unaryExpr()sempre estritamente na ordem dos valores no array, ou pode ocorrer execução fora de ordem ou até mesmo paralelização?

Seria mais seguro escrever o loop explicitamente para garantir que a ordem seja sempre a esperada?

No momento, parece estar funcionando corretamente, mas não consigo encontrar nenhuma documentação explícita sobre seu comportamento.

c++
  • 1 1 respostas
  • 36 Views

1 respostas

  • Voted
  1. Best Answer
    Homer512
    2025-04-10T02:35:46+08:002025-04-10T02:35:46+08:00

    Uma expressão unária, como todas as expressões próprias, é na verdade apenas um functor sofisticado que se comporta como um Eigen::Matrixor Array, que permite alguma introspecção e pode ser solicitado para valores de índices individuais de linha e coluna. A ordem em que esses valores são solicitados é determinada pelo objeto ao qual os valores são atribuídos; essencialmente, o lado esquerdo da atribuição. Podemos demonstrar isso em 2D:

      Eigen::ArrayXXi in(2, 3);
      in <<
        0, 1, 2,
        3, 4, 5;
      // just the identity function with some debut output
      auto expr = in.unaryExpr([](int x) {
        std::cout << x << ' ';
        return x;
      });
    
      // assignment 1, simple copy
      Eigen::ArrayXXi out1 = expr;
      std::cout << '\n';
    
      // assignment 2, copy to row major array
      using RowMajorArray = Eigen::Array<
        int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
      RowMajorArray out2 = expr;
      std::cout << '\n';
    
      // assignment 3, copy to transposed output array
      Eigen::ArrayXXi out3(3, 2);
      out3.transpose() = expr;
    

    A primeira atribuição imprime 0 3 1 4 2 5, as outras duas imprimem 0 1 2 3 4 5. O motivo é que out1usa a ordem padrão de coluna principal. Portanto, a ordem mais eficiente para preenchê-la com valores é coluna 0 linha 0, coluna 0 linha 1, coluna 1, linha 0, coluna 1 linha 1, … As outras duas matrizes de saída têm ordem de memória transposta, portanto, usam a ordem de atribuição transposta.

    Observe também que nada me impede de avaliar duas vezes. É claro que isso não é um uso regular, mas pode aparecer em códigos que de outra forma seriam inofensivos, como este modelo aqui:

    template<class Derived>
    typename Eigen::ArrayBase<Derived>::PlainObject
    derivative(const Eigen::ArrayBase<Derived>& in)
    {
      Eigen::Index n = in.cols() - 1;
      return in.rightCols(n) - in.leftCols(n);
    }
    

    Se eu chamar derivative(in.unaryExpr(…)), ele imprimirá 0 1 3 4 1 2 4 5, avaliando a maioria das entradas duas vezes.

    Resumindo: não acho uma boa ideia tornar as expressões com estado como você deseja, pelo menos em geral. Idealmente, as expressões devem ser idempotentes. Mas se for o código mais curto, você sabe o que está fazendo e adiciona alguns avisos para que o próximo programador também entenda as limitações, deve ficar tudo bem.

    Em geral, o Eigen não realiza paralelismo automaticamente, exceto para multiplicações de matrizes e operações complexas semelhantes e conhecidas. Todo o resto é considerado pequeno, rápido e, em grande parte, limitado pela largura de banda da memória. Não consigo imaginar essa suposição mudando, exceto em uma nova versão principal, o Eigen4. E mesmo assim, eu não presumiria que esse fosse o comportamento padrão para expressões personalizadas. O custo de iniciar e interromper uma região paralela do OpenMP é alto demais para ser feito sem um bom conhecimento de que isso se justifica. E, por definição, o Eigen não tem ideia da complexidade computacional da sua expressão personalizada.

    Em geral, a ordem de avaliação também será de frente para trás na ordem de armazenamento da saída na memória, pelo menos em casos simples. Isso é o que torna o cálculo rápido e a programação simples.

    Pessoalmente, eu usaria apenas um método simples std::transformou um loop para tornar a ordem das operações explícita. Iteradores para vetores e matrizes 1D são rápidos, o mesmo com colwise()iteradores em 2D.

    Eigen::ArrayXf input(1234), output(1234);
    std::transform(std::begin(input), std::end(input), std::begin(output),
        [state](float x) mutable { return state(x); });
    
    • 2

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve