Skip to content

feat: Add dummy index insertion utility for partial LinearOperator #151

@shinaoka

Description

@shinaoka

Summary

Add a utility to insert dim=1 dummy indices into MPO/state for nodes that are missing input or output site indices. This allows representing partial/rectangular operators while keeping the existing LinearOperator implementation unchanged.

Motivation

Some operators naturally have asymmetric input/output structure:

  • Embedding operators (fewer inputs than outputs)
  • Projection operators (fewer outputs than inputs)
  • Operators with "gaps" in the middle (some nodes have no physical index on one side)

Rather than generalizing LinearOperator (which would require changes to apply, projected_operator, linsolve, etc.), we insert dim=1 dummy indices to satisfy the existing "1 input + 1 output per node" constraint.

Proposed Approach

Insert Dummy Indices Utility

/// Insert dim=1 dummy indices where input or output site indices are missing.
///
/// For each node:
/// - If missing input site index → insert dummy input with dim=1
/// - If missing output site index → insert dummy output with dim=1
pub fn insert_dummy_indices<T, V>(
    mpo: &mut TreeTN<T, V>,
    input_sites: &HashMap<V, T::Index>,   // nodes that have real input
    output_sites: &HashMap<V, T::Index>,  // nodes that have real output
) -> DummyIndexInfo<V, T::Index>;

/// Information about inserted dummy indices (for later removal if needed)
pub struct DummyIndexInfo<V, I> {
    pub dummy_inputs: HashMap<V, I>,   // node → dummy input index
    pub dummy_outputs: HashMap<V, I>,  // node → dummy output index
}

Example

Original MPO with partial indices:

Nodes:     A        B        C        D        E
Input:     -        i_b      -        i_d      i_e
Output:    o_a      o_b      o_c      o_d      -

After insert_dummy_indices():

Nodes:     A          B        C          D        E
Input:     d_a(1)     i_b      d_c(1)     i_d      i_e
Output:    o_a        o_b      o_c        o_d      d_e(1)

(d_x(1) = dummy index with dim=1)

Now all nodes have exactly 1 input + 1 output, satisfying LinearOperator constraints.

State Padding

Corresponding utility for states:

/// Pad state with dim=1 dummy indices to match operator structure
pub fn pad_state_with_dummies<T, V>(
    state: &mut TreeTN<T, V>,
    dummy_info: &DummyIndexInfo<V, T::Index>,
) -> Result<()>;

/// Remove dummy indices from result state
pub fn remove_dummy_indices<T, V>(
    state: &mut TreeTN<T, V>,
    dummy_info: &DummyIndexInfo<V, T::Index>,
) -> Result<()>;

High-Level API

impl LinearOperator<T, V> {
    /// Create LinearOperator from partial MPO, auto-inserting dummy indices
    pub fn from_partial_mpo(
        mpo: TreeTN<T, V>,
        input_sites: HashMap<V, T::Index>,
        output_sites: HashMap<V, T::Index>,
    ) -> Result<(Self, DummyIndexInfo<V, T::Index>)>;
}

/// Apply partial operator, handling dummy indices automatically
pub fn apply_partial_operator<T, V>(
    operator: &LinearOperator<T, V>,
    state: TreeTN<T, V>,
    dummy_info: &DummyIndexInfo<V, T::Index>,
) -> Result<TreeTN<T, V>>;

Advantages

  1. No changes to LinearOperator core - apply, projected_operator, linsolve unchanged
  2. Simple implementation - just tensor product with dim=1 identity
  3. Mathematically equivalent - dim=1 index doesn't change the operator semantics
  4. Reversible - can remove dummy indices from results

Implementation Steps

  1. Add DummyIndexInfo struct
  2. Implement insert_dummy_indices() for MPO
  3. Implement pad_state_with_dummies() and remove_dummy_indices() for states
  4. Add LinearOperator::from_partial_mpo() convenience constructor
  5. Add apply_partial_operator() helper
  6. Add tests for various partial operator patterns
  7. Document with examples

Implementation Details

Inserting Dummy Index into Tensor

For a node tensor T[link1, link2, ..., site_out] missing input:

// Create dummy index with dim=1
let dummy_in = Index::new_dyn(1);

// Reshape tensor: T[link1, link2, ..., site_out] 
//              → T[link1, link2, ..., dummy_in, site_out]
// Since dummy_in has dim=1, this is just adding a trivial dimension

For a node tensor missing output, similar approach.

Rectangular Operators

For operators where total input size ≠ total output size:

  • Insert dummy indices as needed
  • The "missing" dimensions are dim=1, so they don't contribute to the vector space
  • Effectively represents projection or embedding

Related

Acceptance criteria

  • Utilities exist to:
    • insert dim=1 dummy input/output site indices into an MPO where missing
    • pad/unpad states consistently using DummyIndexInfo
  • Applying an operator padded with dim=1 dummies is semantically identical to the unpadded operator on the original (non-dummy) space.
  • Tests cover:
    • insertion on patterns with missing input/output at various nodes
    • pad_state_with_dummies + remove_dummy_indices roundtrip
    • apply_partial_operator produces a result that, after dummy removal, matches the expected result for a hand-constructed “already padded” reference operator.
  • Docs include at least one example of a partial/rectangular operator use-case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions