How to apply not operator to all matrix elements in Julia?

1.4k Views Asked by At

I need to apply "not" operator to matrix of zeros and ones in Julia. In Matlab I would do this:

A=not(B);

In Julia I tried doing this:

A = .~ B;

and

A = .! B;

It should turn zeros to ones and ones to zeros but I get error as a result or all matrix elements are some negative numbers that I didn't enter. Thanks in advance!

4

There are 4 best solutions below

5
On BEST ANSWER

The issue with A = .!B is that logical negation, !(::Int64), isn't defined for integers. This makes sense: What should, say, !3 reasonably give?

Since you want to perform a logical operation, is there a deeper reason why you are working with integers to begin with?

You could perhaps work with a BitArray instead which is vastly more efficient and should behave like a regular Array in most operations.

You can easily convert your integer matrix to a BitArray. Afterwards, applying a logical not works as expected.

julia> A = rand(0:1, 5,5)
5×5 Array{Int64,2}:
 0  0  0  1  1
 0  1  0  0  1
 0  1  1  1  0
 1  1  0  0  0
 1  1  1  0  0

julia> B = BitArray(A)
5×5 BitArray{2}:
 0  0  0  1  1
 0  1  0  0  1
 0  1  1  1  0
 1  1  0  0  0
 1  1  1  0  0

julia> .!B
5×5 BitArray{2}:
 1  1  1  0  0
 1  0  1  1  0
 1  0  0  0  1
 0  0  1  1  1
 0  0  0  1  1

The crucial part here is that the element type (eltype) of a BitArray is Bool, for which negation is obviously well defined. In this sense, you could also use B = Bool.(A) to convert all the elements to booleans.

1
On

While not conceptually the cleanest, A=1.-B will do what you want. The problem with ~ is that it is performing a bitwise not on integers, which produces negative numbers. Not sure what is wrong wiht ! except it maybe should be !.B

1
On

For a general solution to going from A where A is a matrix of numbers to a boolean matrix with true values where there were zeros and false values elsewhere, you can do this:

julia> A = rand(0:3, 5, 5)
5×5 Array{Int64,2}:
 1  0  1  0  3
 2  0  1  1  0
 2  1  1  3  1
 1  0  3  0  3
 1  3  3  1  2

julia> (!iszero).(A)
5×5 BitArray{2}:
 1  0  1  0  1
 1  0  1  1  0
 1  1  1  1  1
 1  0  1  0  1
 1  1  1  1  1

To break down what's going on here:

  • iszero is a predicate that tests if a scalar value is zero
  • !iszero is a predicate that returns if a scalar value is not zero
  • (!iszero).(A) broadcasts the !iszero function over the matrix A

This returns a BitArray with the desired pattern of zeros (falses) and ones (trues). Note that in an array context, false prints as 0 and true prints as 1 (they are numerically equal). You can also compare with the number 0 like this:

julia> A .!= 0
5×5 BitArray{2}:
 1  0  1  0  1
 1  0  1  1  0
 1  1  1  1  1
 1  0  1  0  1
 1  1  1  1  1
1
On

You can also roll your own:

not(x) = (x |> Bool |> !) |> Float64

defines a method that will convert x to boolean, apply not, and then convert the result back to numbers. not.(A) will act element-wise on the array A. Here |> redirects the output to the next method and works with broadcasting.