fix: use residual stopping for FEAST eigenanalysis

This commit is contained in:
KOKO\Mimi
2026-09-10 01:52:49 +09:00
parent 76192508fd
commit 7ebdce373c
12 changed files with 209 additions and 17 deletions
+11 -1
View File
@@ -86,4 +86,14 @@
- 근거: [실행 결과](implementation-verification.md), [독립 수치 검토](implementation-numerical-review.md), [S3 검토](implementation-numerical-review-s3-static.md). - 근거: [실행 결과](implementation-verification.md), [독립 수치 검토](implementation-numerical-review.md), [S3 검토](implementation-numerical-review-s3-static.md).
- 관찰: 원본 모델은 고정 FEAST trace stopping의 실제 반환값에서 전체 c residual 기준을 넘는다. S3 public static은 rotation-only drilling의 미평형 모멘트 때문에 실패한다. - 관찰: 원본 모델은 고정 FEAST trace stopping의 실제 반환값에서 전체 c residual 기준을 넘는다. S3 public static은 rotation-only drilling의 미평형 모멘트 때문에 실패한다.
- 현재 처리: r1 controls·tolerance·물리 식을 유지하고 실패를 명시한다. 요청 N 밖의 모드를 버리거나 reaction에서 torque를 제거하지 않는다. 구현 진행분은 커밋하되 기능 완료로 표시하지 않는다. - 현재 처리: r1 controls·tolerance·물리 식을 유지하고 실패를 명시한다. 요청 N 밖의 모드를 버리거나 reaction에서 torque를 제거하지 않는다. 구현 진행분은 커밋하되 기능 완료로 표시하지 않는다.
- 후속 제안: residual stopping 후보의 FEAST 제어와 S3 정식화/회복/평형 계약을 사용자 결정 후 formulation·NR에서 재검토한다. 아직 채택·승인된 변경은 없다. - 당시 후속 제안: residual stopping 후보의 FEAST 제어와 S3 정식화/회복/평형 계약을 사용자 결정 후 formulation·NR에서 재검토한다. 이 기록 시점에는 채택·승인된 변경이 없었다. 이후 FEAST 제어만 ADR-011로 변경한다.
## MFE2-ADR-011 — FEAST residual stopping과 S3 후속 분리
- 상태: 사용자 명시 승인, 2026-09-10. Owner: 메인 assistant; 수치 검토: numerical-review-agent.
- 승인 근거: “FEAST 잔차 초과 문제를 Trace 기반 종료 → residual 기반 종료로 변경”, “S3 문제는 추후에 고려”.
- 결정: C-index `fpm[5]`를 `1`에서 `0`으로 변경한다. `fpm[2]=12`, `fpm[3]=20`, count/solve 구간·capacity·seed·thread·실패 정책 및 전체 c개 독립 `1e-10` 검증은 유지한다.
- 이유: trace 변화의 수렴만으로는 원본 모델 전체 고유쌍의 독립 잔차를 충족하지 못했다. 개별 잔차를 사용하는 backend 종료를 선택하되 backend 성공을 독립 검증으로 대체하지 않는다.
- 영향: [정식화 E5](formulation-eigen.md), [수치 controls C5](numerical-review-controls.md), backend와 HDF5 writer의 control 검증을 함께 갱신한다. 기존 schema의 실제 `base_fpm[5]` 기록값이 바뀌며 field·shape·단위와 reference mapping은 유지한다.
- 검증: [실행 결과](implementation-verification.md) 및 [독립 수치 검토](implementation-feast-residual-review.md)에 새 실행을 기록한다. 기존 trace 실패 evidence는 당시 결과로 보존한다.
- 범위: S3 정식화·부분 회전 BC·reaction·평형 기준은 변경하지 않고 알려진 충돌을 후속 과제로 유지한다. S3를 해결하거나 unsupported로 재분류한 결정이 아니다. 외부 reference와 공통 tolerance도 유지한다.
@@ -3,7 +3,7 @@
- Feature ID: `mitc4-shell-feast-eigen2` - Feature ID: `mitc4-shell-feast-eigen2`
- Owner: 메인 assistant - Owner: 메인 assistant
- Requirement baseline revision: `r1` - Requirement baseline revision: `r1`
- 현재 작업: 확정된 requirement/formulation/NR/I/O r1을 기준으로 implementation과 필요한 실행 검증을 진행한다. - 현재 작업: requirement/formulation/I/O r1과 [ADR-011](ADR.md#mfe2-adr-011--feast-residual-stopping과-s3-후속-분리)의 FEAST residual stopping 변경을 적용한다. C5 controls는 r2이며 S3는 후속 과제로 유지한다.
- 목적: MITC4 질량행렬과 FEAST 고유진동 해석의 요구사항을 이론·수학·수치 검토·입출력 계약으로 구체화한다. - 목적: MITC4 질량행렬과 FEAST 고유진동 해석의 요구사항을 이론·수학·수치 검토·입출력 계약으로 구체화한다.
- 현재 checklist: [PRD](PRD.md#현재-checklist). - 현재 checklist: [PRD](PRD.md#현재-checklist).
@@ -40,5 +40,6 @@
| [implementation-verification.md](implementation-verification.md) | 메인 assistant | 실제 구현·실행·실패·남은 evidence와 후속 결정 | | [implementation-verification.md](implementation-verification.md) | 메인 assistant | 실제 구현·실행·실패·남은 evidence와 후속 결정 |
| [구현 수치 검토](implementation-numerical-review.md), [검토 이력](implementation-numerical-review-history.md), [S3 정적 검토](implementation-numerical-review-s3-static.md) | numerical-review-agent | 구현의 독립 수치 대조와 계약 충돌 | | [구현 수치 검토](implementation-numerical-review.md), [검토 이력](implementation-numerical-review-history.md), [S3 정적 검토](implementation-numerical-review-s3-static.md) | numerical-review-agent | 구현의 독립 수치 대조와 계약 충돌 |
| [구현 물리 검토](implementation-physics-review.md) | physics-evaluation-agent | 실제 retained 결과의 물리 evidence·범위와 기존 문제 | | [구현 물리 검토](implementation-physics-review.md) | physics-evaluation-agent | 실제 retained 결과의 물리 evidence·범위와 기존 문제 |
| [FEAST 종료 제어 검토](implementation-feast-residual-review.md) | numerical-review-agent | 사용자 승인 residual stopping의 독립 검토와 새 실행 판정 |
반환은 결과·변경 파일·정적 확인·미해결 항목으로 충분하다. Git 경로 선택·커밋과 최종 결과 확인은 메인이 수행한다. 반환은 결과·변경 파일·정적 확인·미해결 항목으로 충분하다. Git 경로 선택·커밋과 최종 결과 확인은 메인이 수행한다.
+12 -2
View File
@@ -29,6 +29,10 @@ solver build/test·reference 비교와 release 감사는 포함하지 않는다.
코드·테스트·실제 FEAST 및 필수 reference/회귀 검증과 작업별 커밋이다. 앞의 30분 제한은 코드·테스트·실제 FEAST 및 필수 reference/회귀 검증과 작업별 커밋이다. 앞의 30분 제한은
완료된 문서 작업의 이력이다. 원본 reference 생성·변경과 push/release는 포함하지 않는다. 완료된 문서 작업의 이력이다. 원본 reference 생성·변경과 push/release는 포함하지 않는다.
2026-09-10 사용자는 FEAST 종료 조건을 trace에서 residual로 변경하고 S3는 추후 고려하도록
명시했다. [ADR-011](ADR.md#mfe2-adr-011--feast-residual-stopping과-s3-후속-분리)에 따라 backend·저장 control 검증·관련 문서를 갱신하며,
기존 독립 잔차와 외부 tolerance, 질량·drilling 수식은 유지한다.
## 솔버 기능의 요구 범위 요약 ## 솔버 기능의 요구 범위 요약
기존 사용자 결정에 기록된 다음 의미를 새 요구사항의 출발점으로 사용한다. 기존 사용자 결정에 기록된 다음 의미를 새 요구사항의 출발점으로 사용한다.
@@ -83,10 +87,16 @@ solver build/test·reference 비교와 release 감사는 포함하지 않는다.
- [ ] 제외 예제 사용 없이 남는 static/내부 회귀·전체 build/test·필수 reference 실행. - [ ] 제외 예제 사용 없이 남는 static/내부 회귀·전체 build/test·필수 reference 실행.
- [ ] 관련 독립 numerical/physics 확인, 결과·한계 기록과 커밋. - [ ] 관련 독립 numerical/physics 확인, 결과·한계 기록과 커밋.
- [x] 승인된 FEAST residual stopping과 HDF5 control 검증을 함께 적용하고 변경 전 실패·변경 후 검사를 확인한다.
- [x] 원본 eigen의 전체 c개 독립 잔차·복구·HDF5 생성을 확인하고 종료 제어의 독립 수치 검토를 받는다.
- [ ] 원본 eigen의 외부 Value 불일치 원인을 조사한다. 현재 Mode2–10의 모드별 RMS가 1%를 초과한다.
- [ ] S3 public static 정적 평형 계약 충돌은 사용자 요청에 따라 후속 검토한다.
현재 구현·실행은 [implementation-verification](implementation-verification.md)에 기록했다. 현재 구현·실행은 [implementation-verification](implementation-verification.md)에 기록했다.
실제 mass/reduction/FEAST/procedure/HDF5 경로와 focused 검사가 있으며, 체크되지 않은 항목이 실제 mass/reduction/FEAST/procedure/HDF5 경로와 focused 검사가 있으며, 체크되지 않은 항목이
전부 미구현이라는 뜻은 아니다. 원본 eigen의 전체 c residual 실패와 S3 public static 전부 미구현이라는 뜻은 아니다. 원본 eigen의 전체 c residual 실패는 residual stopping으로
계약 충돌, 세부 case의 미완료 evidence 때문에 기능 전체 acceptance는 완료하지 않았다. 해소했다. 현재 외부 Value 불일치와 S3 public static 계약 충돌, 세부 case의 미완료 evidence가
남으므로 기능 전체 acceptance는 완료하지 않았다.
## 이전 문서 단계의 결과와 구현 입력 ## 이전 문서 단계의 결과와 구현 입력
@@ -128,8 +128,10 @@ K와 identity의 pattern이 같을 필요는 없다. Vendor types와 workspace
매 call마다 `feastinit` 후 명시 controls를 채운다. C-index `fpm[49]=1`은 CSR count를 매 call마다 `feastinit` 후 명시 controls를 채운다. C-index `fpm[49]=1`은 CSR count를
m0로 반환하고 flag가 0으로 reset된다. Count output m0·solve requested m0·allocated capacity를 m0로 반환하고 flag가 0으로 reset된다. Count output m0·solve requested m0·allocated capacity를
분리한다. CSR/SPD 검사를 켜고 subspace-only를 끈다. Zero mode에도 적용할 수 있도록 분리한다. CSR/SPD 검사를 켜고 subspace-only를 끈다.
`fpm[5]=1` trace stopping을 사용하며 residual을 독립 검증한다. `epsout`은 [MFE2-ADR-011](ADR.md#mfe2-adr-011--feast-residual-stopping과-s3-후속-분리)의 사용자 승인으로
`fpm[5]=0` residual stopping을 사용한다. 내부 목표 `1e-12`와 전체 c개 독립 residual
기준 `1e-10`을 유지하며 zero/mixed-zero mode에도 실제 backend 회귀를 수행한다. `epsout`은
`|trace_i-trace_previous|/max(|emin|,|emax|)`이며 eigenpair 상대오차가 아니다. `|trace_i-trace_previous|/max(|emin|,|emax|)`이며 eigenpair 상대오차가 아니다.
`info=1`은 certified empty count가 아니다. 넓은 interval의 isolated cluster를 놓친 `info=1`은 certified empty count가 아니다. 넓은 interval의 isolated cluster를 놓친
+3 -1
View File
@@ -39,7 +39,9 @@ Numerical scale은 초기 physical rotary diagonal 8개 trace 평균의 `10^-3`
질량 및 trace 평균은 FESA 운동학에서 유도한 선택이다. 외부 source가 이 lumping/scale을 질량 및 trace 평균은 FESA 운동학에서 유도한 선택이다. 외부 source가 이 lumping/scale을
지정한다고 주장하지 않는다. 최신 API 근거와 검토 한계는 [research](research.md)와 지정한다고 주장하지 않는다. 최신 API 근거와 검토 한계는 [research](research.md)와
[research evidence](research-evidence.md)에 연결한다. FEAST count의 `fpm[49]=1`과 [research evidence](research-evidence.md)에 연결한다. FEAST count의 `fpm[49]=1`과
trace stopping의 `fpm[5]=1`은 C-index다. 빈 count interval의 `info=0,m0=0`과 작은 residual stopping의 `fpm[5]=0`은 C-index다. 종료 제어는 [ADR-011](ADR.md#mfe2-adr-011--feast-residual-stopping과-s3-후속-분리)과
[controls C5](numerical-review-controls.md#c5-fixed-lower-enclosure와-bounded-upper-search)의 승인된 변경을 적용한다.
빈 count interval의 `info=0,m0=0`과 작은
scratch 허용은 보장된 vendor 계약으로 채택하지 않는다. scratch 허용은 보장된 vendor 계약으로 채택하지 않는다.
## 검증 의무와 미해결 항목 ## 검증 의무와 미해결 항목
@@ -0,0 +1,71 @@
# FEAST residual stopping 독립 검토
- Feature: `mitc4-shell-feast-eigen2`; Owner: `numerical-review-agent`; 2026-09-10.
- 범위: 사용자 승인 `fpm[5]:1→0`, `[2]=12`, `[3]=20` 유지. S3는 보류 상태를 유지한다.
- 판정: **`PASS` — 승인된 종료 제어 변경**, **`FAIL` — 원본 외부 Value acceptance**.
전체 기능 완료 판정이 아니다.
- 기준: [PRD](PRD.md), [ADR](ADR.md), [E4–E7](formulation-eigen.md),
[C3/C5](numerical-review-controls.md), [I/O](io-schema.md), [TOLERANCE](../TOLERANCE.md).
## 판단과 필요한 확인
| 항목 | 독립 판단 |
| --- | --- |
| 종료 기준 | [Intel C parameter 표](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2026-0/extended-eigensolver-input-parameters.html)는 `[5]=0` residual, `1` trace이며 double epsilon은 `10^-fpm[2]`임을 명시한다. `1e-12` vendor stopping과 독립 all-c `1e-10`은 서로 다른 metric이다 |
| 불변 수식 | `B=A/s`, `mu=lambda/s`는 무차원이고 `rho_B=norm2(Bx-mu x)/norm2(x)`도 무차원이다. 종료 시점만 바뀌며 K/M, 부호·단위·DOF 순서, 적분, whitening, raw sort, 복구·state commit 식은 그대로다 |
| 전체 c | 요청 N 밖을 포함한 c개 residual과 pairwise/Frobenius Gram 검증 후 첫 N개를 공개해야 한다. FEAST 성공이나 작은 epsout으로 생략할 수 없다 |
| Zero·반복군 | 정확한 zero의 backend residual이 비유한이면 기존 available=false 표현을 유지한다. 독립 zero identity와 nonzero vector·Gram은 검증한다. Residual stopping에서 zero/mixed-zero의 실제 성공 여부는 실행으로 확인해야 하며 trace fallback을 추가하지 않는다. 반복군은 multiplicity·공간·Gram으로 판단하고 개별 벡터 방향의 유일성을 요구하지 않는다 |
| 상태·metadata | `SetControls`를 count/solve마다 재초기화하며 count의 `[49]=1` reset을 다음 solve에 전파하지 않는다. `base_fpm[5]=0,[2]=12,[3]=20`은 실제 새 HDF5에서 확인한다. `epsout`은 기존 trace 변화 진단량이며 residual stopping 지표로 이름·의미를 바꾸지 않는다 |
| 실패·안정성 | Refinement 최대20, bounded interval/capacity retry와 독립 검증 실패 즉시 종료를 유지한다. 새 종료 조건에서도 모든 conditioning의 수렴을 보장하지 않는다. Source의 미수렴/status/budget/allocation 전체 실패 주입 coverage는 기존 미완료 위험으로 남는다 |
검토 source: [backend](../../src/fesa/solvers/eigen/mkl_feast_eigen_solver.cpp),
[기존 backend tests](../../tests/unit/solvers/eigen/mkl_feast_eigen_solver_test.cpp).
추가로 [writer 검증](../../src/fesa/io/hdf5/eigen_hdf5_results_writer.cpp)의 `[5]=0` 제한과
[실제 HDF5 readback·변조 거부 검사](../../tests/unit/io/hdf5/eigen_hdf5_results_writer_test.cpp)를
대조했다. Schema의 field/type/layout 변경 없이 승인된 control 값만 일치시킨다.
본 검토자는 source/tests를 변경하거나 build/test를 중복 실행하지 않고 메인의 실행 로그를 대조했다.
## 새 실행 evidence
개인 `.harness/config.json`과 preset의 MSVC x64 Debug·oneMKL 2026.1 설정을 확인했다.
| Evidence 경로 | 확인 결과 |
| --- | --- |
| `.harness/feast-residual-red.log` | 변경 전 backend와 실제 HDF5에서 `[5]=1`을 읽어 새 `[5]=0` 검사 두 개가 실패함 |
| `.harness/feast-residual-focused.log` | 12개 중 11 통과. Backend 10개는 n1/all-zero/mixed-zero/repeated40 prefix/close distinct·Givens/negative/invalid/thread 복원 포함. Writer 한 개는 실제 control readback·trace로 변조한 candidate 거부 포함 |
| 같은 focused log의 원본 reference | Application 성공 후 Value 비교까지 진행했으나 10 singleton 중 9개 실패. 기존 독립 residual 차단과 다른 외부 acceptance 실패이며 전체 검사가 통과한 것은 아님 |
| `.harness/feast-residual-full-run.log` | 구성된 전체 build/test에서 CTest 395개 중 394 통과, 원본 Value reference 한 개 실패, CTest exit8, 실행178.42초. 전체 통과 아님 |
| `.harness/build-ninja-msvc-debug/feast-residual-metrics.json` | `.harness/build-ninja-msvc-debug/extract_feast_residual.py`가 공식 원본 sibling HDF5를 read-only 추출한 값. 스크립트의 실제 dataset·mode_id 대응과 JSON을 대조함 |
원본 새 HDF5에서 `c=22,m0=33,info=0,loop=6`, controls `[2]=12,[3]=20,[5]=0`,
`epsout=2.4227135616446226e-17`을 확인했다. 전체 c개의 최대값은 다음과 같다.
| Metric | 실제 최대값 | 판정 기준 |
| --- | ---: | ---: |
| 독립 rho_B | `1.605467212112365e-13` | `<=1e-10`, PASS |
| Original-free eta_r / whitened eta_w | `9.981033437726324e-15` / `7.315529163435965e-15` | 각각 `<=1e-10`, PASS |
| Gram eta_gram / max_eta_orth | `1.3777964580680282e-15` / `1.6958335496991244e-15` | 각각 `<=1e-10`, PASS |
| Backend res | `8.280018892001454e-13` | vendor 진단량, 독립 rho_B 대체 아님 |
Value 행별 상대오차는 전부 5% 이내지만 Mode2–10의 singleton RMS는 1%를 초과한다.
Mode1은 `0.5648341627%`로 PASS, Mode2–10은 `1.3496440956%`–`4.2613310845%`로 FAIL이다.
양의 singleton은 RMS가 relative error와 같다는 [승인된 family 계약](reference-model.md)을
그대로 적용했다. 행 5%만으로 전체 PASS를 선언하거나 frame을 합쳐 RMS를 완화할 수 없다.
**필요한 후속 correction:** 메인이 이 외부 불일치의 원인·모델 가정을 별도 조사해야 한다.
현재 evidence만으로 질량·stabilization 등 특정 물리 식이 원인이라고 단정할 수 없다.
반복군 검사 통과를 모든 projector·3회 결정론·vendor 실패 주입 coverage 완료로 확장하지 않는다.
## Trace stopping 이력과 잔여 위험
[기존 실행 기록](implementation-verification.md)의 trace stopping 실패는
`n=3125,N=10,c=22,m0=33,info=0,loop=4`, raw solver column20의
`rho_B=1.48674481038207483e-10>1e-10`, `epsout=2.82488401287762986e-14`다.
Full/upper action 차이 `1.38724134018909290e-17`은 해당 실패 크기를 설명하지 못한다.
이 관찰은 trace 수렴이 각 vector residual 통과를 보장하지 않는 실제 반례이며,
새 제어의 개선 정도·통과 여부를 선취하지 않는다.
공통 외부 정책은 필요한 row의 누락·추가·중복·비유한을 tolerance 전에 거부하고 승인된
Value family에 적용한다. 독립 modal 허용오차를 외부 reference tolerance로 대체하지 않는다.
S3 정적 계약 충돌과 기존 nonlinear recovery 문제, 27개 case 전체 세부 coverage 미완료는
[기존 독립 검토](implementation-numerical-review.md)의 별도 제한으로 남는다.
@@ -1,12 +1,81 @@
# MITC4 eigen 구현 및 실행 결과 # MITC4 eigen 구현 및 실행 결과
- Feature: `mitc4-shell-feast-eigen2`; Owner: 메인 assistant; 2026-09-09 KST. - Feature: `mitc4-shell-feast-eigen2`; Owner: 메인 assistant; 갱신 2026-09-10 KST.
- 판정: **구현 진행분 보존, 기능 acceptance 미완료**. 시간 제한으로 중지한 작업이 아니다. - 현재 판정: **FEAST 잔차 초과 해소, 외부 Value 비교와 기능 acceptance 미완료**.
아래 2026-09-10 결과가 최신이며 2026-09-09 trace 실행은 당시 evidence로 보존한다.
- 기준: [프로젝트 지침](../../AGENTS.md), [PRD](PRD.md), [ADR](ADR.md), - 기준: [프로젝트 지침](../../AGENTS.md), [PRD](PRD.md), [ADR](ADR.md),
[정식화](formulation.md), [수치 controls](numerical-review-controls.md), [I/O](io.md). [정식화](formulation.md), [수치 controls](numerical-review-controls.md), [I/O](io.md).
- 독립 검토: [수치](implementation-numerical-review.md), - 독립 검토: [수치](implementation-numerical-review.md),
[S3 정적 계약](implementation-numerical-review-s3-static.md), [S3 정적 계약](implementation-numerical-review-s3-static.md),
[물리](implementation-physics-review.md). [물리](implementation-physics-review.md), [FEAST 종료 변경](implementation-feast-residual-review.md).
## 2026-09-10 FEAST residual stopping 변경 결과
[ADR-011](ADR.md#mfe2-adr-011--feast-residual-stopping과-s3-후속-분리)의 사용자 승인에 따라 backend의 C-index
`fpm[5]`만 `1→0`으로 변경하고 HDF5 writer의 실제 control 검증도 `0`으로 맞췄다.
`fpm[2]=12`, `[3]=20`, seed/thread/구간/capacity/실패 정책과 모든 독립 tolerance는 유지했다.
S3, K/M·질량 축소·회복 수식, reference artifact는 변경하지 않았다.
새 테스트는 실제 backend snapshot과 저장한 HDF5의 `[5]=0`을 확인하고 trace 값으로
변조한 candidate를 거부하면서 기존 최종 파일을 보존하는지 검사한다. 변경 전 `[5]=1`
때문에 두 검사가 실패한 뒤 최소 source 수정으로 통과했다.
| 실행 | 결과 |
| --- | --- |
| 변경 전 backend/HDF5 focused CTest | 2/2 실패, `[5]=1` 확인. `.harness/feast-residual-red.log` |
| MSVC x64 Debug 3개 test target build | exit0, 새 compiler warning 없음 |
| 변경 후 backend/writer/원본 reference focused CTest | 12개 중 11 통과, exit1. 영·혼합 영·반복·근접 고유값, thread 복원, control readback/변조 거부 통과. 원본은 해석 성공 후 외부 Value 비교에서 실패 |
| `python scripts/execute.py` | build 성공, runner exit1 / CTest exit8. **395개 중 394 통과**, 원본 Value reference 1개 실패. 178.42초; unit320, integration42, reference33 |
| 공식 HDF5 read-only 추출 | 전체 c개 metric과 실제 controls·backend call·10개 Value를 확인. Focused와 full 실행의 modes/vectors/eigenpair_checks/base_fpm dataset bytes 동일 |
전체 실행은 `.harness/feast-residual-full-run.log`, 상세 CTest는
`.harness/feast-residual-full-ctest.log`, focused는 `.harness/feast-residual-focused.log`다.
Read-only 추출 스크립트와 JSON은 최종적으로 ignored build directory에 보관했다.
재현 명령은 `uv run --with h5py python .harness/build-ninja-msvc-debug/extract_feast_residual.py`이며,
그 directory의 `feast-residual-metrics.json`과 `feast-residual-full-metrics.json`이 각 실행의 기록이다.
개인 환경·추출 스크립트·기계 생성 로그/결과는 커밋하지 않는다. 이 작업에서 Python Harness suite는 실행하지 않았다.
원본 [결과 HDF5](../../reference/shellNL-eigen-meshfine/shellNL-eigen-meshfine_results.h5)는
이번 실제 해석이 새로 생성한 공식 sibling output이다. 생성과 closed-file self-check는 성공했고,
기존 외부 INP/TXT의 실행 전후 bytes는 reference test에서 보존을 확인했다.
| Metric | 새 결과 |
| --- | ---: |
| 요청 N / 계산 c / m0 | 10 / 22 / 33 |
| Count / solve calls | 25 / 1 |
| FEAST info / loop | 0 / 6 (기존 trace는 4회) |
| 전체 c 최대 rho_B | `1.605467212112365e-13` |
| 최대 original-free eta_r / whitened eta_w | `9.981033437726324e-15` / `7.315529163435965e-15` |
| eta_gram / max_eta_orth | `1.3777964580680282e-15` / `1.6958335496991244e-15` |
| 최대 backend_res | `8.280018892001454e-13` |
| epsout (trace 변화 진단량) | `2.4227135616446226e-17` |
전체 22개는 각각 독립 `1e-10` 기준을 통과한다. 기존 실패 column20의
`rho_B=1.48674481038207483e-10` 대비 같은 column의 잔차가 약926배 감소했다.
기존 trace 진단에서 추출한 첫10개 Value 대비 새 Value의 최대 상대 변화는 약`2.74e-14`다.
따라서 이 개선은 고유쌍의 대수적 잔차 개선이며 외부 reference와의 일치를 보장하지 않는다.
| Mode | FESA Value (표시 반올림) | Abaqus Value | 상대오차 / singleton RMS (%) |
| --- | ---: | ---: | ---: |
| 1 | 218267.149475 | 219507 | 0.564834 |
| 2 | 873571.591115 | 885523 | 1.349644 |
| 3 | 873571.591115 | 885523 | 1.349644 |
| 4 | 1816890.360227 | 1855340 | 2.072377 |
| 5 | 2669030.373076 | 2740230 | 2.598308 |
| 6 | 2703557.194039 | 2775150 | 2.579781 |
| 7 | 4013818.213002 | 4149410 | 3.267737 |
| 8 | 4013818.213002 | 4149410 | 3.267737 |
| 9 | 6446840.913563 | 6733790 | 4.261331 |
| 10 | 6446840.913563 | 6733790 | 4.261331 |
모드별 singleton family와 [공통 tolerance](../TOLERANCE.md)를 그대로 적용했다.
모든 행은 상대오차5% 이내지만 Mode2–10은 RMS1%를 초과하여 blocking FAIL이다.
이는 이전에는 residual 실패 때문에 도달하지 못했던 비교 결과다. 원인은 이번 변경에서
확정하지 않았으며 질량·drilling 정식화나 tolerance를 결과에 맞춰 수정하지 않았다.
독립 수치 검토는 이번 종료 제어 변경을 PASS로 판단했으나 외부 acceptance는 FAIL로 구분했다.
S3의 알려진 실패와 아래 기존 세부 coverage 제한도 남는다.
## 2026-09-09 trace stopping 구현 이력
## 구현된 경로 ## 구현된 경로
@@ -95,11 +164,12 @@ Newton tangent/objectivity/energy/rollback와 pressure synthetic 검사는 초
full-row-sum mutation, C06 이종 section 공유 node mass assembly, C21/22의 vendor-status/ full-row-sum mutation, C06 이종 section 공유 node mass assembly, C21/22의 vendor-status/
budget/allocation 실패 주입 전체, C24의 close/replace 실패 주입 전체는 추가 evidence가 필요하다. budget/allocation 실패 주입 전체, C24의 close/replace 실패 주입 전체는 추가 evidence가 필요하다.
## 사용자 결정이 필요한 후속 작업 ## 2026-09-09 당시 후속 제안
현재 요구·정식화·NR·I/O의 수치를 구현 결과에 맞춰 조용히 바꾸지 않는다. 현재 요구·정식화·NR·I/O의 수치를 구현 결과에 맞춰 조용히 바꾸지 않는다.
[프로젝트 지침](../../AGENTS.md)의 Physics/지원 범위/acceptance 변경 및 미해결 필수 계약 충돌 [프로젝트 지침](../../AGENTS.md)의 Physics/지원 범위/acceptance 변경 및 미해결 필수 계약 충돌
경계에 따라 다음 재검토를 제안한다. 아래는 **미승인 제안**이다. 경계에 따라 다음 재검토를 제안했다. 당시에는 **미승인 제안**이었으며,
이후 1번의 residual stopping만 ADR-011로 승인·실행했다. 2번 S3는 사용자 요청으로 후속 검토한다.
1. `rho_B<=1e-10`과 전체 c 검증을 유지하면서 FEAST 종료 제어를 재검토한다. 1. `rho_B<=1e-10`과 전체 c 검증을 유지하면서 FEAST 종료 제어를 재검토한다.
`fpm[5]=0` residual stopping은 검토 후보이며, actual runtime·zero/repeated/endpoint/ `fpm[5]=0` residual stopping은 검토 후보이며, actual runtime·zero/repeated/endpoint/
@@ -1,8 +1,10 @@
# 내부 수치 기준과 FEAST controls # 내부 수치 기준과 FEAST controls
- Feature ID: `mitc4-shell-feast-eigen2`; Owner: `numerical-review-agent`; revision `r1`. - Feature ID: `mitc4-shell-feast-eigen2`; Owner: `numerical-review-agent`; revision `r2` (2026-09-10, C5 종료 제어만 변경).
- 기본 보고서: [numerical-review](numerical-review.md); 수식: [새 formulation](formulation.md). - 기본 보고서: [numerical-review](numerical-review.md); 수식: [새 formulation](formulation.md).
- IEEE binary64의 내부 검증 계약이며 [외부 TOLERANCE](../TOLERANCE.md)를 변경하지 않는다. - IEEE binary64의 내부 검증 계약이며 [외부 TOLERANCE](../TOLERANCE.md)를 변경하지 않는다.
- 아래 `NOT RUN`은 r1 문서 검토 당시의 기록이다. 변경된 C5의 실제 실행 판정은
[종료 제어 구현 검토](implementation-feast-residual-review.md)를 따른다.
## C1–C4, C6, C7의 독립 검토 후 명시 채택 ## C1–C4, C6, C7의 독립 검토 후 명시 채택
@@ -46,15 +48,25 @@ Seed 변경으로 통과를 찾지 않는다. oneMKL thread-local 1을 설정하
| Index | 값 | | Index | 값 |
| --- | --- | | --- | --- |
| `[0],[1],[2],[3]` | `0,16,12,20` | | `[0],[1],[2],[3]` | `0,16,12,20` |
| `[4],[5],[13]` | `1,1,0` | | `[4],[5],[13]` | `1,0,0` |
| `[26],[27]` | `1,1` | | `[26],[27]` | `1,1` |
| `[49]` | Count `1`, solve `0` | | `[49]` | Count `1`, solve `0` |
| `[63]` | `0` | | `[63]` | `0` |
나머지는 해당 설치의 초기값을 유지·기록한다. 이번 [Intel parameter table](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2026-0/extended-eigensolver-input-parameters.html)의 허용 contour16, 나머지는 해당 설치의 초기값을 유지·기록한다. 이번 [Intel parameter table](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2026-0/extended-eigensolver-input-parameters.html)의 허용 contour16,
trace stopping, CSR/SPD checks와 count flag reset을 확인했다. 위 값은 FESA의 고정 residual stopping, CSR/SPD checks와 count flag reset을 확인했다. 위 값은 FESA의 고정
제어 선택이며 어떤 matrix에서도 수렴한다는 vendor 보장이 아니다. 제어 선택이며 어떤 matrix에서도 수렴한다는 vendor 보장이 아니다.
2026-09-10 사용자 승인으로 C-index `fpm[5]=1` trace stopping을 `0` residual stopping으로
대체한다. Double precision의 vendor stopping epsilon은 `10^-fpm[2]=1e-12`이며
`fpm[3]=20`을 유지한다. Count/solve 모두 같은 초기 controls를 적용하고 `[49]`만 구분한다.
전체 c개의 독립 `rho_B=||Bx-mu x||2/||x||2<=1e-10`, Gram 및 original-free 복구 검증은
그대로다. Vendor residual의 정규화와 독립 rho_B를 동일시하지 않으며 `info=0`도 독립 검증을
대체하지 않는다. `epsout`은 trace 변화 진단량으로 보존하고 새 residual 오차로 재해석하지 않는다.
기존 trace 실행의 pass/fail·loop·epsout은 당시 controls의 이력이다. Zero/mixed-zero/repeated
및 원본 모델의 새 실행과 미해결 위험은 [종료 제어 구현 검토](implementation-feast-residual-review.md)에
구분한다. S3·물리 정식화·공통 외부 tolerance는 이 결정으로 변경하지 않는다.
Gershgorin off-diagonal absolute row sum은 매 합산 뒤 `nextafter(+infinity)`로 outward Gershgorin off-diagonal absolute row sum은 매 합산 뒤 `nextafter(+infinity)`로 outward
누적하고 diagonal±sum도 바깥 한 ULP를 적용한다. `beta=norm(B,inf)`도 outward로 구한다. 누적하고 diagonal±sum도 바깥 한 ULP를 적용한다. `beta=norm(B,inf)`도 outward로 구한다.
`B=0`의 algorithmic enclosure에서만 beta=1이며 physical mass/λ floor가 아니다. `B=0`의 algorithmic enclosure에서만 beta=1이며 physical mass/λ floor가 아니다.
@@ -137,7 +137,7 @@ Status Validate(const Domain& domain, const EigenAnalysisState& state,
{2U, 12}, {2U, 12},
{3U, 20}, {3U, 20},
{4U, 1}, {4U, 1},
{5U, 1}, {5U, 0},
{13U, 0}, {13U, 0},
{26U, 1}, {26U, 1},
{27U, 1}, {27U, 1},
@@ -174,7 +174,7 @@ void SetControls(std::array<MKL_INT, 128>& fpm, const bool count) {
fpm[2] = 12; fpm[2] = 12;
fpm[3] = 20; fpm[3] = 20;
fpm[4] = 1; fpm[4] = 1;
fpm[5] = 1; fpm[5] = 0; // Trace convergence alone can leave individual pairs inaccurate.
fpm[13] = 0; fpm[13] = 0;
fpm[26] = 1; fpm[26] = 1;
fpm[27] = 1; fpm[27] = 1;
@@ -3,6 +3,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <hdf5.h> #include <hdf5.h>
#include <array>
#include <cstdint>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <functional> #include <functional>
@@ -78,6 +80,15 @@ TEST(EigenHdf5ResultsWriter, WritesModalSchemaAndRejectsTamperedState) {
H5Fopen(path.string().c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); H5Fopen(path.string().c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
ASSERT_GE(file, 0); ASSERT_GE(file, 0);
EXPECT_GT(H5Lexists(file, "/steps/Step-1/eigen/modes", H5P_DEFAULT), 0); EXPECT_GT(H5Lexists(file, "/steps/Step-1/eigen/modes", H5P_DEFAULT), 0);
const hid_t controls =
H5Dopen2(file, "/steps/Step-1/eigen/backend/base_fpm", H5P_DEFAULT);
ASSERT_GE(controls, 0);
std::array<std::int64_t, 128> stored_controls{};
ASSERT_GE(H5Dread(controls, H5T_NATIVE_INT64, H5S_ALL, H5S_ALL,
H5P_DEFAULT, stored_controls.data()),
0);
EXPECT_EQ(stored_controls[5U], 0);
EXPECT_GE(H5Dclose(controls), 0);
EXPECT_GE(H5Fclose(file), 0); EXPECT_GE(H5Fclose(file), 0);
std::ifstream original_file{path, std::ios::binary}; std::ifstream original_file{path, std::ios::binary};
const std::string original{std::istreambuf_iterator<char>{original_file}, {}}; const std::string original{std::istreambuf_iterator<char>{original_file}, {}};
@@ -91,6 +102,7 @@ TEST(EigenHdf5ResultsWriter, WritesModalSchemaAndRejectsTamperedState) {
[](auto& candidate) { candidate.modes[0].cluster_id = 7U; }, [](auto& candidate) { candidate.modes[0].cluster_id = 7U; },
[](auto& candidate) { candidate.constraint_mask[0] = 1U; }, [](auto& candidate) { candidate.constraint_mask[0] = 1U; },
[](auto& candidate) { candidate.nodal_reduction[0].rcond_inf = 1e-15; }, [](auto& candidate) { candidate.nodal_reduction[0].rcond_inf = 1e-15; },
[](auto& candidate) { candidate.backend.base_fpm[5U] = 1; },
[](auto& candidate) { candidate.eta_gram = 1e-5; }}; [](auto& candidate) { candidate.eta_gram = 1e-5; }};
for (const auto& mutate : mutations) { for (const auto& mutate : mutations) {
auto candidate = state; auto candidate = state;
@@ -71,6 +71,8 @@ TEST(MklFeastEigenSolver, SolvesN1AndRetainsBackendEvidence) {
EXPECT_EQ(result.Value().eigenvectors.Rows(), 1U); EXPECT_EQ(result.Value().eigenvectors.Rows(), 1U);
EXPECT_EQ(result.Value().eigenvectors.Columns(), 1U); EXPECT_EQ(result.Value().eigenvectors.Columns(), 1U);
EXPECT_EQ(result.Value().thread_count, 1U); EXPECT_EQ(result.Value().thread_count, 1U);
ASSERT_EQ(result.Value().base_fpm.size(), 128U);
EXPECT_EQ(result.Value().base_fpm[5U], 0);
ASSERT_FALSE(result.Value().backend_calls.empty()); ASSERT_FALSE(result.Value().backend_calls.empty());
EXPECT_EQ(result.Value().backend_calls.front().purpose, "total-enclosure"); EXPECT_EQ(result.Value().backend_calls.front().purpose, "total-enclosure");
EXPECT_EQ(result.Value().backend_calls.back().kind, "solve"); EXPECT_EQ(result.Value().backend_calls.back().kind, "solve");