license import { getGlobal } from './global_util' ; import { tensorToString } from './tensor_format' ; import { ArrayMap , BackendValues , DataType , DataTypeMap , DataValues , NumericDataType , Rank , ShapeMap , SingleValueMap , TypedArray } from './types' ; import * as util from './util' ; import { computeStrides , toNestedArray } from './util' ; export interface TensorData < D extends DataType > { dataId ? : DataId ; values ? : DataTypeMap [ D ] ; } export interface Backend { } doc export class TensorBuffer < R extends Rank , D extends DataType = 'float32' > { size : number ; shape : ShapeMap [ R ] ; strides : number [ ] ; values : DataTypeMap [ D ] ; constructor ( shape , public dtype , values ? ) { this . shape = shape . slice ( ) as ShapeMap [ R ] ; this . size = util . sizeFromShape ( shape ) ; if ( values != null ) { const n = values . length ; util . assert ( n === this . size , ( ) => `Length of values '${ n }' does not match the size ` + `inferred by the shape '${ this . size }'.` ) ; } if ( dtype === 'complex64' ) { throw new Error ( `complex64 dtype TensorBuffers are not supported. Please create ` + `a TensorBuffer for the real and imaginary parts separately and ` + `call tf.complex(real, imag).` ) ; } this . values = values || util . getArrayFromDType ( dtype , this . size ) ; this . strides = computeStrides ( shape ) ; } param value param locs doc set ( value , ... locs ) { if ( locs . length === 0 ) { locs = [ 0 ] ; } util . assert ( locs . length === this . rank , ( ) => `The number of provided coordinates (${ locs . length }) must ` + `match the rank (${ this . rank })` ) ; const index = this . locToIndex ( locs ) ; this . values [ index ] = value as number ; } param locs doc get ( ... locs ) { if ( locs . length === 0 ) { locs = [ 0 ] ; } let i = 0 ; for ( const loc of locs ) { if ( loc < 0 || loc >= this . shape [ i ] ) { const msg = `Requested out of range element at ${ locs }. ` + `  Buffer shape=${ this . shape }` ; throw new Error ( msg ) ; } i ++ ; } let index = locs [ locs . length - 1 ] ; for ( let i = 0 ; i < locs . length - 1 ; ++ i ) { index += this . strides [ i ] * locs [ i ] ; } return this . values [ index ] as SingleValueMap [ D ] ; } locToIndex ( locs ) { if ( this . rank === 0 ) { return 0 ; } else if ( this . rank === 1 ) { return locs [ 0 ] ; } let index = locs [ locs . length - 1 ] ; for ( let i = 0 ; i < locs . length - 1 ; ++ i ) { index += this . strides [ i ] * locs [ i ] ; } return index ; } indexToLoc ( index ) { if ( this . rank === 0 ) { return [ ] ; } else if ( this . rank === 1 ) { return [ index ] ; } const locs = new Array ( this . shape . length ) ; for ( let i = 0 ; i < locs . length - 1 ; ++ i ) { locs [ i ] = Math . floor ( index / this . strides [ i ] ) ; index -= locs [ i ] * this . strides [ i ] ; } locs [ locs . length - 1 ] = index ; return locs ; } get rank ( ) { return this . shape . length ; } doc toTensor ( ) { return trackerFn ( ) . makeTensor ( this . values , this . shape , this . dtype ) as Tensor < R > ; } } export interface DataToGPUWebGLOption { customTexShape ? : [ number , number ] ; } export type DataToGPUOptions = DataToGPUWebGLOption ; export interface GPUData { tensorRef : Tensor ; texture ? : WebGLTexture ; texShape ? : [ number , number ] ; } export interface TensorTracker { makeTensor ( values , shape , dtype , backend ? ) : Tensor ; makeVariable ( initialValue , trainable ? , name ? , dtype ? ) : Variable ; incRef ( a , backend ) : void ; disposeTensor ( t ) : void ; disposeVariable ( v ) : void ; read ( dataId ) : Promise < BackendValues > ; readSync ( dataId ) : BackendValues ; readToGPU ( dataId , options ? ) : GPUData ; } /**
 * The Tensor class calls into this handler to delegate chaining operations.
 */ export interface OpHandler { cast < T extends Tensor > ( x , dtype ) : T ; buffer < R extends Rank , D extends DataType > ( shape , dtype , values ? ) : TensorBuffer < R , D > ; print < T extends Tensor > ( x , verbose ) : void ; clone < T extends Tensor > ( x ) : T ; } let trackerFn = null ; let opHandler = null ; let deprecationWarningFn = null ; [ deprecationWarningFn ] ; /**
 * An external consumer can register itself as the tensor tracker. This way
 * the Tensor class can notify the tracker for every tensor created and
 * disposed.
 */ export function setTensorTracker ( fn ) { trackerFn = fn ; } /**
 * An external consumer can register itself as the op handler. This way the
 * Tensor class can have chaining methods that call into ops via the op
 * handler.
 */ export function setOpHandler ( handler ) { opHandler = handler ; } /**
 * Sets the deprecation warning function to be used by this file. This way the
 * Tensor class can be a leaf but still use the environment.
 */ export function setDeprecationWarningFn ( fn ) { deprecationWarningFn = fn ; } /**
 * We wrap data id since we use weak map to avoid memory leaks.
 * Since we have our own memory management, we have a reference counter
 * mapping a tensor to its data, so there is always a pointer (even if that
 * data is otherwise garbage collectable).
 * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
 * Global_Objects/WeakMap
 */ export type DataId = object ; export declare namespace Tensor { } doc export class Tensor < R extends Rank = Rank > { /** Unique id of this tensor. */ readonly id : number ; /**
     * Id of the bucket holding the data for this tensor. Multiple arrays can
     * point to the same bucket (e.g. when calling array.reshape()).
     */ dataId : DataId ; /** The shape of the tensor. */ readonly shape : ShapeMap [ R ] ; /** Number of elements in the tensor. */ readonly size : number ; /** The data type for the array. */ readonly dtype : DataType ; /** The rank type for the array (see `Rank` enum). */ readonly rankType : R ; /** Whether this tensor has been globally kept. */ kept = false ; /** The id of the scope this tensor is being tracked in. */ scopeId : number ; /**
     * Number of elements to skip in each dimension when indexing. See
     * https://docs.scipy.org/doc/numpy/reference/generated/\
     * numpy.ndarray.strides.html
     */ readonly strides : number [ ] ; constructor ( shape , dtype , dataId , id ) { this . shape = shape . slice ( ) as ShapeMap [ R ] ; this . dtype = dtype || 'float32' ; this . size = util . sizeFromShape ( shape ) ; this . strides = computeStrides ( shape ) ; this . dataId = dataId ; this . id = id ; this . rankType = ( this . rank < 5 ? this . rank . toString ( ) : 'higher' ) as R ; } get rank ( ) : number { return this . shape . length ; } doc async buffer < D extends DataType = 'float32' > ( ) { const vals = await this . data < D > ( ) ; return opHandler . buffer ( this . shape , this . dtype as D , vals ) ; } doc bufferSync < D extends DataType = 'float32' > ( ) { return opHandler . buffer ( this . shape , this . dtype as D , this . dataSync ( ) ) ; } doc async array ( ) { const vals = await this . data ( ) ; return toNestedArray ( this . shape , vals , this . dtype === 'complex64' ) as ArrayMap [ R ] ; } doc arraySync ( ) { return toNestedArray ( this . shape , this . dataSync ( ) , this . dtype === 'complex64' ) as ArrayMap [ R ] ; } doc async data < D extends DataType = NumericDataType > ( ) { this . throwIfDisposed ( ) ; const data = trackerFn ( ) . read ( this . dataId ) ; if ( this . dtype === 'string' ) { const bytes = await data as Uint8Array [ ] ; try { return bytes . map ( b => util . decodeString ( b ) ) as DataTypeMap [ D ] ; } catch { throw new Error ( 'Failed to decode the string bytes into utf-8. ' + 'To get the original bytes, call tensor.bytes().' ) ; } } return data as Promise < DataTypeMap [ D ] > ; } param options returns doc dataToGPU ( options ? ) { this . throwIfDisposed ( ) ; return trackerFn ( ) . readToGPU ( this . dataId , options ) ; } doc dataSync < D extends DataType = NumericDataType > ( ) { this . throwIfDisposed ( ) ; const data = trackerFn ( ) . readSync ( this . dataId ) ; if ( this . dtype === 'string' ) { try { return ( data as Uint8Array [ ] ) . map ( b => util . decodeString ( b ) ) as DataTypeMap [ D ] ; } catch { throw new Error ( 'Failed to decode the string bytes into utf-8. ' + 'To get the original bytes, call tensor.bytes().' ) ; } } return data as DataTypeMap [ D ] ; } /** Returns the underlying bytes of the tensor's data. */ async bytes ( ) { this . throwIfDisposed ( ) ; const data = await trackerFn ( ) . read ( this . dataId ) ; if ( this . dtype === 'string' ) { return data as Uint8Array [ ] ; } else { return new Uint8Array ( ( data as TypedArray ) . buffer ) ; } } doc dispose ( ) { if ( this . isDisposed ) { return ; } trackerFn ( ) . disposeTensor ( this ) ; this . isDisposedInternal = true ; } protected isDisposedInternal = false ; get isDisposed ( ) : boolean { return this . isDisposedInternal ; } throwIfDisposed ( ) { if ( this . isDisposed ) { throw new Error ( `Tensor is disposed.` ) ; } } param verbose doc print ( verbose = false ) { return opHandler . print ( this , verbose ) ; } doc clone < T extends Tensor > ( this ) { this . throwIfDisposed ( ) ; return opHandler . clone ( this ) ; } doc toString ( verbose = false ) { const vals = this . dataSync ( ) ; return tensorToString ( vals , this . shape , this . dtype , verbose ) ; } cast < T extends this > ( dtype ) { this . throwIfDisposed ( ) ; return opHandler . cast ( this as T , dtype ) ; } variable ( trainable = true , name ? , dtype ? ) { this . throwIfDisposed ( ) ; return trackerFn ( ) . makeVariable ( this , trainable , name , dtype ) as Variable < R > ; } } Object . defineProperty ( Tensor , Symbol . hasInstance , { value : ( instance ) => { return ! ! instance && instance . data != null && instance . dataSync != null && instance . throwIfDisposed != null ; } } ) ; export function getGlobalTensorClass ( ) { return getGlobal ( 'Tensor' , ( ) => { return Tensor ; } ) ; } getGlobalTensorClass ( ) ; export interface NumericTensor < R extends Rank = Rank > extends Tensor < R > { dtype : NumericDataType ; dataSync < D extends DataType = NumericDataType > ( ) : DataTypeMap [ D ] ; data < D extends DataType = NumericDataType > ( ) : Promise < DataTypeMap [ D ] > ; dataToGPU ( options ? ) : GPUData ; } export interface StringTensor < R extends Rank = Rank > extends Tensor < R > { dtype : 'string' ; dataSync < D extends DataType = 'string' > ( ) : DataTypeMap [ D ] ; data < D extends DataType = 'string' > ( ) : Promise < DataTypeMap [ D ] > ; } doclink export type Scalar = Tensor < Rank . R0 > ; doclink export type Tensor1D = Tensor < Rank . R1 > ; doclink export type Tensor2D = Tensor < Rank . R2 > ; doclink export type Tensor3D = Tensor < Rank . R3 > ; doclink export type Tensor4D = Tensor < Rank . R4 > ; doclink export type Tensor5D = Tensor < Rank . R5 > ; doclink export type Tensor6D = Tensor < Rank . R6 > ; doc export class Variable < R extends Rank = Rank > extends Tensor < R > { name : string ; constructor ( initialValue , public trainable , name , tensorId ) { super ( initialValue . shape , initialValue . dtype , initialValue . dataId , tensorId ) ; this . name = name ; } param newValue doc assign ( newValue ) { if ( newValue . dtype !== this . dtype ) { throw new Error ( `dtype of the new value (${ newValue . dtype }) and ` + `previous value (${ this . dtype }) must match` ) ; } if ( ! util . arraysEqual ( newValue . shape , this . shape ) ) { throw new Error ( `shape of the new value (${ newValue . shape }) and ` + `previous value (${ this . shape }) must match` ) ; } trackerFn ( ) . disposeTensor ( this ) ; this . dataId = newValue . dataId ; trackerFn ( ) . incRef ( this , null ) ; } dispose ( ) { trackerFn ( ) . disposeVariable ( this ) ; this . isDisposedInternal = true ; } } Object . defineProperty ( Variable , Symbol . hasInstance , { value : ( instance ) => { return instance instanceof Tensor && instance . assign != null && instance . assign instanceof Function ; } } ) ;