<commit_before>/**
 * Created by ivar on 1.12.15.
 */

define([
	'angularAMD',
    'service/LexiconService',
    'service/ExtendedSearchModalService'
], function(angularAMD) {

	angularAMD.controller('main/ExtendedSearchCtrl', [ '$scope', '$rootScope', '$q', '$state', '$log', '$http', '$uibModal', '$uibModalInstance', 'wnwbApi',  'spinnerService', 'service/ExtendedSearchModalService', function($scope, $rootScope, $q, $state, $log, $http, $uibModal, $uibModalInstance, wnwbApi,  spinnerService, extendedSearchModalService) {

		$log.log('main/ExternalSearchCtrl');

        var SearchTypes = {
                synset      : 'Synset',
                lexentry    : 'Lexentry',
                sense       : 'Sense'

        };

        var Fields = {
                synset : {},
                sense : {},
                lexentry : {}
        };

        var Types = {
                I : {
                        regexp :'\\d+',
                        errorMessage : 'Only numeric values are allowed.'
                      },
                N : {
                        regexp :'\\d+',
                        errorMessage : 'Only numeric values are allowed.'
                      }
        };

        var SearchResult = null;

        var initSearchParams = function (hash, searchtype)
        {
            var fieldsDict = {};

            $scope.searchTitle[searchtype] = hash.name;
            parameters = hash.parameters;

            relations = {};

            //relations hash
            for (el in hash.relations) {
              relations[hash.relations[el][0]] = hash.relations[el][1];
            }

            //fields from array to hash
            for (el in parameters) {
                if (parameters[el].field) {
                    if (parameters[el].values=='[relations]') {
                          parameters[el].relations = relations;
                    }
                    else if (parameters[el].values && parameters[el].values!='*') {
                       var fixedValues =  (parameters[el].values).split(',');
                        parameters[el].fixedValues = fixedValues;
                    }
                   fieldsDict[parameters[el].field] =  parameters[el];
                }
            }
            $scope.Fields[searchtype] = fieldsDict;
        }

        var RootFilter = {
                type: 'group',
                boolOp: 'OR',
                items : [ {type:'group', boolOp:'AND', items:[]}]
                };

        $scope.filterTree = {};
        $scope.searchTitle = {};

        $scope.filterTree.synset = {};
        $scope.filterTree.sense = {};
        $scope.filterTree.lexentry = {};

        $scope.init = function (qAllResults) {
            if (!$scope.selectedSearchType) {
                $scope.selectedSearchType = 'synset';
                }

            $scope.Fields = Fields;

            initSearchParams(qAllResults[0][0], 'synset');
            initSearchParams(qAllResults[1][0], 'sense');
            initSearchParams(qAllResults[2][0], 'lexentry');

            $scope.TypeValidation = Types;
            $scope.searchTypes = SearchTypes;

            $scope.filterTree.synset = angular.copy(RootFilter);
            $scope.filterTree.sense = angular.copy(RootFilter);
            $scope.filterTree.lexentry = angular.copy(RootFilter);

        };

        $scope.changeSearchType = function(key) {
            $scope.selectedSearchType = key;
        }

        $scope.resetFilter = function(searchType) {
              $scope.filterTree[searchType] =  angular.copy(RootFilter);
        }

        $scope.cancel = function() {
              $uibModalInstance.close(null);
          }

        var evaluateFilterTree = function(items) {
            for (key in items) {
                if (items[key].type =='group') {
                    evaluateFilterTree(items[key].items);
                } else if (items[key].type=='field') {
                    console.debug('items', items[key].field.insertedValue);
                }
            }
            return true;
        }

        $scope.evaluateAndDoSearch = function () {
            if(evaluateFilterTree($scope.filterTree[$scope.selectedSearchType].items)) {
                $scope.doSearch();
            }
        }

        var constructFilter = function (element) {
            if (element.type=='group') {
                var Group = {type:'bool', op: (element.boolOp).toLowerCase(), exps : []};
                for (key in element.items) {
                   Group.exps.push(constructFilter(element.items[key]));
                }
                return Group;
            } else if (element.type=='field') {

                if (element.field.selectedOps == 'isempty')
                {
                    element.field.insertedValue = null;
                }
                return { type:'simple'
                        , field: element.field.field
                        , op : element.field.selectedOps
                        , value: element.field.insertedValue };

            }
        }

        $scope.doSearch = function() {
            var Filter = constructFilter($scope.filterTree[$scope.selectedSearchType]);
            //console.debug(Filter);
           /* var data = {filter:
                { type:"bool", op: "and", exps: [
                    { type:"simple", field:"date_created", op:">=", value:"2017-05-01T18:50:07.352550Z" },
                    { type:"simple", field:"lemma", op:"like", value:"omp" }
                ]
                }};*/
            var data = {filter:Filter};
            console.log('request data', data);
            // data = {filter:{}};
            spinnerService.show('searchLemmaSpinner');
            if ($scope.selectedSearchType == 'lexentry') {
                var resultPromise =  wnwbApi.LexicalEntrySearch.query(data).$promise;
            }
            else if ($scope.selectedSearchType == 'sense') {
                var resultPromise =  wnwbApi.SenseSearch.query(data).$promise;
            }
            else {
                var resultPromise =  wnwbApi.SynsetSearch.query(data).$promise;
            }

            //console.log('resultPromise', resultPromise);
            resultPromise.then(function(searchRes) {
                 	console.log("searchRes",searchRes);

                    //kui tylemus tyhi, j22 sellele lehele
                 	SearchResult = searchRes;
                    extendedSearchModalService.setSearchTitle($scope.searchTitle[$scope.selectedSearchType]);
                    extendedSearchModalService.setSearchType($scope.selectedSearchType);
                    extendedSearchModalService.setSearchResult(SearchResult);
                    $state.go('extsearch');
                    spinnerService.hide('searchLemmaSpinner');
                    $uibModalInstance.close(null);
            });
		};

        var LexentryFieldsPromise =  extendedSearchModalService.getLexentryFilterFieldsPromise();
        var SynsetFieldsPromise = extendedSearchModalService.getSynsetFilterFieldsPromise();
        var SenseFieldsFromise = extendedSearchModalService.getSenseFilterFieldsPromise();
        var PromiseList = [SynsetFieldsPromise, SenseFieldsFromise, LexentryFieldsPromise];

        $q.all(PromiseList).then(function(qAllResults) {
		  $scope.init(qAllResults);
        });

	} ]);
});<commit_msg>pagination added, limit etc<commit_after>/**
 * Created by ivar on 1.12.15.
 */

define([
	'angularAMD',
    'service/LexiconService',
    'service/ExtendedSearchModalService'
], function(angularAMD) {

	angularAMD.controller('main/ExtendedSearchCtrl', [ '$scope', '$rootScope', '$q', '$state', '$log', '$http', '$uibModal', '$uibModalInstance', 'wnwbApi',  'spinnerService', 'service/ExtendedSearchModalService', function($scope, $rootScope, $q, $state, $log, $http, $uibModal, $uibModalInstance, wnwbApi,  spinnerService, extendedSearchModalService) {

		$log.log('main/ExternalSearchCtrl');
        var SearchTypes = {
                synset      : 'Synset',
                lexentry    : 'Lexentry',
                sense       : 'Sense'

        };

        var Fields = {
                synset : {},
                sense : {},
                lexentry : {}
        };

        var Types = {
                I : {
                        regexp :'\\d+',
                        errorMessage : 'Only numeric values are allowed.'
                      },
                N : {
                        regexp :'\\d+',
                        errorMessage : 'Only numeric values are allowed.'
                      }
        };

        var SearchResult = null;

        var initSearchParams = function (hash, searchtype)
        {
            var fieldsDict = {};

            $scope.searchTitle[searchtype] = hash.name;
            parameters = hash.parameters;

            $scope.limit = extendedSearchModalService.getSearchLimit();
            relations = {};

            //relations hash
            for (el in hash.relations) {
              relations[hash.relations[el][0]] = hash.relations[el][1];
            }

            //fields from array to hash
            for (el in parameters) {
                if (parameters[el].field) {
                    if (parameters[el].values=='[relations]') {
                          parameters[el].relations = relations;
                    }
                    else if (parameters[el].values && parameters[el].values!='*') {
                       var fixedValues =  (parameters[el].values).split(',');
                        parameters[el].fixedValues = fixedValues;
                    }
                   fieldsDict[parameters[el].field] =  parameters[el];
                }
            }
            $scope.Fields[searchtype] = fieldsDict;
        }

        var RootFilter = extendedSearchModalService.getRootFilter();

        $scope.filterTree = {};
        $scope.searchTitle = {};

        $scope.filterTree.synset = {};
        $scope.filterTree.sense = {};
        $scope.filterTree.lexentry = {};

        $scope.init = function (qAllResults) {
            $scope.selectedSearchType = extendedSearchModalService.getSearchType();
            if (!$scope.selectedSearchType) {
                $scope.selectedSearchType = 'synset';
            }

            $scope.Fields = Fields;

            initSearchParams(qAllResults[0][0], 'synset');
            initSearchParams(qAllResults[1][0], 'sense');
            initSearchParams(qAllResults[2][0], 'lexentry');

            $scope.TypeValidation = Types;
            $scope.searchTypes = SearchTypes;
            $scope.limit = extendedSearchModalService.getSearchLimit();
            $scope.filterTree  = extendedSearchModalService.getFilterTree();
        };

        $scope.changeSearchType = function(key) {
            $scope.selectedSearchType = key;
        }

        $scope.resetFilter = function(searchType) {
              $scope.filterTree[searchType] =  extendedSearchModalService.getRootFilter();
        }

        $scope.cancel = function() {
             extendedSearchModalService.setFilterTree($scope.filterTree);
              $uibModalInstance.close(null);
          }

        var evaluateFilterTree = function(items) {
            for (key in items) {
                if (items[key].type =='group') {
                    evaluateFilterTree(items[key].items);
                } else if (items[key].type=='field') {
                    console.debug('items', items[key].field.insertedValue);
                }
            }
            return true;
        }

        $scope.evaluateAndDoSearch = function () {
            if(evaluateFilterTree($scope.filterTree[$scope.selectedSearchType].items)) {
                $scope.doSearch();
            }
        }

        var constructFilter = function (element) {
            if (element.type=='group') {
                var Group = {type:'bool', op: (element.boolOp).toLowerCase(), exps : []};
                for (key in element.items) {
                   Group.exps.push(constructFilter(element.items[key]));
                }
                return Group;
            } else if (element.type=='field') {

                if (element.field.selectedOps == 'isempty')
                {
                    element.field.insertedValue = null;
                }
                return { type:'simple'
                        , field: element.field.field
                        , op : element.field.selectedOps
                        , value: element.field.insertedValue };

            }
        }

        $scope.doSearch = function() {
            var Filter = constructFilter($scope.filterTree[$scope.selectedSearchType]);
            //console.log('request filter', Filter);
            spinnerService.show('searchLemmaSpinner');
            var resultPromise = extendedSearchModalService.getSearchResultPromise($scope.selectedSearchType, Filter, 0, $scope.limit);

            extendedSearchModalService.setFilterTree($scope.filterTree);
            //console.log('resultPromise', resultPromise);
            resultPromise.then(function(searchRes) {
                 	//console.log("searchRes",searchRes);
                 	SearchResult = searchRes;
                    extendedSearchModalService.setSearchTitle($scope.searchTitle[$scope.selectedSearchType]);
                    extendedSearchModalService.setSearchType($scope.selectedSearchType);
                    extendedSearchModalService.setSearchLimit(SearchResult.limit);
                    extendedSearchModalService.setSearchResult(SearchResult);
                    extendedSearchModalService.setSearchFilter(Filter);
                    extendedSearchModalService.setSearchLimit($scope.limit);
                    extendedSearchModalService.setFilterTree($scope.filterTree);
                    $state.go('extsearch');
                    spinnerService.hide('searchLemmaSpinner');
                    $uibModalInstance.close(null);
            });
		};

        var LexentryFieldsPromise =  extendedSearchModalService.getLexentryFilterFieldsPromise();
        var SynsetFieldsPromise = extendedSearchModalService.getSynsetFilterFieldsPromise();
        var SenseFieldsFromise = extendedSearchModalService.getSenseFilterFieldsPromise();
        var PromiseList = [SynsetFieldsPromise, SenseFieldsFromise, LexentryFieldsPromise];

        $q.all(PromiseList).then(function(qAllResults) {
		  $scope.init(qAllResults);
        });

	} ]);
});<|endoftext|>


<commit_before>export { channelCount1_pointwise1Before };
export { Pointwise_HigherHalfDifferent };
export { Depthwise_HigherHalfDifferent };
export { AvgMax_Or_ChannelMultiplier };
export { ConvBlock };

import { Int } from "./ValueDesc_Base.js";

/** Describe id, range, name of channelCount1_pointwise1Before.
 *
 * Convert number value into integer between [ -5, ( 10 * 1024 ) ] representing operation:
 *   - -5: ONE_INPUT_HALF_THROUGH
 *   - -4: ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1
 *   - -3: TWO_INPUTS_CONCAT_POINTWISE21_INPUT1
 *   - -2: ONE_INPUT_TWO_DEPTHWISE
 *   - -1: ONE_INPUT_ADD_TO_OUTPUT
 *   -  0: ONE_INPUT
 *   - [ 1, ( 10 * 1024 ) ]: TWO_INPUTS with the second input channel count between 1 and 10240 (inclusive). (without names defined.)
 */
class channelCount1_pointwise1Before extends Int {

  constructor() {
    super( -5, ( 10 * 1024 ), [
      "ONE_INPUT_HALF_THROUGH",                   // (-5) ShuffleNetV2_ByMobileNetV1's body/tail
      "ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1", // (-4) ShuffleNetV2_ByMobileNetV1's head
      "TWO_INPUTS_CONCAT_POINTWISE21_INPUT1",     // (-3) ShuffleNetV2's body/tail
      "ONE_INPUT_TWO_DEPTHWISE",                  // (-2) ShuffleNetV2's head (and ShuffleNetV2_ByPointwise22's head) (simplified)
      "ONE_INPUT_ADD_TO_OUTPUT",                  // (-1) MobileNetV2
      "ONE_INPUT",                                // ( 0) MobileNetV1 (General Pointwise1-Depthwise1-Pointwise2)

      // "TWO_INPUTS_1", "TWO_INPUTS_2", ..., "TWO_INPUTS_10240".
      //
      // ShuffleNetV2's (and ShuffleNetV2_ByPointwise22's) body/tail
      //
      // (2021/07/13 Remarked) Do not define these names because they will occupy too many memory.
      //
      //... [ ... new Array( 10 * 1024 ).keys() ].map( x => "TWO_INPUTS_" + ( x + 1 ) )
    ] );
  }

}

/** The only one ValueDesc.channelCount1_pointwise1Before instance. */
channelCount1_pointwise1Before.Singleton = new channelCount1_pointwise1Before;

/** Describe id, range, name of the processing mode of pointwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 4 ] representing:
 *   - 0: NONE
 *   - 1: HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH
 *   - 2: HIGHER_HALF_COPY_LOWER_HALF
 *   - 3: HIGHER_HALF_ANOTHER_POINTWISE
 *   - 4: HIGHER_HALF_PASS_THROUGH
 */
class Pointwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 4, [
      "NONE",                                                 // (0) (for normal poitwise convolution. no higher half different.)
      "HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH", // (1) (for pointwise1 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_COPY_LOWER_HALF",                          // (2) (for pointwise1 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_ANOTHER_POINTWISE",                        // (3) (for pointwise2 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_PASS_THROUGH",                             // (4) (for pointwise1/pointwise2 of ShuffleNetV2_ByMopbileNetV1's body/tail)
    ] );
  }

}

/** The only one ValueDesc.Pointwise_HigherHalfDifferent instance. */
Pointwise_HigherHalfDifferent.Singleton = new Pointwise_HigherHalfDifferent;

/** Describe id, range, name of the processing mode of depthwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 2 ] representing:
 *   - 0: NONE
 *   - 1: HIGHER_HALF_DEPTHWISE2
 *   - 2: HIGHER_HALF_PASS_THROUGH
 */
class Depthwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 2, [
      "NONE",                     // (0) (for normal depthwise convolution. no higher half different.)
      "HIGHER_HALF_DEPTHWISE2",   // (1) (for depthwise1 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_PASS_THROUGH", // (2) (for depthwise1 of ShuffleNetV2_ByMopbileNetV1's body/tail)
    ] );
  }

}

/** The only one ValueDesc.Depthwise_HigherHalfDifferent instance. */
Depthwise_HigherHalfDifferent.Singleton = new Depthwise_HigherHalfDifferent;

/** Describe depthwise operation's id, range, name.
 *
 * Convert number value into integer between [ -2, 32 ] representing depthwise operation:
 *   - -2: average pooling. (AVG)
 *   - -1: maximum pooling. (MAX)
 *   -  0: no depthwise operation. (NONE)
 *   - [ 1, 32 ]: depthwise convolution with channel multiplier between 1 and 32 (inclusive).
 */
class AvgMax_Or_ChannelMultiplier extends Int {

  constructor() {
    super( -2, 32, [ "AVG", "MAX", "NONE" ] );
  }

}

/** The only one ValueDesc.AvgMax_Or_ChannelMultiplier instance. */
AvgMax_Or_ChannelMultiplier.Singleton = new AvgMax_Or_ChannelMultiplier;

/** Describe id, range, name of ConvBlock (Convolution Block).
 *
 * Convert number value into integer between [ 0, 6 ] representing operation:
 *   - 0: MOBILE_NET_V1                             (i.e. no-add-inut-to-output)
 *   - 1: MOBILE_NET_V2_DOUBLE_POINTWISE1           (i.e. pointwise1 double, add-inut-to-output)
 *   - 2: MOBILE_NET_V2_QUADRUPLE_POINTWISE1        (i.e. pointwise1 quadruple, add-inut-to-output)
 *   - 3: SHUFFLE_NET_V2                            (i.e. by channel shuffler)
 *   - 4: SHUFFLE_NET_V2_BY_POINTWISE22             (i.e. by pointwise22)
 *   - 5: SHUFFLE_NET_V2_BY_MOBILE_NET_V1           (i.e. by integrated pointwise1, depthwise1, pointwise21)
 *   - 6: SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID (i.e. by depthwise1 with ( pad = "valid" )
 */
class ConvBlock extends Int {

  constructor() {
    super( 0, 6, [
      "MOBILE_NET_V1",                             // (0)
      "MOBILE_NET_V2_DOUBLE_POINTWISE1",           // (1)
      "MOBILE_NET_V2_QUADRUPLE_POINTWISE1",        // (2)
      "SHUFFLE_NET_V2",                            // (3)
      "SHUFFLE_NET_V2_BY_POINTWISE22",             // (4)
      "SHUFFLE_NET_V2_BY_MOBILE_NET_V1",           // (5)
      "SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID", // (6)
    ] );
  }

}

/** The only one ValueDesc.WhetherShuffleChannel instance. */
WhetherShuffleChannel.Singleton = new WhetherShuffleChannel;

<commit_msg>Update ValueDesc_Other.js<commit_after>export { channelCount1_pointwise1Before };
export { Pointwise_HigherHalfDifferent };
export { Depthwise_HigherHalfDifferent };
export { AvgMax_Or_ChannelMultiplier };
export { ConvBlockType };

import { Int } from "./ValueDesc_Base.js";

/** Describe id, range, name of channelCount1_pointwise1Before.
 *
 * Convert number value into integer between [ -5, ( 10 * 1024 ) ] representing operation:
 *   - -5: ONE_INPUT_HALF_THROUGH
 *   - -4: ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1
 *   - -3: TWO_INPUTS_CONCAT_POINTWISE21_INPUT1
 *   - -2: ONE_INPUT_TWO_DEPTHWISE
 *   - -1: ONE_INPUT_ADD_TO_OUTPUT
 *   -  0: ONE_INPUT
 *   - [ 1, ( 10 * 1024 ) ]: TWO_INPUTS with the second input channel count between 1 and 10240 (inclusive). (without names defined.)
 */
class channelCount1_pointwise1Before extends Int {

  constructor() {
    super( -5, ( 10 * 1024 ), [
      "ONE_INPUT_HALF_THROUGH",                   // (-5) ShuffleNetV2_ByMobileNetV1's body/tail
      "ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1", // (-4) ShuffleNetV2_ByMobileNetV1's head
      "TWO_INPUTS_CONCAT_POINTWISE21_INPUT1",     // (-3) ShuffleNetV2's body/tail
      "ONE_INPUT_TWO_DEPTHWISE",                  // (-2) ShuffleNetV2's head (and ShuffleNetV2_ByPointwise22's head) (simplified)
      "ONE_INPUT_ADD_TO_OUTPUT",                  // (-1) MobileNetV2
      "ONE_INPUT",                                // ( 0) MobileNetV1 (General Pointwise1-Depthwise1-Pointwise2)

      // "TWO_INPUTS_1", "TWO_INPUTS_2", ..., "TWO_INPUTS_10240".
      //
      // ShuffleNetV2's (and ShuffleNetV2_ByPointwise22's) body/tail
      //
      // (2021/07/13 Remarked) Do not define these names because they will occupy too many memory.
      //
      //... [ ... new Array( 10 * 1024 ).keys() ].map( x => "TWO_INPUTS_" + ( x + 1 ) )
    ] );
  }

}

