Determinant and Inverse return wrong values when called from more than one thread
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 35/100
- Tipo de issue
- Bug
- Clareza
- Claramente especificada
- Status de atividade
- Estagnada
- Stack de tecnologia
- csharp
- Domínio
- performance
Direção de pesquisa
Comece com SquareMatrixFactory<T, TWrapper>.GetMatrix e ExpressionCompiler<T, TWrapper>.storage; em seguida, reproduza as falhas relatadas de determinante/inversa com Parallel.For, incluindo um cache frio. Considera-se concluído quando as operações concorrentes de matriz retornarem os valores verificados sequencialmente, sem exceções de coleção nem corrupção de buffers compartilhados.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Two process-wide statics are read and written with no synchronisation, so matrix operations called from more than one thread return wrong numbers. Nothing throws, nothing is malformed, and no result looks suspicious.
I found this from the other side: AngouriMath uses GenTensor for its symbolic matrices, and a determinant computed on a background thread was coming back numerically wrong. AngouriMath's issue is #1219.
1. The scratch-matrix pool
SquareMatrixFactory<T, TWrapper>.GetMatrix hands every caller the same GenTensor for a given size, and the caller then writes into it — Inversion.GetCofactorMatrix(t, temp, ...) fills the matrix it is given. Two threads taking a determinant or an inverse of the same size get the same buffer and overwrite each other's minors between the write and the read.
Sixty 5×5 int matrices, each computed once sequentially for truth and then rebuilt and recomputed under Parallel.For:
DeterminantLaplace 53 of 60 disagree
Adjoint 60 of 60 disagree
Around 10 ms, every run. This is not a rare interleaving, it is the normal case.
DeterminantGaussianSafeDivision is unaffected — it works on its own copy and never asks the pool for anything.
The lock inside GetMatrix does not help and is itself incomplete: the list is indexed after the lock is released, so a concurrent Add can reallocate the backing array underneath the reader.
2. The compiled-operation cache
ExpressionCompiler<T, TWrapper>.storage is a plain Dictionary, written by whichever thread first asks for a given (operation, rank, parallel). Dictionary<,> is documented as safe for concurrent readers only while nobody is writing.
Reached cold from several threads it fails with the runtime's own diagnostic:
System.InvalidOperationException: Operations that change non-concurrent collections must
have exclusive access. A concurrent update was performed on this collection and corrupted
its state. The collection's state is no longer correct.
...
The given key '(Subtraction, 1, False)' was not present in the dictionary.
Worth noting that this one hides easily. My first test computed its expected values sequentially and only then went parallel, which populated every key before the threads started — the cache holds a handful of entries, so a warm-up makes the defect invisible and the test passes against the broken code.
Fix
I have opened a PR. Both are small: [ThreadStatic] for the pool, since a scratch buffer has nothing to share between threads, and ConcurrentDictionary for the cache. The Laplace determinant comes out about 5% faster, because the pool is now taken once at the top of the recursion instead of re-checked and re-indexed at every one of its n! nodes.
- Linguagem predominante
- C#
- Estrelas
- 52
- Forks
- 6
- Métricas de merge de PRs
- Nenhum PR com merge em 30d
Preparar o ambiente
Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de ASC-Community/GenericTensor
-
good first issue
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 25/100
-
proposal
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 35/100
ASC-Community/GenericTensor#36 · 1 comentário ·
-
Opinions wanted proposal
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 25/100
ASC-Community/GenericTensor#31 · 2 comentários ·
-
Will this package support MKL or OpenBlas as backend to accelerate matrix inverse computing speedAberta
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 25/100
ASC-Community/GenericTensor#30 · 1 comentário ·
-
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 20/100
ASC-Community/GenericTensor#29 · 1 comentário ·
Todas as issues de ASC-Community/GenericTensor
Issues semelhantes
-
[i18n] 安装实例完成后的成功提示未正确本地化Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
PCL-Community/PCL-CE#3658 ·
Mantenedores costumam responder em até 1 dia
-
Deploy & Patch-issues opprettes ikke: create-pnd-issues.yml har feilet hver uke siden 2025-09-08Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
Altinn/altinn-auth#4359 ·
Mantenedores costumam responder em até 1 dia
-
アプリ: チャット 優先: 中 提案
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
yksr-melt/Meltype#243 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
type/automation type/tech-debt
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 72/100
Mantenedores costumam responder em até 1 dia
-
High-DPI fixes for release/1.3: editor toolbar icons and Color Picker layout (patch included)Abertano-stack-trace
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 83/100
Mantenedores costumam responder em até 1 dia