3

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!

Vasilije Bursac
  • 185
  • 1
  • 2
  • 15

4 Answers4

7

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.

carstenbauer
  • 9,817
  • 1
  • 27
  • 40
  • Thank you very much for detailed answer! I perfectly understand it now. I wanted to perform logical negation to only zeros and ones, I know that it isn't defined for integers, but I didn't know how to do it and that BitArray command exists... Thank you for great answer! – Vasilije Bursac Oct 28 '19 at 16:25
  • 3
    I feel like recommending `BitArray` obscures the issue a bit. If you only have 0s and 1s, use `Bool.(B)` to convert all elements to logical values on which you can do logical operations. It does indeed _also_ return a `BitArray` in most cases, but it's also a bit clearer _why_ it does the trick IMO. – mbauman Oct 28 '19 at 16:42
  • In other words — it's not about the array type at all! It's about the _element types_. – mbauman Oct 28 '19 at 16:44
  • @MattB. Thank you very much! I will try that, too. – Vasilije Bursac Oct 28 '19 at 16:55
  • Thanks for the comment Matt. I'll update my answer and try to clarify things a bit more. – carstenbauer Oct 28 '19 at 19:55
6

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
StefanKarpinski
  • 32,404
  • 10
  • 86
  • 111
3

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.

2

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

Oscar Smith
  • 5,766
  • 1
  • 20
  • 34
  • `A=1 .- B` is a great idea! I didn't think of that. It gets the job done. I tried ` !.B` , too but it doesn't work. Thank you for smart solution! – Vasilije Bursac Oct 28 '19 at 16:16