/** The only one ValueDesc.channelCount1_pointwise1Before instance. */
channelCount1_pointwise1Before.Singleton = new channelCount1_pointwise1Before;

/** Describe id, range, name of the processing mode of pointwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 4 ] representing:
 *   - 0: NONE
 *   - 1: HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH
 *   - 2: HIGHER_HALF_COPY_LOWER_HALF
 *   - 3: HIGHER_HALF_ANOTHER_POINTWISE
 *   - 4: HIGHER_HALF_PASS_THROUGH
 */
class Pointwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 4, [
      "NONE",                                                 // (0) (for normal poitwise convolution. no higher half different.)
      "HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH", // (1) (for pointwise1 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_COPY_LOWER_HALF",                          // (2) (for pointwise1 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_ANOTHER_POINTWISE",                        // (3) (for pointwise2 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_PASS_THROUGH",                             // (4) (for pointwise1/pointwise2 of ShuffleNetV2_ByMopbileNetV1's body/tail)
    ] );
  }

}

/** The only one ValueDesc.Pointwise_HigherHalfDifferent instance. */
Pointwise_HigherHalfDifferent.Singleton = new Pointwise_HigherHalfDifferent;

/** Describe id, range, name of the processing mode of depthwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 2 ] representing:
 *   - 0: NONE
 *   - 1: HIGHER_HALF_DEPTHWISE2
 *   - 2: HIGHER_HALF_PASS_THROUGH
 */
class Depthwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 2, [
      "NONE",                     // (0) (for normal depthwise convolution. no higher half different.)
      "HIGHER_HALF_DEPTHWISE2",   // (1) (for depthwise1 of ShuffleNetV2_ByMopbileNetV1's head)
      "HIGHER_HALF_PASS_THROUGH", // (2) (for depthwise1 of ShuffleNetV2_ByMopbileNetV1's body/tail)
    ] );
  }

}

/** The only one ValueDesc.Depthwise_HigherHalfDifferent instance. */
Depthwise_HigherHalfDifferent.Singleton = new Depthwise_HigherHalfDifferent;

/** Describe depthwise operation's id, range, name.
 *
 * Convert number value into integer between [ -2, 32 ] representing depthwise operation:
 *   - -2: average pooling. (AVG)
 *   - -1: maximum pooling. (MAX)
 *   -  0: no depthwise operation. (NONE)
 *   - [ 1, 32 ]: depthwise convolution with channel multiplier between 1 and 32 (inclusive).
 */
class AvgMax_Or_ChannelMultiplier extends Int {

  constructor() {
    super( -2, 32, [ "AVG", "MAX", "NONE" ] );
  }

}

/** The only one ValueDesc.AvgMax_Or_ChannelMultiplier instance. */
AvgMax_Or_ChannelMultiplier.Singleton = new AvgMax_Or_ChannelMultiplier;

/** Describe id, range, name of ConvBlockType (Convolution Block Type).
 *
 * Convert number value into integer between [ 0, 6 ] representing operation:
 *   - 0: MOBILE_NET_V1                             (i.e. no-add-inut-to-output)
 *   - 1: MOBILE_NET_V2_DOUBLE_POINTWISE1           (i.e. pointwise1 double, add-inut-to-output)
 *   - 2: MOBILE_NET_V2_QUADRUPLE_POINTWISE1        (i.e. pointwise1 quadruple, add-inut-to-output)
 *   - 3: SHUFFLE_NET_V2                            (i.e. by channel shuffler)
 *   - 4: SHUFFLE_NET_V2_BY_POINTWISE22             (i.e. by pointwise22)
 *   - 5: SHUFFLE_NET_V2_BY_MOBILE_NET_V1           (i.e. by integrated pointwise1, depthwise1, pointwise21)
 *   - 6: SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID (i.e. by depthwise1 with ( pad = "valid" )
 */
class ConvBlockType extends Int {

  constructor() {
    super( 0, 6, [
      "MOBILE_NET_V1",                             // (0)
      "MOBILE_NET_V2_DOUBLE_POINTWISE1",           // (1)
      "MOBILE_NET_V2_QUADRUPLE_POINTWISE1",        // (2)
      "SHUFFLE_NET_V2",                            // (3)
      "SHUFFLE_NET_V2_BY_POINTWISE22",             // (4)
      "SHUFFLE_NET_V2_BY_MOBILE_NET_V1",           // (5)
      "SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID", // (6)
    ] );
  }

}

/** The only one ValueDesc.ConvBlockType instance. */
ConvBlockType.Singleton = new ConvBlockType;

<|endoftext|>


<commit_before>export { channelCount1_pointwise1Before };
export { Pointwise_HigherHalfDifferent };
export { Depthwise_HigherHalfDifferent };
export { AvgMax_Or_ChannelMultiplier };

import { Int } from "./ValueDesc_Base.js";

//!!! ...unfinished... (2022/06/12)
// Perhaps, integrated bOutput1Requested into this enumeration.

/** Describe id, range, name of channelCount1_pointwise1Before.
 *
 * Convert number value into integer between [ -5, ( 10 * 1024 ) ] representing operation:
 *   - -5: ONE_INPUT_HALF_THROUGH                   (ShuffleNetV2_ByMobileNetV1's body/tail)
 *   - -4: ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1 (ShuffleNetV2_ByMobileNetV1's head)
 *   - -3: TWO_INPUTS_CONCAT_POINTWISE20_INPUT1     (ShuffleNetV2's body/tail)
 *   - -2: ONE_INPUT_TWO_DEPTHWISE                  (ShuffleNetV2's head simplified with ( pointwise1ChannelCount >= 1 ) or
 *                                                   ShuffleNetV2_ByPointwise21's head with ( pointwise1ChannelCount >= 1 ))
 *
 *   - -1: ONE_INPUT_ADD_TO_OUTPUT                  (MobileNetV2)
 *   -  0: ONE_INPUT                                (General Pointwise1-Depthwise1-Pointwise2)
 *                                                  (MobileNetV1 or
 *                                                   MobileNetV2's head or
 *                                                   ShuffleNetV2's head simplified with ( pointwise1ChannelCount == 0 ) or
 *                                                   ShuffleNetV2_ByPointwise21's head with ( pointwise1ChannelCount == 0 ))
 *
 *   - [ 1, ( 10 * 1024 ) ]: TWO_INPUTS with the second input channel count between 1 and 10240 (inclusive). (without names defined.)
 *                                                  (ShuffleNetV2_ByPointwise21's body/tail)
 */
class channelCount1_pointwise1Before extends Int {

  constructor() {
    super( -5, ( 10 * 1024 ), [
      "ONE_INPUT_HALF_THROUGH",                   // (-5)
      "ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1", // (-4)
      "TWO_INPUTS_CONCAT_POINTWISE20_INPUT1",     // (-3)
      "ONE_INPUT_TWO_DEPTHWISE",                  // (-2)
      "ONE_INPUT_ADD_TO_OUTPUT",                  // (-1)
      "ONE_INPUT",                                // ( 0)

      // "TWO_INPUTS_1", "TWO_INPUTS_2", ..., "TWO_INPUTS_10240".
      //
      // ShuffleNetV2's (and ShuffleNetV2_ByPointwise21's) body/tail
      //
      // (2021/07/13 Remarked) Do not define these names because they will occupy too many memory.
      //
      //... [ ... new Array( 10 * 1024 ).keys() ].map( x => "TWO_INPUTS_" + ( x + 1 ) )
    ] );
  }

}

/** The only one ValueDesc.channelCount1_pointwise1Before instance. */
channelCount1_pointwise1Before.Singleton = new channelCount1_pointwise1Before;

/** Describe id, range, name of the processing mode of pointwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 4 ] representing:
 *   - 0: NONE                                                 (normal poitwise convolution. no higher half different.)
 *   - 1: HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH (pointwise1 of ShuffleNetV2_ByMopbileNetV1's head) ( pointwise1ChannelCount == 0 )
 *   - 2: HIGHER_HALF_COPY_LOWER_HALF                          (pointwise1 of ShuffleNetV2_ByMopbileNetV1's head) ( pointwise1ChannelCount > 0 )
 *   - 3: HIGHER_HALF_ANOTHER_POINTWISE                        (pointwise2 of ShuffleNetV2_ByMopbileNetV1's head)
 *   - 4: HIGHER_HALF_PASS_THROUGH                             (pointwise1/pointwise2 of ShuffleNetV2_ByMopbileNetV1's body/tail)
 */
class Pointwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 4, [
      "NONE",                                                 // (0)
      "HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH", // (1)
      "HIGHER_HALF_COPY_LOWER_HALF",                          // (2)
      "HIGHER_HALF_ANOTHER_POINTWISE",                        // (3)
      "HIGHER_HALF_PASS_THROUGH",                             // (4)
    ] );
  }

}

/** The only one ValueDesc.Pointwise_HigherHalfDifferent instance. */
Pointwise_HigherHalfDifferent.Singleton = new Pointwise_HigherHalfDifferent;

/** Describe id, range, name of the processing mode of depthwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 2 ] representing:
 *   - 0: NONE                     (normal depthwise convolution. no higher half different.)
 *   - 1: HIGHER_HALF_DEPTHWISE2   (depthwise1 of ShuffleNetV2_ByMopbileNetV1's head)
 *   - 2: HIGHER_HALF_PASS_THROUGH (depthwise1 of ShuffleNetV2_ByMopbileNetV1's body/tail)
 */
class Depthwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 2, [
      "NONE",                     // (0)
      "HIGHER_HALF_DEPTHWISE2",   // (1)
      "HIGHER_HALF_PASS_THROUGH", // (2)
    ] );
  }

}

/** The only one ValueDesc.Depthwise_HigherHalfDifferent instance. */
Depthwise_HigherHalfDifferent.Singleton = new Depthwise_HigherHalfDifferent;

/** Describe depthwise operation's id, range, name.
 *
 * Convert number value into integer between [ -2, 32 ] representing depthwise operation:
 *   - -2: average pooling. (AVG)
 *   - -1: maximum pooling. (MAX)
 *   -  0: no depthwise operation. (NONE)
 *   - [ 1, 32 ]: depthwise convolution with channel multiplier between 1 and 32 (inclusive).
 */
class AvgMax_Or_ChannelMultiplier extends Int {

  constructor() {
    super( -2, 32, [ "AVG", "MAX", "NONE" ] );
  }

}

/** The only one ValueDesc.AvgMax_Or_ChannelMultiplier instance. */
AvgMax_Or_ChannelMultiplier.Singleton = new AvgMax_Or_ChannelMultiplier;

<commit_msg>Update ValueDesc_Other.js<commit_after>export { channelCount1_pointwise1Before };
export { Pointwise_HigherHalfDifferent };
export { Depthwise_HigherHalfDifferent };
export { AvgMax_Or_ChannelMultiplier };

import { Int } from "./ValueDesc_Base.js";

