Skip to content

[codex] fix Tensor.Fromfile and Eig values-only regressions#884

Draft
ianmccul wants to merge 5 commits into
masterfrom
codex/add-regression-tests-issues-880-883
Draft

[codex] fix Tensor.Fromfile and Eig values-only regressions#884
ianmccul wants to merge 5 commits into
masterfrom
codex/add-regression-tests-issues-880-883

Conversation

@ianmccul

@ianmccul ianmccul commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Fixes two issue reports opened from the repo review. The package-config report in #882 is intentionally excluded because maintainers noted it was already fixed by #809 and #811 and master already has tests/downstream_find_package plus a dedicated GitHub Action for that path.

Fixes #881
Fixes #883

Changes:

  • Python Tensor.Fromfile(fname, dtype, count) now dispatches to cytnx::Tensor::Fromfile instead of cytnx::Tensor::Load, so raw Tensor.Tofile output can be read back through the Python API.
  • Complex Eig(..., false) LAPACKE paths initialize the unused eigenvector pointer to nullptr when eigenvectors are not requested.
  • Adds regression coverage for the Python raw-file round trip and order-insensitive linalg::Eig(..., false) eigenvalue comparison.

Validation performed locally:

  • python3 -m py_compile pytests/io/test_tensor_fromfile.py
  • git diff --check
  • cmake --build /tmp/cytnx-storage-fromfile-count-build --target test_main -j2
  • /usr/bin/ctest --test-dir /tmp/cytnx-storage-fromfile-count-build -R '^linalg_Test\.Tensor_Eig_ValuesOnly$' --output-on-failure
  • cmake --build /tmp/cytnx-tdvp-python-build --target pycytnx -j2
  • PYTHONPATH=/tmp/cytnx-pydeps:/tmp/cytnx-pr884-testpkg pytest pytests/io/test_tensor_fromfile.py -q from a temp test root: 1 passed in 0.18s

Note: the reused local CMake coverage build emitted gcov checksum warnings while relinking after branch changes; the focused tests passed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several unit tests for Fromfile storage operations, CMake package configuration exports, and the linalg::Eig function. The review feedback highlights a critical bug in the underlying Storage::Fromfile implementation where an uninitialized variable Nelem causes undefined behavior when count >= 0. Additionally, the reviewer recommends extending the CMake test to build the consumer project rather than just configuring it, and refactoring the eigenvalue test to compare values in an order-independent manner to prevent flaky test failures.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread tests/Storage_test.cpp Outdated
Storage source = Storage::from_vector(std::vector<cytnx_double>{1.0, 2.0, 3.0, 4.0});
source.Tofile(path);

EXPECT_THROW(Storage::Fromfile(path, Type.Double, 5), std::logic_error);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Note that Storage::Fromfile currently contains a critical bug where the Nelem variable is used uninitialized when count >= 0 (which is the case here since count = 5).

Specifically, in src/backend/Storage.cpp:

