user3380558
user3380558

Reputation: 33

How to implement NOR, NAND, XNOR in math.js?

I would like to somebody help me. There is a very good JS library math.js. It implements boolean logical operators NOT, OR, AND, XOR. I need the others ones: NOR, NAND, XNOR.

I know that NOR is NOT OR, but; there is a problem I need this operators to be able to use them as a string input to evaluate, for example:

(A OR B) XNOR C
B NAND (NOT (A OR B AND C))

The math.js has a parser and can deliminate (?) the string to the structure with nodes and evaluate it. But, it knows NOT, OR, AND, XOR only.

Is my request clear? Anybody help me?

Thanks!

Upvotes: 1

Views: 4585

Answers (1)

deamentiaemundi
deamentiaemundi

Reputation: 5525

Math.js has a regular parser to do so. That means you can simply (for some large values of "simple") add to it what you need.

(Assuming you clone'd Math.js from Github) One round to add nor, the others are similar.

In /lib/expression/parse.js add what you need in the object NAMED_DELIMITERS (and don't be like me and forget the commas ;-) ).

var NAMED_DELIMITERS = {
  'mod': true,
  'to': true,
  'in': true,
  'and': true,
  'xor': true,
  'or': true,
  'nor': true,
  'not': true
};

Add it to the operators listed in /lib/expression/operators.js, too. e.g.:

{ //logical nor
  'OperatorNode:nor': {
    associativity: 'left',
    associativeWith: []
  }
},

Write the working code (just build them from the existing functions) and put the files in the directory /lib/function/logical/.

'use strict';

function factory (type, config, load, typed) {
  var latex = require('../../utils/latex');

  var matrix = load(require('../../type/matrix/function/matrix'));

  var algorithm03 = load(require('../../type/matrix/utils/algorithm03'));
  var algorithm05 = load(require('../../type/matrix/utils/algorithm05'));
  var algorithm12 = load(require('../../type/matrix/utils/algorithm12'));
  var algorithm13 = load(require('../../type/matrix/utils/algorithm13'));
  var algorithm14 = load(require('../../type/matrix/utils/algorithm14'));

  var nor = typed('nor', {

    'number, number': function (x, y) {
      return !(!!(x || y));
    },

    'Complex, Complex': function (x, y) {
      return !((x.re !== 0 || x.im !== 0) || (y.re !== 0 || y.im !== 0));
    },

    'BigNumber, BigNumber': function (x, y) {
      return !((!x.isZero() && !x.isNaN()) || (!y.isZero() && !y.isNaN()));
    },

    'Unit, Unit': function (x, y) {
      return !((x.value !== 0 && x.value !== null) || (y.value !== 0 && y.value !== null));
    },

    'Matrix, Matrix': function (x, y) {
      // result
      var c;

      // process matrix storage
      switch (x.storage()) {
        case 'sparse':
          switch (y.storage()) {
            case 'sparse':
              // sparse + sparse
              c = algorithm05(x, y, nor);
              break;
            default:
              // sparse + dense
              c = algorithm03(y, x, nor, true);
              break;
          }
          break;
        default:
          switch (y.storage()) {
            case 'sparse':
              // dense + sparse
              c = algorithm03(x, y, nor, false);
              break;
            default:
              // dense + dense
              c = algorithm13(x, y, nor);
              break;
          }
          break;
      }
      return c;
    },

    'Array, Array': function (x, y) {
      // use matrix implementation
      return nor(matrix(x), matrix(y)).valueOf();
    },

    'Array, Matrix': function (x, y) {
      // use matrix implementation
      return nor(matrix(x), y);
    },

    'Matrix, Array': function (x, y) {
      // use matrix implementation
      return nor(x, matrix(y));
    },

    'Matrix, any': function (x, y) {
      // result
      var c;
      // check storage format
      switch (x.storage()) {
        case 'sparse':
          c = algorithm12(x, y, nor, false);
          break;
        default:
          c = algorithm14(x, y, nor, false);
          break;
      }
      return c;
    },

    'any, Matrix': function (x, y) {
      // result
      var c;
      // check storage format
      switch (y.storage()) {
        case 'sparse':
          c = algorithm12(y, x, nor, true);
          break;
        default:
          c = algorithm14(y, x, nor, true);
          break;
      }
      return c;
    },

    'Array, any': function (x, y) {
      // use matrix implementation
      return algorithm14(matrix(x), y, nor, false).valueOf();
    },

    'any, Array': function (x, y) {
      // use matrix implementation
      return algorithm14(matrix(y), x, nor, true).valueOf();
    }
  });

  nor.toTex = '\\left(${args[0]}' + latex.operators['nor'] + '${args[1]}\\right)';

  return nor;
}

exports.name = 'nor';
exports.factory = factory;

Add those files to index.js residing in the same directory.

module.exports = [
  require('./and'),
  require('./not'),
  require('./or'),
  require('./nor'),
  require('./xor')
];

Add the correct symbol to the Latex dictionary in /lib/utils/latex.js

exports.operators = {
  // ...
  'nor': '\\curlywedge'
};

Math.js is quite legible, it should be no problem to add what you need and if not…well…that's what Stackoverflow is for, isn't it? ;-)

Update the documentation. In the file ./lib/expression/docs/function/logical/nor.js put

module.exports = {
  'name': 'nor',
  'category': 'Logical',
  'syntax': [
    'x or y',
    'or(x, y)'
  ],
  'description': 'Logical nor. Test if neither value is defined with a nonzero/nonempty value.',
  'examples': [
    'true nor false',
    'false nor false',
    '0 nor 4'
  ],
  'seealso': [
    'not', 'and', 'xor', 'or'
  ]
};

and update the doc-index in the file ./lib/expression/docs/index.js with

docs['nor'] = require('./function/logical/or');

Update the tests. Copy the file test/function/logical/or.test.js to the file test/function/logical/nor.test.js and replace every or with nor and reverse all of the booleans. With the following exceptions:

  it('should nor two booleans', function () {
    assert.strictEqual(nor(false, false), true);
    assert.strictEqual(nor(false, true), false);
    assert.strictEqual(nor(true, false), false);
    assert.strictEqual(nor(true, true), false);
  });

  it('should nor mixed numbers and booleans', function () {
    assert.strictEqual(nor(2, false), false);
    assert.strictEqual(nor(2, true), false);
    assert.strictEqual(nor(0, false), true);
    assert.strictEqual(nor(0, true), false);
    assert.strictEqual(nor(false, 2), false);
    assert.strictEqual(nor(true, 2), false);
    assert.strictEqual(nor(true, 0), false);
  });

Build math.js by running:

 npm install
 npm run build

The building process might last a little while (two and a half minutes for minify).

Run the tests.

npm test

The test in test/function/logical/nor.test.js at line 202 fails and I do not know if it is in the nor implementation (unlikely but possible) or in the implementation of the sparse matrix optimizations.

If it works: offer your changes to math.js but the chance is quite small that they get accepted (syntactic sugar is sometimes, albeit not always, frowned upon), so don't get too disappointed.

Upvotes: 3

Related Questions