//!!! ...unfinished... (2022/06/12)
// Perhaps, integrated bOutput1Requested into this enumeration.

/** Describe id, range, name of channelCount1_pointwise1Before.
 *
 * Convert number value into integer between [ -6, ( 10 * 1024 ) ] representing operation:
 *   - -6: SHUFFLE_NET_V2_HEAD                      (ShuffleNetV2's head)
 *   - -5: ONE_INPUT_HALF_THROUGH                   (ShuffleNetV2_ByMobileNetV1's body/tail)
 *   - -4: ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1 (ShuffleNetV2_ByMobileNetV1's head)
 *   - -3: TWO_INPUTS_CONCAT_POINTWISE20_INPUT1     (ShuffleNetV2's body/tail)
 *   - -2: SHUFFLE_NET_V2_BY_POINTWISE21_HEAD       (ShuffleNetV2_ByPointwise21's head with ( pointwise1ChannelCount >= 1 ))

//!!! (2022/06/14 Remarked)
// *   - -2: ONE_INPUT_TWO_DEPTHWISE                  (ShuffleNetV2's head simplified with ( pointwise1ChannelCount >= 1 ) or
// *                                                   ShuffleNetV2_ByPointwise21's head with ( pointwise1ChannelCount >= 1 ))

 *
 *   - -1: ONE_INPUT_ADD_TO_OUTPUT                  (MobileNetV2)
 *   -  0: ONE_INPUT                                (General Pointwise1-Depthwise1-Pointwise2)
 *                                                  (MobileNetV1 or
 *                                                   MobileNetV2's head or

//!!! (2022/06/14 Remarked)
// *                                                   ShuffleNetV2's head simplified with ( pointwise1ChannelCount == 0 ) or

 *                                                   ShuffleNetV2_ByPointwise21's head with ( pointwise1ChannelCount == 0 ))
 *
 *   - [ 1, ( 10 * 1024 ) ]: TWO_INPUTS with the second input channel count between 1 and 10240 (inclusive). (without names defined.)
 *                                                  (ShuffleNetV2_ByPointwise21's body/tail)
 */
class channelCount1_pointwise1Before extends Int {

  constructor() {
    super( -6, ( 10 * 1024 ), [
      "SHUFFLE_NET_V2_HEAD",                      // (-6)
      "ONE_INPUT_HALF_THROUGH",                   // (-5)
      "ONE_INPUT_HALF_THROUGH_EXCEPT_DEPTHWISE1", // (-4)
      "TWO_INPUTS_CONCAT_POINTWISE20_INPUT1",     // (-3)
      "SHUFFLE_NET_V2_BY_POINTWISE21_HEAD",       // (-2)
      "ONE_INPUT_ADD_TO_OUTPUT",                  // (-1)
      "ONE_INPUT",                                // ( 0)

      // "TWO_INPUTS_1", "TWO_INPUTS_2", ..., "TWO_INPUTS_10240".
      //
      // ShuffleNetV2's (and ShuffleNetV2_ByPointwise21's) body/tail
      //
      // (2021/07/13 Remarked) Do not define these names because they will occupy too many memory.
      //
      //... [ ... new Array( 10 * 1024 ).keys() ].map( x => "TWO_INPUTS_" + ( x + 1 ) )
    ] );
  }

}

/** The only one ValueDesc.channelCount1_pointwise1Before instance. */
channelCount1_pointwise1Before.Singleton = new channelCount1_pointwise1Before;

/** Describe id, range, name of the processing mode of pointwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 4 ] representing:
 *   - 0: NONE                                                 (normal poitwise convolution. no higher half different.)
 *   - 1: HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH (pointwise1 of ShuffleNetV2_ByMopbileNetV1's head) ( pointwise1ChannelCount == 0 )
 *   - 2: HIGHER_HALF_COPY_LOWER_HALF                          (pointwise1 of ShuffleNetV2_ByMopbileNetV1's head) ( pointwise1ChannelCount > 0 )
 *   - 3: HIGHER_HALF_ANOTHER_POINTWISE                        (pointwise2 of ShuffleNetV2_ByMopbileNetV1's head)
 *   - 4: HIGHER_HALF_PASS_THROUGH                             (pointwise1/pointwise2 of ShuffleNetV2_ByMopbileNetV1's body/tail)
 */
class Pointwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 4, [
      "NONE",                                                 // (0)
      "HIGHER_HALF_COPY_LOWER_HALF__LOWER_HALF_PASS_THROUGH", // (1)
      "HIGHER_HALF_COPY_LOWER_HALF",                          // (2)
      "HIGHER_HALF_ANOTHER_POINTWISE",                        // (3)
      "HIGHER_HALF_PASS_THROUGH",                             // (4)
    ] );
  }

}

/** The only one ValueDesc.Pointwise_HigherHalfDifferent instance. */
Pointwise_HigherHalfDifferent.Singleton = new Pointwise_HigherHalfDifferent;

/** Describe id, range, name of the processing mode of depthwise convolution's higher half channels.
 *
 * Convert number value into integer between [ 0, 2 ] representing:
 *   - 0: NONE                     (normal depthwise convolution. no higher half different.)
 *   - 1: HIGHER_HALF_DEPTHWISE2   (depthwise1 of ShuffleNetV2_ByMopbileNetV1's head)
 *   - 2: HIGHER_HALF_PASS_THROUGH (depthwise1 of ShuffleNetV2_ByMopbileNetV1's body/tail)
 */
class Depthwise_HigherHalfDifferent extends Int {

  constructor() {
    super( 0, 2, [
      "NONE",                     // (0)
      "HIGHER_HALF_DEPTHWISE2",   // (1)
      "HIGHER_HALF_PASS_THROUGH", // (2)
    ] );
  }

}

/** The only one ValueDesc.Depthwise_HigherHalfDifferent instance. */
Depthwise_HigherHalfDifferent.Singleton = new Depthwise_HigherHalfDifferent;

/** Describe depthwise operation's id, range, name.
 *
 * Convert number value into integer between [ -2, 32 ] representing depthwise operation:
 *   - -2: average pooling. (AVG)
 *   - -1: maximum pooling. (MAX)
 *   -  0: no depthwise operation. (NONE)
 *   - [ 1, 32 ]: depthwise convolution with channel multiplier between 1 and 32 (inclusive).
 */
class AvgMax_Or_ChannelMultiplier extends Int {

  constructor() {
    super( -2, 32, [ "AVG", "MAX", "NONE" ] );
  }

}

/** The only one ValueDesc.AvgMax_Or_ChannelMultiplier instance. */
AvgMax_Or_ChannelMultiplier.Singleton = new AvgMax_Or_ChannelMultiplier;

<|endoftext|>


<commit_before>// Ooui v1.0.0

var debug = false;

const nodes = {};
const hasText = {};

let socket = null;
let wasmSession = null;

function send (json) {
    if (debug) console.log ("Send", json);
    if (socket != null) {
        socket.send (json);
    }
    else if (wasmSession != null) {
        WebAssemblyApp.receiveMessagesJson (wasmSession, json);
    }
}

const mouseEvents = {
    click: true,
    dblclick: true,
    mousedown: true,
    mouseenter: true,
    mouseleave: true,
    mousemove: true,
    mouseout: true,
    mouseover: true,
    mouseup: true,
    wheel: true,
};

// Try to close the socket gracefully
window.onbeforeunload = function() {
    if (socket != null) {
        socket.close (1001, "Unloading page");
        socket = null;
        console.log ("Web socket closed");
    }
    return null;
}

function getSize () {
    return {
        height: window.innerHeight,
        width: window.innerWidth
    };
}

