import * as Weights from "./Weights.js";

export { Params, Layer };

/**
 * Embedding (2D) layer parameters.
 */
class Params extends Weights.Params {

  /**
   * @param {number} channelMultiplier
   *   Every input channel will be expanded into so many embedding channels. The outChannels (output channel count)
   * is always depending on channelMultiplier and equal to ( inChannels * channelMultiplier ). If null, it will be
   * extracted from inputFloat32Array (i.e. by evolution).
   *
   * @return {boolean} Return false, if initialization failed.
   *
   * @override
   */
  init( inputFloat32Array, byteOffsetBegin, inChannels, channelMultiplier = null ) {

//!!! ...unfinished...
// inverted residual connection (by add or by concatenate) ? (dense net)
// squeeze-and-excitation ?
// Shuffled Grouped Pointwise Convolution ... ? (by tf.gather() ?)

    let parameterMap = new Map( [
      [ Weights.Params.Keys.inChannels,         inChannels ],
      [ Weights.Params.Keys.channelMultiplier,  channelMultiplier ],

      // For an embedding layer, its output channel count is always depeding on channelMultiplier.
      [ Weights.Params.Keys.outChannels,        Inifity ],
    ] );

    return super.init( inputFloat32Array, byteOffsetBegin, parameterMap );
  }

}


/**
 * An embedding layer contains one params (this.params) and inChannels embedding vocabulary tables.
 * Every input channel has one embedding vocabulary table. Every embedding vocabulary table has
 * vocabularyCountPerInputChannel vocabularies. Every vocabulary has channelMultiplier embedding channels.
 */
class Layer {

  /**
   * @param {Float32Array} inputFloat32Array
   *   A Float32Array whose values will be interpret as weights.
   *
   * @param {number} byteOffsetBegin
   *   The position to start to decode from the inputFloat32Array. This is relative to the inputFloat32Array.buffer
   * (not to the inputFloat32Array.byteOffset).
   *
   * @param {number} inChannels
   *   The input channel count.
   *
   * @param {number} vocabularyCountPerInputChannel
   *   Every input channel will have how many vocabularies. This is also vocabulary count per vocabulary table (because
   * every input channel has a vocabulary table). For an image data (R-G-B-A four channels), there will be 256
   * vocabularies per input channel because every channel is represented by one byte (8 bits) which has 2^8 = 256 kinds
   * of possible values.
   *
   * @param {number} channelMultiplier
   *   Every vocabulary will have how many embedding channels. Every input channel will be expanded into so many
   * embedding channels. The outChannels (output channel count) is always depending on channelMultiplier and equal
   * to ( inChannels * channelMultiplier ). If null, it will be extracted from inputFloat32Array (i.e. by evolution).
   *
   * @return {boolean} Return false, if initialization failed.
   */
  init( inputFloat32Array, byteOffsetBegin, inChannels, vocabularyCountPerInputChannel, channelMultiplier = null ) {

//!!! ...unfinished...
// inverted residual connection (by add or by concatenate) ? (dense net)
// squeeze-and-excitation ?
// Shuffled Grouped Pointwise Convolution ... ? (by tf.gather() ?)

    this.vocabularyCountPerInputChannel = vocabularyCountPerInputChannel;

    this.params = new Params();
    if ( !this.params.init( inputFloat32Array, byteOffsetBegin, inChannels, channelMultiplier ) )
      return false;

    {
      this.vocabularyTables = new Array( inChannels );

      let channelMultiplierInFact = this.params.channelMultiplier;
      let nextByteOffsetBegin = this.params.defaultByteOffsetEnd;
      for ( let i = 0; i < inChannels; ++i ) {

        this.vocabularyTables[ i ] = new Weights.Base();
        if ( !this.vocabularyTables[ i ].init(
               inputFloat32Array, nextByteOffsetBegin, null, 0, [vocabularyCountPerInputChannel, channelMultiplierInFact] ) )
          return false;

        nextByteOffsetBegin = this.vocabularyTables[ i ].defaultByteOffsetEnd;
      });
    }

    return true;
  }


  isValid() {
    if ( this.params )
      if ( this.vocabularyTables )
        if ( this.vocabularyTables[ this.params.inChannels - 1 ] )
          if ( this.vocabularyTables[ this.params.inChannels - 1 ].isValid() )  // Every vocabulary table is valid.
            return true;
    return false;
  }

  get byteOffsetBegin() { return this.params.defaultByteOffsetBegin; }
  get byteOffsetEnd()   { return this.vocabularyTables[ this.params.inChannels - 1 ].defaultByteOffsetEnd; }
}

@@ -20,16 +20,17 @@
  from %22.
+.
 /Weights
@@ -934,17 +934,16 @@
         
- 
 inChanne
@@ -994,17 +994,16 @@
 tiplier,
- 
  channel
@@ -1075,19 +1075,16 @@
 l count 
-is 
 always d
@@ -1086,20 +1086,19 @@
 ays depe
-ding
+nds
  on chan
@@ -1148,25 +1148,24 @@
 outChannels,
- 
        Inifi
@@ -3184,24 +3184,129 @@
 ather() ?)%0A%0A
+    this.params = this.vocabularyTables = null; // So that distinguishable if re-initialization failed.%0A%0A
     this.voc
@@ -3390,16 +3390,24 @@
 s = new 
+Weights.
 Params()
@@ -4183,32 +4183,69 @@
 ams )%0A      if (
+ this.params.isValid() )%0A        if (
  this.vocabulary
@@ -4249,24 +4249,26 @@
 aryTables )%0A
+  
         if (
@@ -4322,16 +4322,18 @@
 - 1 %5D )%0A
+  
         
@@ -4440,16 +4440,18 @@
  valid.%0A
+  
         

Update Embedding2D.js