Source code for tltorch.utils.tensorize_shape

import numpy as np
import math
from bisect import insort_left

# Author : Jean Kossaifi

def factorize(value, min_value=2, remaining=-1):
    """Factorize an integer input value into it's smallest divisors
    
    Parameters
    ----------
    value : int
        integer to factorize
    min_value : int, default is 2
        smallest divisors to use
    remaining : int, default is -1
        DO NOT SPECIFY THIS VALUE, IT IS USED FOR TAIL RECURSION

    Returns
    -------
    factorization : int tuple
        ints such that prod(factorization) == value
    """
    if value <= min_value or remaining == 0:
        return (value, )
    lim = math.isqrt(value)
    for i in range(min_value, lim+1):
        if value == i:
            return (i, )
        if not (value % i):
            return (i, *factorize(value//i, min_value=min_value, remaining=remaining-1))
    return (value, )

def merge_ints(values, size):
    """Utility function to merge the smallest values in a given tuple until it's length is the given size
    
    Parameters
    ----------
    values : int list
        list of values to merge
    size : int
        target len of the list
        stop merging when len(values) <= size
    
    Returns
    -------
    merge_values : list of size ``size``
    """
    if len(values) <= 1:
        return values

    values = sorted(list(values))
    while (len(values) > size):
        a, b, *values = values
        insort_left(values, a*b)
    
    return tuple(values)
    
[docs]def get_tensorized_shape(in_features, out_features, order=None, min_dim=2, verbose=True): """ Factorizes in_features and out_features such that: * they both are factorized into the same number of integers * they should both be factorized into `order` integers * each of the factors should be at least min_dim This is used to tensorize a matrix of size (in_features, out_features) into a higher order tensor Parameters ---------- in_features, out_features : int order : int the number of integers that each input should be factorized into min_dim : int smallest acceptable integer value for the factors Returns ------- in_tensorized, out_tensorized : tuple[int] tuples of ints used to tensorize each dimension Notes ----- This is a bruteforce solution but is enough for the dimensions we encounter in DNNs """ in_ten = factorize(in_features, min_value=min_dim) out_ten = factorize(out_features, min_value=min_dim, remaining=len(in_ten)) if order is not None: merge_size = min(order, len(in_ten), len(out_ten)) else: merge_size = min(len(in_ten), len(out_ten)) if len(in_ten) > merge_size: in_ten = merge_ints(in_ten, size=merge_size) if len(out_ten) > merge_size: out_ten = merge_ints(out_ten, size=merge_size) if verbose: print(f'Tensorizing (in, out)=({in_features, out_features}) -> ({in_ten, out_ten})') return in_ten, out_ten