199:    cytnx_uint64 Nelem;
...
217:    if (count < 0)
218:      Nelem = Nbytes / Type.typeSize(dtype);
219:    else {
220:      cytnx_error_msg(count > Nelem, "[ERROR] count exceed the total # of elements %d in file.\n",
221:                      Nelem);

When count >= 0, the else branch is taken, and count > Nelem is evaluated while Nelem is still uninitialized, leading to undefined behavior. This test might pass or fail unpredictably depending on the compiler and stack garbage. Please fix the uninitialized variable bug in src/backend/Storage.cpp as well.

Comment thread tests/CMakeLists.txt Outdated
Comment on lines +68 to +74
add_test(
NAME package_config_exports_linkable_target
COMMAND ${CMAKE_COMMAND}
-S ${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_config_consumer
-B ${CMAKE_CURRENT_BINARY_DIR}/package_config_consumer
-DCMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The test package_config_exports_linkable_target currently only runs the CMake configuration step (-S ... -B ...). It does not actually build (compile and link) the consumer project.

To verify that the package configuration exposes a truly linkable target (as intended by this test), the project must also be built. We can achieve this in a platform-independent way by adding a second test for the build step and making it depend on the configuration test.

add_test(
  NAME package_config_exports_linkable_target_configure
  COMMAND ${CMAKE_COMMAND}
          -S ${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_config_consumer
          -B ${CMAKE_CURRENT_BINARY_DIR}/package_config_consumer
          -DCMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}
)

add_test(
  NAME package_config_exports_linkable_target_build
  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/package_config_consumer
)

set_tests_properties(package_config_exports_linkable_target_build
                     PROPERTIES DEPENDS package_config_exports_linkable_target_configure)

Comment on lines +367 to +370
for (cytnx_uint64 i = 0; i < values_only[0].shape()[0]; ++i) {
EXPECT_TRUE(abs(values_only[0].at<cytnx_complex128>({i}) -
with_vectors[0].at<cytnx_complex128>({i})) < 1e-13);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Eigenvalues of a non-symmetric matrix returned by linalg::Eig are not guaranteed to be in any specific order, and the order can differ depending on whether eigenvectors are computed or not (or across different BLAS/LAPACK backends).

Comparing them element-by-element directly can lead to flaky test failures in CI/CD environments. It is much more robust to verify that each eigenvalue in values_only has a matching counterpart in with_vectors within the specified tolerance, regardless of their order.

Suggested change
for (cytnx_uint64 i = 0; i < values_only[0].shape()[0]; ++i) {
EXPECT_TRUE(abs(values_only[0].at<cytnx_complex128>({i}) -
with_vectors[0].at<cytnx_complex128>({i})) < 1e-13);
}
for (cytnx_uint64 i = 0; i < values_only[0].shape()[0]; ++i) {
bool found = false;
auto val = values_only[0].at<cytnx_complex128>({i});
for (cytnx_uint64 j = 0; j < with_vectors[0].shape()[0]; ++j) {
if (abs(val - with_vectors[0].at<cytnx_complex128>({j})) < 1e-13) {
found = true;
break;
}
}
EXPECT_TRUE(found);
}

@IvanaGyro

Copy link
Copy Markdown
Collaborator

I guess your report was generated from abandoned dev-master branch. All PR should target to master branch now.

@ianmccul ianmccul changed the base branch from dev-master to master June 12, 2026 07:17
@ianmccul

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new tests for Tensor.Fromfile in Python, package configuration consumer tests in CMake, and unit tests for Tensor_Eig_ValuesOnly in C++. The feedback identifies a critical bug where cy.Tensor.Fromfile is incorrectly bound to cytnx::Tensor::Load in Python, which will cause the new Python test to fail. Additionally, it is recommended to explicitly set the C++17 standard in the package consumer's CMake configuration and to use std::abs instead of abs for complex numbers in the C++ tests to prevent compilation or overload resolution issues.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

tensor = cy.arange(0, 5, 1, dtype=cy.Type.Double)

tensor.Tofile(str(path))
loaded = cy.Tensor.Fromfile(str(path), cy.Type.Double)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The cy.Tensor.Fromfile method in Python is currently bound to cytnx::Tensor::Load in pybind/tensor_py.cpp (line 302) instead of cytnx::Tensor::Fromfile.\n\nBecause Tensor::Load expects a serialized Cytnx tensor format (which starts with the 888 magic header), while Tensor.Tofile writes raw binary data, this test is guaranteed to fail with [ERROR] the object is not a cytnx tensor!.\n\nTo fix this, please update the binding in pybind/tensor_py.cpp to call cytnx::Tensor::Fromfile(fname, dtype, count) instead of cytnx::Tensor::Load(fname).

@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.20)
project(CytnxPackageConfigConsumer LANGUAGES CXX)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since cytnx uses C++17 features (such as std::variant in Tensor.hpp), the consumer project should explicitly require C++17 to ensure successful compilation across all compilers and environments.\n\nPlease set CMAKE_CXX_STANDARD to 17 and CMAKE_CXX_STANDARD_REQUIRED to ON.

project(CytnxPackageConfigConsumer LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)

Comment thread tests/linalg_test/linalg_test.cpp Outdated
Comment on lines +372 to +373
if (!matched[j] &&
abs(value - with_vectors[0].at<cytnx_complex128>({j})) < 1e-13) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the bare abs function on a std::complex argument can lead to compilation errors or incorrect overload resolution (e.g., resolving to ::abs(int) from <stdlib.h>) on some compilers. It is safer and more portable to explicitly use std::abs from <complex>.

      if (!matched[j] &&\n          std::abs(value - with_vectors[0].at<cytnx_complex128>({j})) < 1e-13) {

Comment on lines +1 to +6
#include "cytnx.hpp"

int main() {
cytnx::Tensor tensor({1});
return tensor.shape()[0] == 1 ? 0 : 1;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have this test in https://github.com/Cytnx-dev/Cytnx/tree/master/tests/downstream_find_package , and GitHub action has guarded the test.

@ianmccul ianmccul force-pushed the codex/add-regression-tests-issues-880-883 branch from 67a51dc to 763932b Compare June 12, 2026 07:51
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 29.54%. Comparing base (87c9fd5) to head (3a86756).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
pybind/tensor_py.cpp 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #884      +/-   ##
==========================================
+ Coverage   29.49%   29.54%   +0.05%     
==========================================
  Files         241      241              
  Lines       35524    35524              
  Branches    14780    14780              
==========================================
+ Hits        10477    10495      +18     
+ Misses      17791    17747      -44     
- Partials     7256     7282      +26     
Flag Coverage Δ
cpp 29.14% <66.66%> (+0.05%) ⬆️
python 52.71% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
C++ backend 30.79% <100.00%> (+0.05%) ⬆️
Python bindings 17.14% <0.00%> (+0.04%) ⬆️
Python package 52.71% <ø> (ø)
Files with missing lines Coverage Δ
src/backend/linalg_internal_cpu/Eig_internal.cpp 85.29% <100.00%> (ø)
pybind/tensor_py.cpp 21.18% <0.00%> (+0.07%) ⬆️

... and 3 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 87c9fd5...3a86756. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ianmccul ianmccul changed the title [codex] add regression tests for issue repros [codex] fix Tensor.Fromfile and Eig values-only regressions Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Eig(is_V=false) passes uninitialized eigenvector pointer to LAPACKE Python Tensor.Fromfile dispatches to Tensor::Load instead of raw Fromfile

2 participants