function setCookie (name, value, days) {
    var expires = "";
    if (days) {
        var date = new Date ();
        date.setTime(date.getTime () + (days*24*60*60*1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + (value || "")  + expires + "; path=/";
}

function saveSize (s) {
    setCookie ("oouiWindowWidth", s.width, 7);
    setCookie ("oouiWindowHeight", s.height, 7);
}

// Main entrypoint
function ooui (rootElementPath) {

    var initialSize = getSize ();
    saveSize (initialSize);

    var wsArgs = (rootElementPath.indexOf("?") >= 0 ? "&" : "?") +
        "w=" + initialSize.width + "&h=" + initialSize.height;

    var proto = "ws";
    if (location.protocol == "https:") {
        proto = "wss";
    }

    socket = new WebSocket (proto + "://" + document.location.host + rootElementPath + wsArgs, "ooui");

    socket.addEventListener ("open", function (event) {
        console.log ("Web socket opened");
    });

    socket.addEventListener ("error", function (event) {
        console.error ("Web socket error", event);
    });

    socket.addEventListener ("close", function (event) {
        console.error ("Web socket close", event);
    });

    socket.addEventListener("message", function (event) {
        const messages = JSON.parse (event.data);
        if (debug) console.log("Messages", messages);
        if (Array.isArray (messages)) {
            messages.forEach (function (m) {
                // console.log('Raw value from server', m.v);
                m.v = fixupValue (m.v);
                processMessage (m);
            });
        }
    });

    console.log("Web socket created");

    monitorSizeChanges (1000/10);
}

function oouiWasm (mainAsmName, mainNamespace, mainClassName, mainMethodName, assemblies)
{
    Module.entryPoint = { "a": mainAsmName, "n": mainNamespace, "t": mainClassName, "m": mainMethodName };
    Module.assemblies = assemblies;

    monitorSizeChanges (1000/30);
}

function monitorSizeChanges (millis)
{
    var resizeTimeout;
    function resizeThrottler() {
        if (!resizeTimeout) {
            resizeTimeout = setTimeout(function() {
                resizeTimeout = null;
                resizeHandler();
            }, millis);
        }
    }

    function resizeHandler() {
        const em = {
            m: "event",
            id: "window",
            k: "resize",
            v: getSize (),
        };
        saveSize (em.v);
        const ems = JSON.stringify (em);
        send (ems);
        if (debug) console.log ("Event", em);
    }

    window.addEventListener("resize", resizeThrottler, false);
}

function getNode (id) {
    switch (id) {
        case "window": return window;
        case "document": return document;
        case "document.body":
            const bodyNode = document.getElementById ("ooui-body");
            return bodyNode || document.body;
        default: return nodes[id];
    }
}

function getOrCreateElement (id, tagName) {
    var e = document.getElementById (id);
    if (e) {
        if (e.firstChild && e.firstChild.nodeType == Node.TEXT_NODE)
            hasText[e.id] = true;
        return e;
    }
    return document.createElement (tagName);
}

function msgCreate (m) {
    const id = m.id;
    const tagName = m.k;
    const node = tagName === "#text" ?
        document.createTextNode ("") :
        getOrCreateElement (id, tagName);
    if (tagName !== "#text")
        node.id = id;
    nodes[id] = node;
    if (debug) console.log ("Created node", node);
}

function msgSet (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    const parts = m.k.split(".");
    let o = node;
    for (let i = 0; i < parts.length - 1; i++) {
        o = o[parts[i]];
    }
    const lastPart = parts[parts.length - 1];
    const value = lastPart === "htmlFor" ? m.v.id : m.v;
    o[lastPart] = value;
    if (debug) console.log ("Set", node, parts, value);
}

function msgSetAttr (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    node.setAttribute(m.k, m.v);
    if (debug) console.log ("SetAttr", node, m.k, m.v);
}

function msgRemAttr (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    node.removeAttribute(m.k);
    if (debug) console.log ("RemAttr", node, m.k);
}

function msgCall (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    const target = node;
    if (m.k === "insertBefore" && m.v[0].nodeType == Node.TEXT_NODE && m.v[1] == null && hasText[id]) {
        // Text is already set so it clear it first
        if (target.firstChild)
            target.removeChild (target.firstChild);
        delete hasText[id];
    }
    const f = target[m.k];
    if (debug) console.log ("Call", node, f, m.v);
    const r = f.apply (target, m.v);
    if (typeof m.rid === 'string' || m.rid instanceof String) {
        nodes[m.rid] = r;
    }
}

function msgListen (m) {
    const node = getNode (m.id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    if (debug) console.log ("Listen", node, m.k);
    node.addEventListener(m.k, function (e) {
        const em = {
            m: "event",
            id: m.id,
            k: m.k,
        };
        if (m.k === "change" || m.k === "input") {
            em.v = (node.tagName === "INPUT" && node.type === "checkbox") ?
                node.checked :
                node.value;
        }
        else if (mouseEvents[m.k]) {
            em.v = {
                offsetX: e.offsetX,
                offsetY: e.offsetY,
            };
        }
        const ems = JSON.stringify (em);
        send (ems);
        if (debug) console.log ("Event", em);
        if (em.k === "submit")
            e.preventDefault ();
    });
}

function processMessage (m) {
    switch (m.m) {
        case "nop":
            break;
        case "create":
            msgCreate (m);
            break;
        case "set":
            msgSet (m);
            break;
        case "setAttr":
            msgSetAttr (m);
            break;
        case "remAttr":
            msgRemAttr (m);
            break;
        case "call":
            msgCall (m);
            break;
        case "listen":
            msgListen (m);
            break;
        default:
            console.error ("Unknown message type", m.m, m);
    }
}

function fixupValue (v) {
    if (Array.isArray (v)) {
        for (x in v) {
            v[x] = fixupValue (v[x]);
        }
        return v;
    }
    else if (typeof v === 'string' || v instanceof String) {
        if ((v.length > 1) && (v[0] === "\u2999")) {
            // console.log("V", v);
            return getNode (v);
        }
    }
    return v;
}

// == WASM Support ==

window["__oouiReceiveMessages"] = function (sessionId, messages)
{
    if (debug) console.log ("WebAssembly Receive", messages);
    if (wasmSession != null) {
        messages.forEach (function (m) {
            // console.log ('Raw value from server', m.v);
            m.v = fixupValue (m.v);
            processMessage (m);
        });
    }
};

var Module = {
    onRuntimeInitialized: function () {
        if (debug) console.log ("Done with WASM module instantiation.");

        Module.FS_createPath ("/", "managed", true, true);

        var pending = 0;
        this.assemblies.forEach (function(asm_name) {
            if (debug) console.log ("Loading", asm_name);
            ++pending;
            fetch ("managed/" + asm_name, { credentials: 'same-origin' }).then (function (response) {
                if (!response.ok)
                    throw "failed to load Assembly '" + asm_name + "'";
                return response['arrayBuffer']();
            }).then (function (blob) {
                var asm = new Uint8Array (blob);
                Module.FS_createDataFile ("managed/" + asm_name, null, asm, true, true, true);
                --pending;
                if (pending == 0)
                    Module.bclLoadingDone ();
            });
        });
    },

    bclLoadingDone: function () {
        if (debug) console.log ("Done loading the BCL.");
        MonoRuntime.init ();
    }
};

var MonoRuntime = {
    init: function () {
        this.load_runtime = Module.cwrap ('mono_wasm_load_runtime', null, ['string', 'number']);
        this.assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']);
        this.find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']);
        this.find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']);
        this.invoke_method = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number']);
        this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']);
        this.mono_string = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']);

        this.load_runtime ("managed", 1);

        if (debug) console.log ("Done initializing the runtime.");

        WebAssemblyApp.init ();
    },

    conv_string: function (mono_obj) {
        if (mono_obj == 0)
            return null;
        var raw = this.mono_string_get_utf8 (mono_obj);
        var res = Module.UTF8ToString (raw);
        Module._free (raw);

        return res;
    },

    call_method: function (method, this_arg, args) {
        var args_mem = Module._malloc (args.length * 4);
        var eh_throw = Module._malloc (4);
        for (var i = 0; i < args.length; ++i)
            Module.setValue (args_mem + i * 4, args [i], "i32");
        Module.setValue (eh_throw, 0, "i32");

        var res = this.invoke_method (method, this_arg, args_mem, eh_throw);

        var eh_res = Module.getValue (eh_throw, "i32");

        Module._free (args_mem);
        Module._free (eh_throw);

        if (eh_res != 0) {
            var msg = this.conv_string (res);
            throw new Error (msg);
        }

        return res;
    },
};

var WebAssemblyApp = {
    init: function () {
        this.loading = document.getElementById ("loading");

        this.findMethods ();

        this.runApp ("1", "2");

        this.loading.hidden = true;
    },

    runApp: function (a, b) {
        try {
            var sessionId = "main";
            if (!!this.ooui_DisableServer_method) {
                MonoRuntime.call_method (this.ooui_DisableServer_method, null, []);
            }
            MonoRuntime.call_method (this.main_method, null, [MonoRuntime.mono_string (a), MonoRuntime.mono_string (b)]);
            wasmSession = sessionId;
            if (!!this.ooui_StartWebAssemblySession_method) {
                var initialSize = getSize ();
                MonoRuntime.call_method (this.ooui_StartWebAssemblySession_method, null, [MonoRuntime.mono_string (sessionId), MonoRuntime.mono_string (""), MonoRuntime.mono_string (Math.round(initialSize.width) + " " + Math.round(initialSize.height))]);
            }
        } catch (e) {
            console.error(e);
        }
    },

    receiveMessagesJson: function (sessionId, json) {
        if (!!this.ooui_ReceiveWebAssemblySessionMessageJson_method) {
            MonoRuntime.call_method (this.ooui_ReceiveWebAssemblySessionMessageJson_method, null, [MonoRuntime.mono_string (sessionId), MonoRuntime.mono_string (json)]);
        }
    },

    findMethods: function () {
        this.main_module = MonoRuntime.assembly_load (Module.entryPoint.a);
        if (!this.main_module)
            throw "Could not find Main Module " + Module.entryPoint.a + ".dll";

        this.main_class = MonoRuntime.find_class (this.main_module, Module.entryPoint.n, Module.entryPoint.t)
        if (!this.main_class)
            throw "Could not find Program class in main module";

        this.main_method = MonoRuntime.find_method (this.main_class, Module.entryPoint.m, -1)
        if (!this.main_method)
            throw "Could not find Main method";

        this.ooui_module = MonoRuntime.assembly_load ("Ooui");
        if (!!this.ooui_module) {

            this.ooui_class = MonoRuntime.find_class (this.ooui_module, "Ooui", "UI");
            if (!this.ooui_class)
                throw "Could not find UI class in Ooui module";

            this.ooui_DisableServer_method = MonoRuntime.find_method (this.ooui_class, "DisableServer", -1);
            if (!this.ooui_DisableServer_method)
                throw "Could not find DisableServer method";

            this.ooui_StartWebAssemblySession_method = MonoRuntime.find_method (this.ooui_class, "StartWebAssemblySession", -1);
            if (!this.ooui_StartWebAssemblySession_method)
                throw "Could not find StartWebAssemblySession method";

            this.ooui_ReceiveWebAssemblySessionMessageJson_method = MonoRuntime.find_method (this.ooui_class, "ReceiveWebAssemblySessionMessageJson", -1);
            if (!this.ooui_ReceiveWebAssemblySessionMessageJson_method)
                throw "Could not find ReceiveWebAssemblySessionMessageJson method";
        }
    },
};

<commit_msg>Change default wasm path to /<commit_after>// Ooui v1.0.0

var debug = false;

const nodes = {};
const hasText = {};

let socket = null;
let wasmSession = null;

function send (json) {
    if (debug) console.log ("Send", json);
    if (socket != null) {
        socket.send (json);
    }
    else if (wasmSession != null) {
        WebAssemblyApp.receiveMessagesJson (wasmSession, json);
    }
}

const mouseEvents = {
    click: true,
    dblclick: true,
    mousedown: true,
    mouseenter: true,
    mouseleave: true,
    mousemove: true,
    mouseout: true,
    mouseover: true,
    mouseup: true,
    wheel: true,
};

// Try to close the socket gracefully
window.onbeforeunload = function() {
    if (socket != null) {
        socket.close (1001, "Unloading page");
        socket = null;
        console.log ("Web socket closed");
    }
    return null;
}

function getSize () {
    return {
        height: window.innerHeight,
        width: window.innerWidth
    };
}

function setCookie (name, value, days) {
    var expires = "";
    if (days) {
        var date = new Date ();
        date.setTime(date.getTime () + (days*24*60*60*1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + (value || "")  + expires + "; path=/";
}

function saveSize (s) {
    setCookie ("oouiWindowWidth", s.width, 7);
    setCookie ("oouiWindowHeight", s.height, 7);
}

// Main entrypoint
function ooui (rootElementPath) {

    var initialSize = getSize ();
    saveSize (initialSize);

    var wsArgs = (rootElementPath.indexOf("?") >= 0 ? "&" : "?") +
        "w=" + initialSize.width + "&h=" + initialSize.height;

    var proto = "ws";
    if (location.protocol == "https:") {
        proto = "wss";
    }

    socket = new WebSocket (proto + "://" + document.location.host + rootElementPath + wsArgs, "ooui");

    socket.addEventListener ("open", function (event) {
        console.log ("Web socket opened");
    });

    socket.addEventListener ("error", function (event) {
        console.error ("Web socket error", event);
    });

    socket.addEventListener ("close", function (event) {
        console.error ("Web socket close", event);
    });

    socket.addEventListener("message", function (event) {
        const messages = JSON.parse (event.data);
        if (debug) console.log("Messages", messages);
        if (Array.isArray (messages)) {
            messages.forEach (function (m) {
                // console.log('Raw value from server', m.v);
                m.v = fixupValue (m.v);
                processMessage (m);
            });
        }
    });

    console.log("Web socket created");

    monitorSizeChanges (1000/10);
}

function oouiWasm (mainAsmName, mainNamespace, mainClassName, mainMethodName, assemblies)
{
    Module.entryPoint = { "a": mainAsmName, "n": mainNamespace, "t": mainClassName, "m": mainMethodName };
    Module.assemblies = assemblies;

    monitorSizeChanges (1000/30);
}

function monitorSizeChanges (millis)
{
    var resizeTimeout;
    function resizeThrottler() {
        if (!resizeTimeout) {
            resizeTimeout = setTimeout(function() {
                resizeTimeout = null;
                resizeHandler();
            }, millis);
        }
    }

    function resizeHandler() {
        const em = {
            m: "event",
            id: "window",
            k: "resize",
            v: getSize (),
        };
        saveSize (em.v);
        const ems = JSON.stringify (em);
        send (ems);
        if (debug) console.log ("Event", em);
    }

    window.addEventListener("resize", resizeThrottler, false);
}

function getNode (id) {
    switch (id) {
        case "window": return window;
        case "document": return document;
        case "document.body":
            const bodyNode = document.getElementById ("ooui-body");
            return bodyNode || document.body;
        default: return nodes[id];
    }
}

function getOrCreateElement (id, tagName) {
    var e = document.getElementById (id);
    if (e) {
        if (e.firstChild && e.firstChild.nodeType == Node.TEXT_NODE)
            hasText[e.id] = true;
        return e;
    }
    return document.createElement (tagName);
}

function msgCreate (m) {
    const id = m.id;
    const tagName = m.k;
    const node = tagName === "#text" ?
        document.createTextNode ("") :
        getOrCreateElement (id, tagName);
    if (tagName !== "#text")
        node.id = id;
    nodes[id] = node;
    if (debug) console.log ("Created node", node);
}

function msgSet (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    const parts = m.k.split(".");
    let o = node;
    for (let i = 0; i < parts.length - 1; i++) {
        o = o[parts[i]];
    }
    const lastPart = parts[parts.length - 1];
    const value = lastPart === "htmlFor" ? m.v.id : m.v;
    o[lastPart] = value;
    if (debug) console.log ("Set", node, parts, value);
}

function msgSetAttr (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    node.setAttribute(m.k, m.v);
    if (debug) console.log ("SetAttr", node, m.k, m.v);
}

function msgRemAttr (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    node.removeAttribute(m.k);
    if (debug) console.log ("RemAttr", node, m.k);
}

function msgCall (m) {
    const id = m.id;
    const node = getNode (id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    const target = node;
    if (m.k === "insertBefore" && m.v[0].nodeType == Node.TEXT_NODE && m.v[1] == null && hasText[id]) {
        // Text is already set so it clear it first
        if (target.firstChild)
            target.removeChild (target.firstChild);
        delete hasText[id];
    }
    const f = target[m.k];
    if (debug) console.log ("Call", node, f, m.v);
    const r = f.apply (target, m.v);
    if (typeof m.rid === 'string' || m.rid instanceof String) {
        nodes[m.rid] = r;
    }
}

function msgListen (m) {
    const node = getNode (m.id);
    if (!node) {
        console.error ("Unknown node id", m);
        return;
    }
    if (debug) console.log ("Listen", node, m.k);
    node.addEventListener(m.k, function (e) {
        const em = {
            m: "event",
            id: m.id,
            k: m.k,
        };
        if (m.k === "change" || m.k === "input") {
            em.v = (node.tagName === "INPUT" && node.type === "checkbox") ?
                node.checked :
                node.value;
        }
        else if (mouseEvents[m.k]) {
            em.v = {
                offsetX: e.offsetX,
                offsetY: e.offsetY,
            };
        }
        const ems = JSON.stringify (em);
        send (ems);
        if (debug) console.log ("Event", em);
        if (em.k === "submit")
            e.preventDefault ();
    });
}

function processMessage (m) {
    switch (m.m) {
        case "nop":
            break;
        case "create":
            msgCreate (m);
            break;
        case "set":
            msgSet (m);
            break;
        case "setAttr":
            msgSetAttr (m);
            break;
        case "remAttr":
            msgRemAttr (m);
            break;
        case "call":
            msgCall (m);
            break;
        case "listen":
            msgListen (m);
            break;
        default:
            console.error ("Unknown message type", m.m, m);
    }
}

function fixupValue (v) {
    if (Array.isArray (v)) {
        for (x in v) {
            v[x] = fixupValue (v[x]);
        }
        return v;
    }
    else if (typeof v === 'string' || v instanceof String) {
        if ((v.length > 1) && (v[0] === "\u2999")) {
            // console.log("V", v);
            return getNode (v);
        }
    }
    return v;
}

// == WASM Support ==

window["__oouiReceiveMessages"] = function (sessionId, messages)
{
    if (debug) console.log ("WebAssembly Receive", messages);
    if (wasmSession != null) {
        messages.forEach (function (m) {
            // console.log ('Raw value from server', m.v);
            m.v = fixupValue (m.v);
            processMessage (m);
        });
    }
};

var Module = {
    onRuntimeInitialized: function () {
        if (debug) console.log ("Done with WASM module instantiation.");

        Module.FS_createPath ("/", "managed", true, true);

        var pending = 0;
        this.assemblies.forEach (function(asm_name) {
            if (debug) console.log ("Loading", asm_name);
            ++pending;
            fetch ("managed/" + asm_name, { credentials: 'same-origin' }).then (function (response) {
                if (!response.ok)
                    throw "failed to load Assembly '" + asm_name + "'";
                return response['arrayBuffer']();
            }).then (function (blob) {
                var asm = new Uint8Array (blob);
                Module.FS_createDataFile ("managed/" + asm_name, null, asm, true, true, true);
                --pending;
                if (pending == 0)
                    Module.bclLoadingDone ();
            });
        });
    },

    bclLoadingDone: function () {
        if (debug) console.log ("Done loading the BCL.");
        MonoRuntime.init ();
    }
};

var MonoRuntime = {
    init: function () {
        this.load_runtime = Module.cwrap ('mono_wasm_load_runtime', null, ['string', 'number']);
        this.assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']);
        this.find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']);
        this.find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']);
        this.invoke_method = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number']);
        this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']);
        this.mono_string = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']);

        this.load_runtime ("managed", 1);

        if (debug) console.log ("Done initializing the runtime.");

        WebAssemblyApp.init ();
    },

    conv_string: function (mono_obj) {
        if (mono_obj == 0)
            return null;
        var raw = this.mono_string_get_utf8 (mono_obj);
        var res = Module.UTF8ToString (raw);
        Module._free (raw);

        return res;
    },

    call_method: function (method, this_arg, args) {
        var args_mem = Module._malloc (args.length * 4);
        var eh_throw = Module._malloc (4);
        for (var i = 0; i < args.length; ++i)
            Module.setValue (args_mem + i * 4, args [i], "i32");
        Module.setValue (eh_throw, 0, "i32");

        var res = this.invoke_method (method, this_arg, args_mem, eh_throw);

        var eh_res = Module.getValue (eh_throw, "i32");

        Module._free (args_mem);
        Module._free (eh_throw);

        if (eh_res != 0) {
            var msg = this.conv_string (res);
            throw new Error (msg);
        }

        return res;
    },
};

var WebAssemblyApp = {
    init: function () {
        this.loading = document.getElementById ("loading");

        this.findMethods ();

        this.runApp ("1", "2");

        this.loading.hidden = true;
    },

    runApp: function (a, b) {
        try {
            var sessionId = "main";
            if (!!this.ooui_DisableServer_method) {
                MonoRuntime.call_method (this.ooui_DisableServer_method, null, []);
            }
            MonoRuntime.call_method (this.main_method, null, [MonoRuntime.mono_string (a), MonoRuntime.mono_string (b)]);
            wasmSession = sessionId;
            if (!!this.ooui_StartWebAssemblySession_method) {
                var initialSize = getSize ();
                MonoRuntime.call_method (this.ooui_StartWebAssemblySession_method, null, [MonoRuntime.mono_string (sessionId), MonoRuntime.mono_string ("/"), MonoRuntime.mono_string (Math.round(initialSize.width) + " " + Math.round(initialSize.height))]);
            }
        } catch (e) {
            console.error(e);
        }
    },

    receiveMessagesJson: function (sessionId, json) {
        if (!!this.ooui_ReceiveWebAssemblySessionMessageJson_method) {
            MonoRuntime.call_method (this.ooui_ReceiveWebAssemblySessionMessageJson_method, null, [MonoRuntime.mono_string (sessionId), MonoRuntime.mono_string (json)]);
        }
    },

    findMethods: function () {
        this.main_module = MonoRuntime.assembly_load (Module.entryPoint.a);
        if (!this.main_module)
            throw "Could not find Main Module " + Module.entryPoint.a + ".dll";

        this.main_class = MonoRuntime.find_class (this.main_module, Module.entryPoint.n, Module.entryPoint.t)
        if (!this.main_class)
            throw "Could not find Program class in main module";

        this.main_method = MonoRuntime.find_method (this.main_class, Module.entryPoint.m, -1)
        if (!this.main_method)
            throw "Could not find Main method";

        this.ooui_module = MonoRuntime.assembly_load ("Ooui");
        if (!!this.ooui_module) {

            this.ooui_class = MonoRuntime.find_class (this.ooui_module, "Ooui", "UI");
            if (!this.ooui_class)
                throw "Could not find UI class in Ooui module";

            this.ooui_DisableServer_method = MonoRuntime.find_method (this.ooui_class, "DisableServer", -1);
            if (!this.ooui_DisableServer_method)
                throw "Could not find DisableServer method";

            this.ooui_StartWebAssemblySession_method = MonoRuntime.find_method (this.ooui_class, "StartWebAssemblySession", -1);
            if (!this.ooui_StartWebAssemblySession_method)
                throw "Could not find StartWebAssemblySession method";

            this.ooui_ReceiveWebAssemblySessionMessageJson_method = MonoRuntime.find_method (this.ooui_class, "ReceiveWebAssemblySessionMessageJson", -1);
            if (!this.ooui_ReceiveWebAssemblySessionMessageJson_method)
                throw "Could not find ReceiveWebAssemblySessionMessageJson method";
        }
    },
};

<|endoftext|>


<commit_before>import * as TensorTools from "../util/TensorTools.js";

/**
 * Test different resize implementation for CNN.
 *
 * @see {@link https://jsperf.com/colorfulcakechen-cnn-height-width-resize}
 */

/**
 * A test set.
 */
class HeightWidthDepth {

  /**
   * @param {number} height      image height
   * @param {number} width       image width
   * @param {number} depth       image channel count
   */
  constructor( height, width, depth ) {

    this.height = height;
    this.width = width;
    this.depth = depth;

    this.valueCount = height * width * depth;

    //this.concatenatedShape = [ height, width, depth ];
    this.targetSize = [ ( height / 2 ), ( width / 2 ) ];

    this.dataTensor3d = tf.tidy( () => {
      let dataTensor1d = tf.linspace( 0, this.valueCount - 1, this.valueCount );
      let dataTensor3d = dataTensor1d.reshape( [ height, width, depth ] );
      return dataTensor3d;
    });

    this.depthwiseConvFilters = tf.tidy( () => {
      let filterHeight =      this.targetSize[ 0 ] + 1;
      let filterWidth =       this.targetSize[ 1 ] + 1;
      let inChannels =        depth;
      let channelMultiplier = 1;
      let filtersShape = [ filterHeight, filterWidth, inChannels, channelMultiplier ];

      let filterSize = tf.util.sizeFromShape( filtersShape );
      let filtersTensor1d = tf.range( 0, filterSize, 1 );
      let filtersTensor4d = filtersTensor1d.reshape( filtersShape );
      return filtersTensor4d;
    });
  }

  disposeTensors() {
    if ( this.dataTensor3d ) {
      tf.dispose( this.dataTensor3d );
      this.dataTensor3d = null;
    }

    if ( this.depthwiseConvFilters ) {
      tf.dispose( this.depthwiseConvFilters );
      this.depthwiseConvFilters = null;
    }
  }

  // Test max-pool
  test_MaxPool() {
    tf.tidy( () => {
      this.dataTensor3d.maxPool( 2, 1, "valid" );
    });
  }

  // Test avg-pool
  test_AvgPool() {
    tf.tidy( () => {
      this.dataTensor3d.avgPool( 2, 1, "valid" );
    });
  }

  // Test depthwise convolution (2D)
  test_DepthwiseConv2d() {
    tf.tidy( () => {
      this.dataTensor3d.depthwiseConv2D( this.depthwiseConvFilters, 1, "valid" );
    });
  }

  // Test rsize-nearest-neighbor
  test_ResizeNearestNeighbor() {
    tf.tidy( () => {
      this.dataTensor3d.resizeNearestNeighbor( this.targetSize, true );
    });
  }

  // Test rsize-bilinear
  test_ResizeBilinear() {
    tf.tidy( () => {
      this.dataTensor3d.resizeBilinear( this.targetSize, true );
    });
  }

  // Testing whether the results of different implementation are the same.
  testResultSame() {
    tf.tidy( () => {
      let quarterTensor1 = this.dataTensor3d.maxPool( 2, 1, "valid" );
      let quarterTensor2 = this.dataTensor3d.avgPool( 2, 1, "valid" );
      let quarterTensor3 = this.dataTensor3d.depthwiseConv2D( this.depthwiseConvFilters, 1, "valid" );
      let quarterTensor4 = this.dataTensor3d.resizeNearestNeighbor( this.targetSize, true );
      let quarterTensor5 = this.dataTensor3d.resizeBilinear( this.targetSize, true );

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor1.shape, quarterTensor2.shape ),
        `MaxPool() != AvgPool()`);

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor2.shape, quarterTensor3.shape ),
        `AvgPool() != DepthwiseConv2d()`);

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor3.shape, quarterTensor4.shape ),
        `DepthwiseConv2d() != ResizeNearestNeighbor()`);

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor4.shape, quarterTensor5.shape ),
        `ResizeNearestNeighbor() != ResizeBilinear()`);
    });
  }

}

globalThis.testSet_110x110x24 = new HeightWidthDepth( 110, 110, 24 ); // height, width, depth
<commit_msg>Update jsPerf_CNNHeightWidthResize.js<commit_after>import * as TensorTools from "../util/TensorTools.js";

/**
 * Test different resize implementation for CNN.
 *
 * @see {@link https://jsperf.com/colorfulcakechen-cnn-height-width-resize}
 */

/**
 * A test set.
 */
class HeightWidthDepth {

  /**
   * @param {number} height      image height
   * @param {number} width       image width
   * @param {number} depth       image channel count
   */
  constructor( height, width, depth ) {

    this.height = height;
    this.width = width;
    this.depth = depth;

    this.valueCount = height * width * depth;

    //this.concatenatedShape = [ height, width, depth ];
    this.targetSize = [ ( height / 2 ), ( width / 2 ) ];

    let filterHeight =      this.targetSize[ 0 ] + 1;
    let filterWidth =       this.targetSize[ 1 ] + 1;
    this.filterHeightWidth = [ filterHeight, filterWidth ];

    this.dataTensor3d = tf.tidy( () => {
      let dataTensor1d = tf.linspace( 0, this.valueCount - 1, this.valueCount );
      let dataTensor3d = dataTensor1d.reshape( [ height, width, depth ] );
      return dataTensor3d;
    });

    this.depthwiseConvFilters = tf.tidy( () => {
      let inChannels =        depth;
      let channelMultiplier = 1;
      let filtersShape = [ filterHeight, filterWidth, inChannels, channelMultiplier ];
      let filtersValueCount = tf.util.sizeFromShape( filtersShape );

      let filtersTensor1d = tf.range( 0, filtersValueCount, 1 );
      let filtersTensor4d = filtersTensor1d.reshape( filtersShape );
      return filtersTensor4d;
    });
  }

