// META: title=test WebNN API sign operation
// META: global=window
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
// META: script=../resources/utils.js
// META: timeout=long

'use strict';

// https://github.com/webmachinelearning/webnn/issues/375#issuecomment-2292466613
// Represents the sign operation that return elementwise -1/0/1 depending on
// element sign.
//
// MLOperand sign(MLOperand input, optional MLOperatorOptions options = {});


const getSignPrecisionTolerance = (graphResources) => {
  return {metricType: 'ULP', value: 0};
};

const signTests = [
  {
    'name': 'sign float32 1D constant tensor',
    'graph': {
      'inputs': {
        'signInput': {
          'data': [
            -0.946033775806427, 0.9996118545532227, 0.21998752653598785,
            -0.22639396786689758
          ],
          'descriptor': {shape: [4], dataType: 'float32'},
          'constant': true
        }
      },
      'operators': [{
        'name': 'sign',
        'arguments': [{'input': 'signInput'}],
        'outputs': 'signOutput'
      }],
      'expectedOutputs': {
        'signOutput': {
          'data': [-1, 1, 1, -1],
          'descriptor': {shape: [4], dataType: 'float32'}
        }
      }
    }
  },
  {
    'name': 'sign float16 1D tensor',
    'graph': {
      'inputs': {
        'signInput': {
          'data': [
            -0.946033775806427, 0.9996118545532227, 0.21998752653598785,
            -0.22639396786689758
          ],
          'descriptor': {shape: [4], dataType: 'float16'}
        }
      },
      'operators': [{
        'name': 'sign',
        'arguments': [{'input': 'signInput'}],
        'outputs': 'signOutput'
      }],
      'expectedOutputs': {
        'signOutput': {
          'data': [-1, 1, 1, -1],
          'descriptor': {shape: [4], dataType: 'float16'}
        }
      }
    }
  },
  {
    'name': 'sign float32 1D tensor',
    'graph': {
      'inputs': {
        'signInput': {
          'data': [
            -0.946033775806427, 0.9996118545532227, 0.21998752653598785, 0.0
          ],
          'descriptor': {shape: [4], dataType: 'float32'}
        }
      },
      'operators': [{
        'name': 'sign',
        'arguments': [{'input': 'signInput'}],
        'outputs': 'signOutput'
      }],
      'expectedOutputs': {
        'signOutput': {
          'data': [-1, 1, 1, 0],
          'descriptor': {shape: [4], dataType: 'float32'}
        }
      }
    }
  },
  {
    'name': 'sign float32 1D tensor with -infinity and +infinity',
    'graph': {
      'inputs': {
        'signInput': {
          'data': [-0.946033775806427, 0.9996118545532227, -Infinity, Infinity],
          'descriptor': {shape: [4], dataType: 'float32'}
        }
      },
      'operators': [{
        'name': 'sign',
        'arguments': [{'input': 'signInput'}],
        'outputs': 'signOutput'
      }],
      'expectedOutputs': {
        'signOutput': {
          'data': [-1, 1, -1, 1],
          'descriptor': {shape: [4], dataType: 'float32'}
        }
      }
    }
  },
  {
    'name': 'sign int32 2D tensor',
    'graph': {
      'inputs': {
        'signInput': {
          // int32 range: [/* -(2**31) */ -2147483648, /* 2**31 - 1 */ 2147483647]
          'data': [-2147483648, 0, 2147483646, 2147483647],
          'descriptor': {shape: [2, 2], dataType: 'int32'}
        }
      },
      'operators': [{
        'name': 'sign',
        'arguments': [{'input': 'signInput'}],
        'outputs': 'signOutput'
      }],
      'expectedOutputs': {
        'signOutput': {
          'data': [-1, 0, 1, 1],
          'descriptor': {shape: [2, 2], dataType: 'int32'}
        }
      }
    }
  },
  {
    'name': 'sign int64 3D tensor',
    'graph': {
      'inputs': {
        'signInput': {
          'data': [-1, 0, 1, 2, -2, -1, 0, 1],
          'descriptor': {shape: [2, 2, 2], dataType: 'int64'}
        }
      },
      'operators': [{
        'name': 'sign',
        'arguments': [{'input': 'signInput'}],
        'outputs': 'signOutput'
      }],
      'expectedOutputs': {
        'signOutput': {
          'data': [-1, 0, 1, 1, -1, -1, 0, 1],
          'descriptor': {shape: [2, 2, 2], dataType: 'int64'}
        }
      }
    }
  },
  {
    'name': 'sign int8 4D tensor',
    'graph': {
      'inputs': {
        'signInput': {
          // int8 range: [/* -(2**7) */ -128, /* 2**7 - 1 */ 127]
          'data': [-128, 0, 1, 2, -2, -1, 0, 127],
          'descriptor': {shape: [1, 2, 2, 2], dataType: 'int8'}
        }
      },
      'operators': [{
        'name': 'sign',
        'arguments': [{'input': 'signInput'}],
        'outputs': 'signOutput'
      }],
      'expectedOutputs': {
        'signOutput': {
          'data': [-1, 0, 1, 1, -1, -1, 0, 1],
          'descriptor': {shape: [1, 2, 2, 2], dataType: 'int8'}
        }
      }
    }
  },
];

if (navigator.ml) {
  signTests.forEach((test) => {
    webnn_conformance_test(
        buildAndExecuteGraph, getSignPrecisionTolerance, test);
  });
} else {
  test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
}
