generate.py

back to table · edit · history · where entries came from · files · download

3019 bytes, as of the version from 2026-10-28 07:03 (current). Recorded here, not run.

"""Trace moments of induced random density matrices -- numberdb.org/T574.

Run with SageMath:
    sage -pip install numberdb
    sage -python generate.py                  # verify every stored entry
    sage -python generate.py --fill           # write entries to this draft

Writing needs NUMBERDB_API_KEY, or NUMBERDB_KEY_FROM_STDIN=1 with a key on
stdin. Filling a draft does not publish or offer it for review.

M_q(N,K) = E Tr(rho^q), for a Haar-uniform pure state on C^N tensor C^K
and rho its N-dimensional reduced density matrix. Complex ensemble only;
ordinary trace, not trace divided by N. Nechita (2007), equations (37)-(38),
give the recurrence used here. All arithmetic is exact over QQ. The suspect
finite sum in that paper's equation (36) is not used. See checks.py for an
independent Wick-permutation computation and eigenvalue-density integration.

Default extent: 2 <= N <= K, N*K <= 64, 2 <= q <= 8. The product bound
controls the underlying Hilbert-space dimension; the moment bound makes
exhaustive permutation validation practical. See argument-selection.md.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from functools import lru_cache
from math import isqrt
import os
import sys


@lru_cache(maxsize=None)
def moment(N, K, q):
    """Exact complex induced trace moment; q=0 and q=1 are controls."""
    if N < 1 or K < 1 or q < 0:
        raise ValueError('Require positive integer dimensions and q >= 0')
    if q == 0:
        return QQ(N)
    if q == 1:
        return QQ(1)
    first = QQ((2*q-1)*(N+K)) / QQ((N*K+q-1)*(q+1))
    second = QQ((q-2)*((q-1)**2-(K-N)**2)) / QQ((N*K+q-1)*(N*K+q-2)*(q+1))
    return first*moment(N, K, q-1) + second*moment(N, K, q-2)


class InducedTraceMoments(numberdb.Generator):
    table = 'T574'
    parameters = ('N', 'K', 'q')
    type = 'Q'
    rigour = 'exact'
    files = ('generate.py', 'checks.py', 'argument-selection.md', 'source-notes.md')

    def enumerate(self, max_dimension=64, max_order=8):
        for N in range(2, isqrt(max_dimension)+1):
            for K in range(N, max_dimension//N+1):
                for q in range(2, max_order+1):
                    yield {'N': N, 'K': K, 'q': q}

    def value(self, params, digits=100):
        N, K, q = (int(params[name]) for name in self.parameters)
        if not 2 <= N <= K or q < 2:
            raise ValueError('Require 2 <= N <= K and q >= 2')
        return moment(N, K, q)


if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        os.environ['NUMBERDB_API_KEY'] = sys.stdin.read().strip()
    generator = InducedTraceMoments()
    if '--fill' in sys.argv or os.environ.get('NUMBERDB_FILL_DRAFT') == '1':
        print(generator.publish(message='Fill exact induced trace moments after independent checks',
                                assisted_by=os.environ.get('NUMBERDB_ASSISTED_BY', '')))
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)