  disposeTensors() {
    if ( this.dataTensor3d ) {
      tf.dispose( this.dataTensor3d );
      this.dataTensor3d = null;
    }

    if ( this.depthwiseConvFilters ) {
      tf.dispose( this.depthwiseConvFilters );
      this.depthwiseConvFilters = null;
    }
  }

  // Test max-pool
  test_MaxPool() {
    tf.tidy( () => {
      this.dataTensor3d.maxPool( this.filterHeightWidth, 1, "valid" );
    });
  }

  // Test avg-pool
  test_AvgPool() {
    tf.tidy( () => {
      this.dataTensor3d.avgPool( this.filterHeightWidth, 1, "valid" );
    });
  }

  // Test depthwise convolution (2D)
  test_DepthwiseConv2d() {
    tf.tidy( () => {
      this.dataTensor3d.depthwiseConv2D( this.depthwiseConvFilters, 1, "valid" );
    });
  }

  // Test rsize-nearest-neighbor
  test_ResizeNearestNeighbor() {
    tf.tidy( () => {
      this.dataTensor3d.resizeNearestNeighbor( this.targetSize, true );
    });
  }

  // Test rsize-bilinear
  test_ResizeBilinear() {
    tf.tidy( () => {
      this.dataTensor3d.resizeBilinear( this.targetSize, true );
    });
  }

  // Testing whether the results of different implementation are the same.
  testResultSame() {
    tf.tidy( () => {
      let quarterTensor1 = this.dataTensor3d.maxPool( this.filterHeightWidth, 1, "valid" );
      let quarterTensor2 = this.dataTensor3d.avgPool( this.filterHeightWidth, 1, "valid" );
      let quarterTensor3 = this.dataTensor3d.depthwiseConv2D( this.depthwiseConvFilters, 1, "valid" );
      let quarterTensor4 = this.dataTensor3d.resizeNearestNeighbor( this.targetSize, true );
      let quarterTensor5 = this.dataTensor3d.resizeBilinear( this.targetSize, true );

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor1.shape, quarterTensor2.shape ),
        `MaxPool() != AvgPool()`);

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor2.shape, quarterTensor3.shape ),
        `AvgPool() != DepthwiseConv2d()`);

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor3.shape, quarterTensor4.shape ),
        `DepthwiseConv2d() != ResizeNearestNeighbor()`);

      tf.util.assert(
        tf.util.arraysEqual( quarterTensor4.shape, quarterTensor5.shape ),
        `ResizeNearestNeighbor() != ResizeBilinear()`);
    });
  }

}

globalThis.testSet_110x110x24 = new HeightWidthDepth( 110, 110, 24 ); // height, width, depth
<|endoftext|>


<commit_before>export { AsyncWorker_Proxy as Proxy };

import * as Pool from "../Pool.js";
import * as Recyclable from "../Recyclable.js";
import { PromiseResolveReject } from "./AsyncWorker_PromiseResolveReject.js";
import { processingId_Resulter_Map } from "./AsyncWorker_processingId_Resulter_Map.js";
import { Resulter } from "./AsyncWorker_Resulter.js";

/**
 * Hold the worker and its related promise map. It is a wrapper of a neural network
 * web worker for handling and communicating easily.
 *
 * @member {string} workerModuleURL
 *   The (absolute) javascript module URL which will be loaded (asynchronously) by
 * worker body (stub).
 *
 * @member {Worker} worker
 *   The worker.
 *
 * @member {number} processingId_next
 *   The next processing id. Zero means no command has been sent. Every
 * postCommand_and_expectResult() call will use a new id.
 *
 * @member {processingId_Resulter_Map} the_processingId_Resulter_Map
 *   Every worker has a result pending promise map. The key of the map is processing
 * id. The value of the map is a AsyncWorker.Resulter.
 *
 */
class AsyncWorker_Proxy extends Recyclable.Root {

  /**
   * Used as default AsyncWorker.Proxy provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "AsyncWorker.Proxy.Pool",
    AsyncWorker_Proxy, AsyncWorker_Proxy.setAsConstructor );

  /** */
  constructor( workerModuleURL ) {
    super();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
  }

  /** @override */
  static setAsConstructor() {
    super.setAsConstructor();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
    return this;
  }

  /** @override */
  static setAsConstructor_self( workerModuleURL ) {

    // Q: What if processingId become too large (e.g. infinity)?
    // A: Because Number.MAX_SAFE_INTEGER is pretty large (at least, 2 ** 52 ),
    //    it is not so easy to become out of bounds.
    //
    this.processingId_next = 0;

    if ( this.the_processingId_Resulter_Map )
      this.the_processingId_Resulter_Map.clear();
    else
      this.the_processingId_Resulter_Map = new processingId_Resulter_Map();

    AsyncWorker_Proxy.createWorker_byModuleURL.call( this, workerModuleURL );
  }

  /** @override */
  disposeResources() {

    if ( this.worker ) {
      // Note: No processingId, because this command needs not return value.
      this.postCommandArgs( [ "disposeResources" ] );
      this.worker = null;
    }

    this.workerOptions = undefined;
    this.workerURL = undefined;
    this.workerModuleURL = undefined;

    this.the_processingId_Resulter_Map.clear();

    this.processingId_next = undefined;

    super.disposeResources();
  }

  /**
   * @param {AsyncWorker_Proxy} this
   *   The worker proxy.
   */
  static createWorker_byModuleURL( workerModuleURL ) {
    this.workerModuleURL = workerModuleURL;

    let workerDataURI
      = AsyncWorker_Proxy.create_WorkerBodyStub_Codes_DataURI( workerModuleURL );

    this.workerURL = workerDataURI;

    // Q: Why not use "module" type worker?
    // A: A "module" type worker can not use importScripts() to load global library.
    //    (e.g. tensorflow.js)
    //
    // On the other hand, a "classic" type worker can use both importScripts() and
    // import() to load global library and module.
    //
    this.workerOptions = null;

    this.worker = new Worker( this.workerURL, this.workerOptions );

    // Register callback from the web worker.
    this.worker.onmessage
      = AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body.bind( this );
  }

  /**
   * Create a data URI representing the main (i.e. body) javascript file of web worker.
   * It is viewed as a classic javascript file (i.e. not an importable module). But
   * it will load specified workerModuleURL as a module.
   *
   * In module (non-classic) web worker, static import is available. But the function
   * importScripts() will not be avbailable. For solving this problem, using
   * classic (non-module) web worker so that some global library (e.g. tensorflow.js)
   * can be loaded by importScripts(). And use dynamic import() to load ourselves
   * modules because import() can be used in classic (non-module) script.
   *
   * @param {string} workerModuleURL
   *   An (absolute) URL to a javascript module file. It will be imported
   * (asynchronously) by this generated classic javascript file (as a dataURI).
   */
  static create_WorkerBodyStub_Codes_DataURI( workerModuleURL ) {

    // The codes do the following:
    //
    //   - Import the specified module URL.
    //   - Create a temporary message queue.
    //   - Collect all messages before
    //       AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body() be registered
    //       as message handler.
    //
    let codes = ``
      + `import( "${workerModuleURL}" );\n`
      + `AsyncWorker_Body_temporaryMessageQueue = [];\n`
      + `onmessage = ( e ) => {\n`
      // + `  console.log( "Hello" );\n`
      // + `  console.log( e );\n`
      + `  AsyncWorker_Body_temporaryMessageQueue.push( e );\n`
      + `};\n`
      ;

    let workerDataURI
      = AsyncWorker_Proxy.createDataURI_byStringASCII( "text/javascript", codes );

    return workerDataURI;
  }

  /**
   * @param {string} strMimeType  The result mime type of the data URI.
   * @param {string} strASCII     The ASCII text to be embedded in data URI.
   *
   * @return {string} Return the data URI string.
   */
  static createDataURI_byStringASCII( strMimeType, strASCII ) {
    // let textEncoder = new TextEncoder();
    // let str_utf8 = textEncoder.encode( str );
    // let str_base64 = btoa( str_utf8 );
    let str_base64 = btoa( strASCII );
    let dataURI = `data:${strMimeType};base64,${str_base64}`;
    return dataURI;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect the final result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {Promise}
   *   Return a promise resolved to the final value of the processing's resulter
   * from WorkerBody. (i.e. Only the Xxx of { done: true, value: Xxx } resolved.
   * All other intermediate result { done: false, value: Yyy } are discarded.)
   */
  createPromise_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let resulter = this.createResulter_by_postCommandArgs(
      commandArgs, transferableObjectArray );
    return resulter.untilDone();
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {AsyncWorker.Resulter}
   *   Return an async generator for receving result from WorkerBody of the processing.
   */
  createResulter_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId = this.processingId_next;
    ++this.processingId_next;

    // Prepare the processing's result's receiving queue before sending it.
    let resulter = this.the_processingId_Resulter_Map.createResulter_by_processingId(
      processingId );

    let processingId_commandArgs = [ processingId, ...commandArgs ];
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
    return resulter;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * without expecting result. (i.e. fire-and-forget)
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   */
  postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId_commandArgs = [ undefined, ...commandArgs ]; // no processingId.
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
  }

  /**
   * Dispatch messages come from the owned web worker. Please register this method
   * as this WorkerProxy's Worker.onmessage.
   *
   * @param {AsyncWorker_Proxy} this
   *   The "this" should be binded to this AsyncWorker_Proxy object.
   */
  static onmessage_from_AsyncWorker_Body( e ) {

    // ( e.data == [ processingId, done, value ] )
    let [ processingId, done, value ] = e.data;

    this.the_processingId_Resulter_Map.resolve_or_reject_by_processingId_done_value(
      processingId, done, value );
  }

}
<commit_msg>workerModuleURL<commit_after>export { AsyncWorker_Proxy as Proxy };

import * as Pool from "../Pool.js";
import * as Recyclable from "../Recyclable.js";
import { PromiseResolveReject } from "./AsyncWorker_PromiseResolveReject.js";
import { processingId_Resulter_Map } from "./AsyncWorker_processingId_Resulter_Map.js";
import { Resulter } from "./AsyncWorker_Resulter.js";

/**
 * Hold the worker and its related promise map. It is a wrapper of a neural network
 * web worker for handling and communicating easily.
 *
 * @member {string} workerModuleURL
 *   The (absolute) javascript module URL which will be loaded (asynchronously) by
 * worker body (stub).
 *
 * @member {Worker} worker
 *   The worker.
 *
 * @member {number} processingId_next
 *   The next processing id. Zero means no command has been sent. Every
 * postCommand_and_expectResult() call will use a new id.
 *
 * @member {processingId_Resulter_Map} the_processingId_Resulter_Map
 *   Every worker has a result pending promise map. The key of the map is processing
 * id. The value of the map is a AsyncWorker.Resulter.
 *
 */
class AsyncWorker_Proxy extends Recyclable.Root {

  /**
   * Used as default AsyncWorker.Proxy provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "AsyncWorker.Proxy.Pool",
    AsyncWorker_Proxy, AsyncWorker_Proxy.setAsConstructor );

  /** */
  constructor( workerModuleURL ) {
    super();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
  }

  /** @override */
  static setAsConstructor( workerModuleURL ) {
    super.setAsConstructor();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
    return this;
  }

  /** @override */
  static setAsConstructor_self( workerModuleURL ) {

    // Q: What if processingId become too large (e.g. infinity)?
    // A: Because Number.MAX_SAFE_INTEGER is pretty large (at least, 2 ** 52 ),
    //    it is not so easy to become out of bounds.
    //
    this.processingId_next = 0;

    if ( this.the_processingId_Resulter_Map )
      this.the_processingId_Resulter_Map.clear();
    else
      this.the_processingId_Resulter_Map = new processingId_Resulter_Map();

    AsyncWorker_Proxy.createWorker_byModuleURL.call( this, workerModuleURL );
  }

  /** @override */
  disposeResources() {

    if ( this.worker ) {
      // Note: No processingId, because this command needs not return value.
      this.postCommandArgs( [ "disposeResources" ] );
      this.worker = null;
    }

    this.workerOptions = undefined;
    this.workerURL = undefined;
    this.workerModuleURL = undefined;

    this.the_processingId_Resulter_Map.clear();

    this.processingId_next = undefined;

    super.disposeResources();
  }

  /**
   * @param {AsyncWorker_Proxy} this
   *   The worker proxy.
   */
  static createWorker_byModuleURL( workerModuleURL ) {
    this.workerModuleURL = workerModuleURL;

    let workerDataURI
      = AsyncWorker_Proxy.create_WorkerBodyStub_Codes_DataURI( workerModuleURL );

    this.workerURL = workerDataURI;

    // Q: Why not use "module" type worker?
    // A: A "module" type worker can not use importScripts() to load global library.
    //    (e.g. tensorflow.js)
    //
    // On the other hand, a "classic" type worker can use both importScripts() and
    // import() to load global library and module.
    //
    this.workerOptions = null;

    this.worker = new Worker( this.workerURL, this.workerOptions );

    // Register callback from the web worker.
    this.worker.onmessage
      = AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body.bind( this );
  }

  /**
   * Create a data URI representing the main (i.e. body) javascript file of web worker.
   * It is viewed as a classic javascript file (i.e. not an importable module). But
   * it will load specified workerModuleURL as a module.
   *
   * In module (non-classic) web worker, static import is available. But the function
   * importScripts() will not be avbailable. For solving this problem, using
   * classic (non-module) web worker so that some global library (e.g. tensorflow.js)
   * can be loaded by importScripts(). And use dynamic import() to load ourselves
   * modules because import() can be used in classic (non-module) script.
   *
   * @param {string} workerModuleURL
   *   An (absolute) URL to a javascript module file. It will be imported
   * (asynchronously) by this generated classic javascript file (as a dataURI).
   */
  static create_WorkerBodyStub_Codes_DataURI( workerModuleURL ) {

    // The codes do the following:
    //
    //   - Import the specified module URL.
    //   - Create a temporary message queue.
    //   - Collect all messages before
    //       AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body() be registered
    //       as message handler.
    //
    let codes = ``
      + `import( "${workerModuleURL}" );\n`
      + `AsyncWorker_Body_temporaryMessageQueue = [];\n`
      + `onmessage = ( e ) => {\n`
      // + `  console.log( "Hello" );\n`
      // + `  console.log( e );\n`
      + `  AsyncWorker_Body_temporaryMessageQueue.push( e );\n`
      + `};\n`
      ;

    let workerDataURI
      = AsyncWorker_Proxy.createDataURI_byStringASCII( "text/javascript", codes );

    return workerDataURI;
  }

  /**
   * @param {string} strMimeType  The result mime type of the data URI.
   * @param {string} strASCII     The ASCII text to be embedded in data URI.
   *
   * @return {string} Return the data URI string.
   */
  static createDataURI_byStringASCII( strMimeType, strASCII ) {
    // let textEncoder = new TextEncoder();
    // let str_utf8 = textEncoder.encode( str );
    // let str_base64 = btoa( str_utf8 );
    let str_base64 = btoa( strASCII );
    let dataURI = `data:${strMimeType};base64,${str_base64}`;
    return dataURI;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect the final result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {Promise}
   *   Return a promise resolved to the final value of the processing's resulter
   * from WorkerBody. (i.e. Only the Xxx of { done: true, value: Xxx } resolved.
   * All other intermediate result { done: false, value: Yyy } are discarded.)
   */
  createPromise_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let resulter = this.createResulter_by_postCommandArgs(
      commandArgs, transferableObjectArray );
    return resulter.untilDone();
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {AsyncWorker.Resulter}
   *   Return an async generator for receving result from WorkerBody of the processing.
   */
  createResulter_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId = this.processingId_next;
    ++this.processingId_next;

    // Prepare the processing's result's receiving queue before sending it.
    let resulter = this.the_processingId_Resulter_Map.createResulter_by_processingId(
      processingId );

    let processingId_commandArgs = [ processingId, ...commandArgs ];
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
    return resulter;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * without expecting result. (i.e. fire-and-forget)
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   */
  postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId_commandArgs = [ undefined, ...commandArgs ]; // no processingId.
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
  }

  /**
   * Dispatch messages come from the owned web worker. Please register this method
   * as this WorkerProxy's Worker.onmessage.
   *
   * @param {AsyncWorker_Proxy} this
   *   The "this" should be binded to this AsyncWorker_Proxy object.
   */
  static onmessage_from_AsyncWorker_Body( e ) {

    // ( e.data == [ processingId, done, value ] )
    let [ processingId, done, value ] = e.data;

    this.the_processingId_Resulter_Map.resolve_or_reject_by_processingId_done_value(
      processingId, done, value );
  }

}
<|endoftext|>