Skip to content

Create buggy test backend for TCICT test validation #17

Description

@ultimatile

Motivation

Mutation testing (see #1) revealed 16 surviving mutations — cases where TCICT conformance tests fail to detect buggy implementations. As fixes are applied to TCICT (issues #2#16), we need a way to verify that the fixed tests actually catch the intended bugs.

The current approach (mutation_test.py in tci-cytnx) uses source-level string matching to introduce mutations, which is fragile and tightly coupled to tci-cytnx internals.

Proposal

Create a minimal stub backend (StubTensor) within the tcict repository that intentionally implements TCI APIs incorrectly. This serves as a "test of the tests" — every TCICT conformance test should fail when run against the corresponding buggy implementation.

StubTensor design

A minimal tensor implementation using only standard library types:

template <typename ElemT>
struct StubTensor {
    std::vector<ElemT> data;
    std::vector<uint64_t> shape;
};

With TCI traits specialized for StubTensor, implementing only what TCICT tests need: allocate, zeros, fill, order, shape, size, size_bytes, get_elem, set_elem, for_each, close, etc.

Linear algebra functions (QR, LQ, SVD, exp, etc.) only need to return tensors with correct shapes — no actual computation required. The current surviving mutations prove that TCICT tests don't verify numerical correctness for these, so returning zeros with the right shape is sufficient to reproduce the gaps.

Bug selection via preprocessor

Each bug is guarded by a define so they can be tested individually:

template <typename TenT>
TenT zeros(context_handle_t<TenT>& ctx, const shape_t<TenT>& shape) {
#ifdef TCICT_BUG_ZEROS_RETURNS_ONES
    return fill(ctx, shape, elem_t<TenT>(1));
#else
    return fill(ctx, shape, elem_t<TenT>(0));
#endif
}

Bugs to implement (mapped to issues)

Function Bug Validates fix for
zeros fill with 1 instead of 0 #3
fill skip fill loop #3
allocate wrong element type / shape #15
clear no-op #13
move clone instead of move #14
scale no-op #7
trace no-op (return input unchanged) #8
svd swap U and V† #9
qr return zero matrices with correct shape #4
lq return zero matrices with correct shape #5
eigvals negate eigenvalues #10
eigvalsh negate eigenvalues #11
stack skip stacking dimension #12
exp return identity #6
save no-op #16
eye return zeros instead of identity #2

Repository structure

tcict/
  include/tcict/
    tests/                     # existing conformance tests
  test_backends/
    stub/
      stub_tensor.h            # StubTensor + TCI traits
      stub_tci_impl.h          # correct TCI API implementations
      stub_tci_buggy.h         # buggy implementations (#ifdef guarded)
    CMakeLists.txt             # build test runner
    buggy_runner.cpp           # run TCICT, expect failures

CI integration

- run: |
    cmake -DTCICT_BUG_ZEROS_RETURNS_ONES=ON ...
    ctest  # should FAIL — if it passes, TCICT has a gap

Fallback plan

If StubTensor's TCI traits specialization proves unexpectedly complex, fall back to a buggy branch approach in tci-cytnx (use the existing full implementation, just introduce bugs).

Alternatives considered

  • Buggy branch of tci-cytnx: lower initial cost but adds Cytnx build dependency to tcict's test infrastructure. Linear algebra functions don't actually need real computation (surviving mutations prove TCICT doesn't check values), so the Cytnx dependency is unnecessary.
  • Source-level mutation script (mutation_test.py): fragile string matching, breaks on refactor
  • Mull (LLVM IR mutation): operator-level mutations don't capture semantic gaps
  • API wrapper mutations: can't express internal logic bugs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions