license import { Backend , DataId , DataToGPUOptions , GPUData } from '../tensor' ; import { BackendValues , DataType } from '../types' ; export const EPSILON_FLOAT32 = 1e-7 ; export const EPSILON_FLOAT16 = 1e-4 ; export interface BackendTimingInfo { kernelMs : number | { error : string ; } ; getExtraProfileInfo ? ( ) : string ; } export interface TensorStorage { read ( dataId ) : Promise < BackendValues > ; readSync ( dataId ) : BackendValues ; disposeData ( dataId , force ? ) : boolean ; write ( values , shape , dtype ) : DataId ; move ( dataId , values , shape , dtype , refCount ) : void ; memory ( ) : { unreliable : boolean ; } ; /** Returns number of data ids currently in the storage. */ numDataIds ( ) : number ; refCount ( dataId ) : number ; } /** Convenient class for storing tensor-related data. */ export class DataStorage < T > { private data = new WeakMap < DataId , T > ( ) ; private dataIdsCount = 0 ; constructor ( private backend , private dataMover ) { } get ( dataId ) { if ( ! this . data . has ( dataId ) ) { this . dataMover . moveData ( this . backend , dataId ) ; } return this . data . get ( dataId ) ; } set ( dataId , value ) { this . dataIdsCount ++ ; this . data . set ( dataId , value ) ; } has ( dataId ) { return this . data . has ( dataId ) ; } delete ( dataId ) { this . dataIdsCount -- ; return this . data . delete ( dataId ) ; } numDataIds ( ) { return this . dataIdsCount ; } } export interface DataMover { /**
     * To be called by backends whenever they see a dataId that they don't own.
     * Upon calling this method, the mover will fetch the tensor from another
     * backend and register it with the current active backend.
     */ moveData ( backend , dataId ) : void ; } export interface BackendTimer { timerAvailable ( ) : boolean ; time ( f ) : Promise < BackendTimingInfo > ; } /**
 * The interface that defines the kernels that should be implemented when
 * adding a new backend. New backends don't need to implement every one of the
 * methods, this can be done gradually (throw an error for unimplemented
 * methods).
 */ export class KernelBackend implements TensorStorage , Backend , BackendTimer { refCount ( dataId ) { return notYetImplemented ( 'refCount' ) ; } incRef ( dataId ) { return notYetImplemented ( 'incRef' ) ; } timerAvailable ( ) { return true ; } time ( f ) { return notYetImplemented ( 'time' ) ; } read ( dataId ) { return notYetImplemented ( 'read' ) ; } readSync ( dataId ) { return notYetImplemented ( 'readSync' ) ; } readToGPU ( dataId , options ? ) { return notYetImplemented ( 'readToGPU' ) ; } numDataIds ( ) { return notYetImplemented ( 'numDataIds' ) ; } disposeData ( dataId , force ? ) { return notYetImplemented ( 'disposeData' ) ; } write ( values , shape , dtype ) { return notYetImplemented ( 'write' ) ; } move ( dataId , values , shape , dtype , refCount ) { return notYetImplemented ( 'move' ) ; } memory ( ) { return notYetImplemented ( 'memory' ) ; } /** Returns the highest precision for floats in bits (e.g. 16 or 32) */ floatPrecision ( ) { return notYetImplemented ( 'floatPrecision' ) ; } /** Returns the smallest representable number.  */ epsilon ( ) { return this . floatPrecision ( ) === 32 ? EPSILON_FLOAT32 : EPSILON_FLOAT16 ; } dispose ( ) { return notYetImplemented ( 'dispose' ) ; } } function notYetImplemented ( kernelName ) { throw new Error ( `'${ kernelName }' not yet implemented or not found in the registry. ` + `This kernel may not be supported by the tfjs backend you have chosen` ) ; }