T81 Foundation

T81 C++ Tensor Guide

This guide summarizes the lightweight T729Tensor implementation plus the supporting APIs shipped in include/t81/tensor. It is the practical reference for developers working with the current C++ tensor utilities.

Companion Documents:


1. Core Concepts


2. Creating a Tensor

Create a tensor by passing a shape (as initializer list or vector) and optionally providing the backing float data. The constructors validate positive dimensions, match the total size, and throw std::invalid_argument on mismatch.

#include "t81/tensor.hpp"
#include <iostream>

int main() {
    t81::T729Tensor a({2, 3});       // zero-initialized data
    a.data() = {1.0f, 2.0f, 3.0f,
                4.0f, 5.0f, 6.0f};

    std::cout << "Rank: " << a.rank() << '\n';
    std::cout << "Shape: ";
    for (int dim : a.shape()) std::cout << dim << ' ';
    std::cout << '\n';
    std::cout << "Data: ";
    for (float v : a.data()) std::cout << v << ' ';
    std::cout << '\n';

    return 0;
}

The same header also exposes utility methods such as T729Tensor::broadcast (naive right-aligned repeat), transpose2d, and contract_dot (dot product between rank-1 tensors) that make small helpers possible without the full ops suite.


3. Core Operations

All tensor operations live in t81::ops and expect T729Tensor arguments. These utilities work well with the examples/tensor_ops.cpp demo and the matching regression tests.

Matrix Multiplication (matmul)

t81::ops::matmul implements a standard 2D matrix product ((m×k)·(k×n) = m×n). It validates ranks and dimensions before constructing the result.

t81::T729Tensor A({2, 3}, std::vector<float>{1, 2, 3, 4, 5, 6});
t81::T729Tensor B({3, 2}, std::vector<float>{7, 8, 9, 10, 11, 12});
auto C = t81::ops::matmul(A, B); // 2×2

Test: tests/cpp/tensor_matmul_test.cpp

Transpose & Reshape

auto transposed = t81::ops::transpose(A);
auto reshaped = t81::ops::reshape(A, {3, 2});

Tests: tests/cpp/tensor_transpose_test.cpp, tests/cpp/tensor_reshape_test.cpp

Slicing & Indexing

t81::ops::slice2d extracts a half-open row/column range from a rank-2 tensor. It checks that the requested row and column bounds are in range before copying the requested rectangle.

auto patch = t81::ops::slice2d(A, 0, 1, 1, 3); // 1×2 block

Test: tests/cpp/tensor_slice_test.cpp

Reduction

reduce_sum_2d, reduce_max_2d, reduce_min_2d, and reduce_mean_2d collapse a rank-2 tensor along axis 0 (columns) or 1 (rows), producing a 1D tensor that summarizes the values.

auto row_sums = t81::ops::reduce_sum_2d(A, 1);
auto col_max = t81::ops::reduce_max_2d(A, 0);
auto col_min = t81::ops::reduce_min_2d(A, 0);
auto row_mean = t81::ops::reduce_mean_2d(A, 1);

Test: tests/cpp/tensor_reduce_test.cpp

Broadcasting & Elementwise Ops

broadcast_to uses the helpers in t81::shape to confirm right-aligned compatibility before materializing a larger tensor. elemwise_binary exposes add/sub/mul/div flavors that automatically broadcast mismatched shapes (div throws on divide-by-zero).

t81::T729Tensor broadcasted = t81::ops::broadcast_to(A, {2, 3});
auto summed = t81::ops::add(A, broadcasted);

Tests: tests/cpp/tensor_broadcast_test.cpp, tests/cpp/tensor_elementwise_test.cpp

Unary Functions

t81::ops::unary_map supports applying any float(float) functor to every element. The convenience helpers relu, tanh, exp, and log demonstrate common activation-style transforms with safety guards (e.g., log throws on negative inputs).

Test: tests/cpp/tensor_unary_test.cpp

IO & Serialization

Use t81::io::load_tensor_txt / save_tensor_txt (and their _file helpers) to stream tensors in a simple text format. T729Tensor also exposes serialize/deserialize for binary persistence, keeping the header/int64 counts for shape and data.

Test: tests/cpp/tensor_loader_test.cpp


4. Status & Next Steps

The tensor API is now feature-complete for v1.0: base storage for both float and ternary types, reshape/slice/matmul/reduce, broadcasting, elementwise, unary transforms, and IO are all implemented and covered by tests.

For a full list of planned work, see TASKS.md.