Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ kyle-compute <[email protected]>
DongKwanKho <[email protected]>
Ikem Peter <[email protected]>
Josh Kelley <[email protected]>
Kryonn <[email protected]>
Richard Taylor <[email protected]>
NilsDietrich <[email protected]>

Expand Down
4 changes: 4 additions & 0 deletions src/expression/embeddedDocs/embeddedDocs.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,11 @@ import { helpDocs } from './function/expression/help.js'
import { distanceDocs } from './function/geometry/distance.js'
import { intersectDocs } from './function/geometry/intersect.js'
import { andDocs } from './function/logical/and.js'
import { nandDocs } from './function/logical/nand.js'
import { notDocs } from './function/logical/not.js'
import { nullishDocs } from './function/logical/nullish.js'
import { orDocs } from './function/logical/or.js'
import { norDocs } from './function/logical/nor.js'
import { xorDocs } from './function/logical/xor.js'
import { mapSlicesDocs } from './function/matrix/mapSlices.js'
import { columnDocs } from './function/matrix/column.js'
Expand Down Expand Up @@ -448,9 +450,11 @@ export const embeddedDocs = {

// functions - logical
and: andDocs,
nand: nandDocs,
not: notDocs,
nullish: nullishDocs,
or: orDocs,
nor: norDocs,
xor: xorDocs,

// functions - matrix
Expand Down
17 changes: 17 additions & 0 deletions src/expression/embeddedDocs/function/logical/nand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const nandDocs = {
name: 'nand',
category: 'Logical',
syntax: [
'x nand y',
'nand(x, y)'
],
description: 'Logical nand. Test whether at least one of values is zero.',
examples: [
'nand(true, false)',
'nand(true, true)',
'nand(2, 4)'
],
seealso: [
'not', 'or', 'xor'
]
}
17 changes: 17 additions & 0 deletions src/expression/embeddedDocs/function/logical/nor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const norDocs = {
name: 'nor',
category: 'Logical',
syntax: [
'x nor y',
'nor(x, y)'
],
description: 'Logical nor. Test if both values are zero',
examples: [
'nor(true, false)',
'nor(false, false)',
'nor(0, 4)'
],
seealso: [
'not', 'or', 'xor'
]
}
12 changes: 12 additions & 0 deletions src/expression/operators.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ export const properties = [
op: 'or',
associativity: 'left',
associativeWith: []
},
// logical nand
'OperatorNode:nand': {
op: 'nand',
associativity: 'left',
associativeWith: []
}
},
{ // logical xor
Expand All @@ -52,6 +58,12 @@ export const properties = [
op: 'and',
associativity: 'left',
associativeWith: []
},
// logical nor
'OperatorNode:nor': {
op: 'nor',
associativity: 'left',
associativeWith: []
}
},
{ // bitwise or
Expand Down
26 changes: 16 additions & 10 deletions src/expression/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({
and: true,
xor: true,
or: true,
not: true
nand: true,
not: true,
nor: true
}

const CONSTANTS = {
Expand Down Expand Up @@ -726,7 +728,7 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({
* @private
*/
function parseConditional (state) {
let node = parseLogicalOr(state)
let node = parseLogicalOrNand(state)

while (state.token === '?') { // eslint-disable-line no-unmodified-loop-condition
// set a conditional level, the range operator will be ignored as long
Expand Down Expand Up @@ -756,15 +758,17 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({

/**
* logical or, 'x or y'
* logical nand, 'x nand y'
* @return {Node} node
* @private
*/
function parseLogicalOr (state) {
function parseLogicalOrNand (state) {
let node = parseLogicalXor(state)

while (state.token === 'or') { // eslint-disable-line no-unmodified-loop-condition
while (state.token === 'or' || state.token === 'nand') { // eslint-disable-line no-unmodified-loop-condition
const op = state.token
getTokenSkipNewline(state)
node = new OperatorNode('or', 'or', [node, parseLogicalXor(state)])
node = new OperatorNode(op, op, [node, parseLogicalXor(state)])
}

return node
Expand All @@ -776,27 +780,29 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({
* @private
*/
function parseLogicalXor (state) {
let node = parseLogicalAnd(state)
let node = parseLogicalAndNor(state)

while (state.token === 'xor') { // eslint-disable-line no-unmodified-loop-condition
getTokenSkipNewline(state)
node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd(state)])
node = new OperatorNode('xor', 'xor', [node, parseLogicalAndNor(state)])
}

return node
}

/**
* logical and, 'x and y'
* logical nor, 'x nor y'
* @return {Node} node
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned in earlier review, nand is actually a form of or (since A nand B == (not A) or (not B)). So nand should go in the logical or precedence group (maybe rename it parseLogicalOrNand?? that's optional). And conversely A nor B == (not A) and (not B) is a form of and so should go in this precedence group, which you could optionally rename parseLogicalAndNor. Thanks!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved. I reversed the group in which the NAND and NOR functions were inserted (NAND -> OR group, NOR -> AND group) and changed the names of the functions.

* @private
*/
function parseLogicalAnd (state) {
function parseLogicalAndNor (state) {
let node = parseBitwiseOr(state)

while (state.token === 'and') { // eslint-disable-line no-unmodified-loop-condition
while (state.token === 'and' || state.token === 'nor') { // eslint-disable-line no-unmodified-loop-condition
const op = state.token
getTokenSkipNewline(state)
node = new OperatorNode('and', 'and', [node, parseBitwiseOr(state)])
node = new OperatorNode(op, op, [node, parseBitwiseOr(state)])
}

return node
Expand Down
2 changes: 2 additions & 0 deletions src/factoriesAny.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export { createRe } from './function/complex/re.js'
export { createNot } from './function/logical/not.js'
export { createNullish } from './function/logical/nullish.js'
export { createOr } from './function/logical/or.js'
export { createNor } from './function/logical/nor.js'
export { createNand } from './function/logical/nand.js'
export { createXor } from './function/logical/xor.js'
export { createConcat } from './function/matrix/concat.js'
export { createColumn } from './function/matrix/column.js'
Expand Down
4 changes: 4 additions & 0 deletions src/factoriesNumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ import {
modNumber,
multiplyNumber,
normNumber,
norNumber,
notNumber,
nthRootNumber,
orNumber,
nandNumber,
powNumber,
rightArithShiftNumber,
rightLogShiftNumber,
Expand Down Expand Up @@ -204,9 +206,11 @@ export { createParserClass } from './expression/Parser.js'

// logical
export const createAnd = /* #__PURE__ */ createNumberFactory('and', andNumber)
export const createNand = /* #__PURE__ */ createNumberFactory('nand', nandNumber)
export const createNot = /* #__PURE__ */ createNumberFactory('not', notNumber)
export const createOr = /* #__PURE__ */ createNumberFactory('or', orNumber)
export const createXor = /* #__PURE__ */ createNumberFactory('xor', xorNumber)
export const createNor = /* #__PURE__ */ createNumberFactory('nor', norNumber)

// matrix
export { createMapSlices } from './function/matrix/mapSlices.js'
Expand Down
51 changes: 51 additions & 0 deletions src/function/logical/nand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { factory } from '../../utils/factory.js'
import { nandNumber } from '../../plain/number/logical.js'

const name = 'nand'
const dependencies = [
'typed',
'and',
'not'
]

export const createNand = /* #__PURE__ */ factory(name, dependencies, ({ typed, and, not }) => {
/**
* Logical `nand`. Test if at least one of the inputs is zero.
* For matrices, the function is evaluated element wise.
*
* Syntax:
*
* math.nand(x, y)
*
* Examples:
*
* math.nand(2, 4) // returns false
*
* a = [2, 5, 0]
* b = [0, 22, 0]
* c = 0
*
* math.nand(a, b) // returns [true, false, true]
* math.nand(b, c) // returns [true, true, true]
*
* See also:
*
* and, or, not, xor
*
* @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check
* @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} y Second value to check
* @return {boolean | Array | Matrix}
* Returns true when at least one of the inputs is zero
*/
return typed(
name,
{
'number, number': nandNumber,
'bigint, bigint': nandNumber,

'any, any': function (x, y) {
return not(and(x, y))
}
}
)
})
51 changes: 51 additions & 0 deletions src/function/logical/nor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { factory } from '../../utils/factory.js'
import { norNumber } from '../../plain/number/logical.js'

const name = 'nor'
const dependencies = [
'typed',
'or',
'not'
]

export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, or, not }) => {
/**
* Logical `nor`. Test if both of values are defined with zero.
* For matrices, the function is evaluated element wise.
*
* Syntax:
*
* math.nor(x, y)
*
* Examples:
*
* math.nor(2, 4) // returns false
*
* a = [2, 5, 0]
* b = [0, 22, 0]
* c = 0
*
* math.nor(a, b) // returns [false, false, true]
* math.nor(b, c) // returns [true, false, true]
*
* See also:
*
* and, or, not, xor
*
* @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check
* @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} y Second value to check
* @return {boolean | Array | Matrix}
* Returns true when both inputs are zero
*/
return typed(
name,
{
'number, number': norNumber,
'bigint, bigint': norNumber,

'any, any': function (x, y) {
return not(or(x, y))
}
}
)
})
10 changes: 10 additions & 0 deletions src/plain/number/logical.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export function orNumber (x, y) {
}
orNumber.signature = n2

export function norNumber (x, y) {
return !(x || y)
}
norNumber.signature = n2

export function xorNumber (x, y) {
return !!x !== !!y
}
Expand All @@ -20,3 +25,8 @@ export function andNumber (x, y) {
return !!(x && y)
}
andNumber.signature = n2

export function nandNumber (x, y) {
return !(x && y)
}
nandNumber.signature = n2
6 changes: 5 additions & 1 deletion src/utils/latex.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,10 @@ export const latexOperators = {
bitXor: '\\underline{|}',
bitOr: '|',
and: '\\wedge',
nand: '\\uparrow',
xor: '\\veebar',
or: '\\vee'
or: '\\vee',
nor: '\\downarrow'
}

export const latexFunctions = {
Expand Down Expand Up @@ -179,8 +181,10 @@ export const latexFunctions = {

// logical
and: { 2: `\\left(\${args[0]}${latexOperators.and}\${args[1]}\\right)` },
nand: { 2: `\\left(\${args[0]}${latexOperators.nand}\${args[1]}\\right)` },
not: { 1: latexOperators.not + '\\left(${args[0]}\\right)' },
or: { 2: `\\left(\${args[0]}${latexOperators.or}\${args[1]}\\right)` },
nor: { 2: `\\left(\${args[0]}${latexOperators.nor}\${args[1]}\\right)` },
xor: { 2: `\\left(\${args[0]}${latexOperators.xor}\${args[1]}\\right)` },

// matrix
Expand Down
Loading