1

I am trying to apply a method that takes in two vectors and returns a resulting vector.

Below is an example input and expected result:

a = [ 1,  0, -1,  0,  0,  1]
b = [ 0,  0, -1,  0,  1, -1]

result = my_func(a, b)
# [ 1,  0, -1,  0,  1, 0]

My intial intuition is that a bitwise logic would be able to meet the above specifications. bitwise or seems the closest:

np.bitwise_or(a,b)
# array([ 1,  0, -1,  0,  1, -1])

np.bitwise_and(a,b)
# array([ 0,  0, -1,  0,  0,  1])

np.bitwise_xor(a,b)
# array([ 1,  0,  0,  0,  1, -2])

If a logical pairing is not possible, would the most efficient method of meeting the specification be applying a lambda to each index?

achtunette
  • 11
  • 4

2 Answers2

2

This is the fastest solution I could find for arrays of type np.int8 (arrays ∈ [-1, 0, 1] should be, for memory and computational efficiency) with less than 10k elements. For larger arrays clipping is more efficient than three additional operations.

Missing combinations were added to the example data.

import numpy as np

a = np.array([ 1, -1, 0,  0, 1, -1, 0,  1, -1]).astype('int8')
b = np.array([ 0,  0, 1, -1, 1, -1, 0, -1,  1]).astype('int8')
# expected   [ 1, -1, 1, -1, 1, -1, 0,  0,  0]

(a | b) * (-a ^ b).view('bool')

Output

array([ 1, -1,  1, -1,  1, -1,  0,  0,  0], dtype=int8)

Benchmark results for arrays of growing size

benchmark result

Code used to run the benchmark

perfplot.show(
    setup = lambda n: (np.random.choice([1, 0, -1], n).astype(np.int8),
                       np.random.choice([1, 0, -1], n).astype(np.int8)),
    kernels = [lambda a, b: (a | b) * (-a ^ b).view('bool'),
               lambda a, b: np.clip(a+b, -1, 1)],
    labels=['or and multiply xor', 'add and clip'],
    n_range=[2**k for k in range(10,25,2)],
    equality_check=np.array_equal
)
Michael Szczesny
  • 4,911
  • 5
  • 15
  • 32
1

You can sum and clip:

a = np.array([ 1,  0, -1,  0,  0,  1])
b = np.array([ 0,  0, -1,  0,  1, -1])

np.clip(a+b, -1, 1)

Output:

array([ 1,  0, -1,  0,  1,  0])
mozway
  • 194,879
  • 13
  • 39
  • 75