Julia error while computing powers of a complex number - julia

I'm a beginner at Julia and am using it to compute the power of a complex number as a subroutine in a larger scientific task where I run
array = [1im^(i-j) for i in 1:5, j in 1:5]
but I get the following DomainError :
DomainError with -1:
Cannot raise an integer x to a negative power -1.
Convert input to float.
Particularly, when I run the for loop and print the value for each (i,j), the same error occurs at (i=2,j=1). I'll be very grateful if someone can help me with this. What seems to be wrong with my code? How can I overcome this error?
Thank you in advance.

Use a float as a base like this (this is what the error message recommends you to do):
julia> [(1.0im)^(i-j) for i in 1:5, j in 1:5]
5×5 Matrix{ComplexF64}:
1.0+0.0im 0.0-1.0im -1.0-0.0im -0.0+1.0im 1.0+0.0im
0.0+1.0im 1.0+0.0im 0.0-1.0im -1.0-0.0im -0.0+1.0im
-1.0+0.0im 0.0+1.0im 1.0+0.0im 0.0-1.0im -1.0-0.0im
-0.0-1.0im -1.0+0.0im 0.0+1.0im 1.0+0.0im 0.0-1.0im
1.0-0.0im -0.0-1.0im -1.0+0.0im 0.0+1.0im 1.0+0.0im
or like this
julia> [float(im)^(i-j) for i in 1:5, j in 1:5]
5×5 Matrix{ComplexF64}:
1.0+0.0im 0.0-1.0im -1.0-0.0im -0.0+1.0im 1.0+0.0im
0.0+1.0im 1.0+0.0im 0.0-1.0im -1.0-0.0im -0.0+1.0im
-1.0+0.0im 0.0+1.0im 1.0+0.0im 0.0-1.0im -1.0-0.0im
-0.0-1.0im -1.0+0.0im 0.0+1.0im 1.0+0.0im 0.0-1.0im
1.0-0.0im -0.0-1.0im -1.0+0.0im 0.0+1.0im 1.0+0.0im
The error follows from this definition:
^(z::Complex{<:Integer}, n::Integer) = power_by_squaring(z,n) # DomainError for n<0

Related

Shorthand for Int32 literals in Julia

I use lots of Int32s in my code because I have some large arrays of those. But for some x::Int32 we have typeof(x+1) == Int64 since numeric literals are Int64 by default (I have to use 64bit Julia to handle my arrays). The problem is, if I have some function f(x::Int32) then f(x+1) will method error. I don't want to implement a f(x::Int64) = f(convert(Int32, x)) for almost every function and want to use concrete types for type stability. Currently, I simply have expressions like x + Int32(1) all over my code which looks really cluttered. For other types we have shorthands, i.e., 1.f0 gives me a Float32 and big"1" a BigInt. Is there something similar for Int32?
Since you explicitly mention the big_str macro (big"") you can easily define a similar macro for Int32 (the same way the uint128_str and int128_str is defined):
macro i32_str(s)
parse(Int32, s)
end
julia> typeof(i32"1")
Int32
this might still clutter your code too much so alternatively you could exploit that a number followed by a name is multiplication:
struct i32 end
(*)(n, ::Type{i32}) = Int32(n)
julia> typeof(1i32)
Int32
You can make a macro to replace every literal integer with an Int32, a bit like what ChangePrecision.jl does for floats. A very quick first attempt is:
julia> macro literal32(ex)
esc(literal32(ex))
end;
julia> literal32(ex::Expr) = Expr(ex.head, literal32.(ex.args)...);
julia> literal32(i::Int) = Int32(i);
julia> literal32(z) = z; # ignore Symbol, literal floats, etc.
julia> #literal32 [1,2] .+ 3
2-element Vector{Int32}:
4
5
julia> #literal32 function fun(x::AbstractVector)
x[1] + 2 # both 1 and 2 are changed
end
fun (generic function with 1 method)
julia> fun(Int32[3,4]) |> typeof
Int32
One place this may have unexpected consequences is literal type parameters:
julia> #literal32([1,2,3]) isa Array{Int32,1}
true
julia> #literal32 [1,2,3] isa Array{Int32,1}
false
Another is that x^2 will not use Base.literal_pow, e.g. #literal32 Meta.#lower pi^2.
What if you say:
# Or, a::Int32 = 1
julia> a = Int32(1)
1
julia> b::Int32 = a+2
3
julia> typeof(b)
Int32
julia> f(b)
...

Creating subset using or statement

I have a data frame with 6 columns and thousands of rows containing share transactions. I want to identify rows with bad price data. The following function gives me a subset with the rows with good price data:
function in_price_range(df)
price_good = subset(df, :UnitPrice => X-> (trough_share_price .<= X .<= peak_share_price), skipmissing=true)
return price_good
end
For a subset for bad data I tried:
function out_price_range(df)
price_discrepancy = subset(df, :UnitPrice => X-> (X .< trough_share_price || X .> peak_share_price), skipmissing=true)
return price_discrepancy
end
However, that givers error TypeError: non-boolean (BitVector) used in boolean context
I tried .|| rather than || but that then gives error: syntax: "|" is not a unary operator
How do I fix the code?
In Julia, || is
help?> ||
search: ||
x || y
Short-circuiting boolean OR.
The short-circuiting part meaning, that if x is true, || will not even bother to evaluate y. In other words, this will make a branch in the code. For example:
julia> 5 < 7 || print("This is unreachable")
true
This is great if you want to write code that is efficient for a case like
if something_easy_to_evaluate || something_costly_to_evaluate
# Do something
end
In other words, this is control flow! Obviously, this cannot be broadcasted. For that, what you want is the regular or operator |, which you can broadcast with .|. So for example:
julia> a = rand(3) .< 0.5
3-element BitVector:
1
0
0
julia> b = rand(3) .< 0.5
3-element BitVector:
0
1
0
julia> a .|| b
ERROR: syntax: "|" is not a unary operator
Stacktrace:
[1] top-level scope
# none:1
julia> a .| b
3-element BitVector:
1
1
0
The same applies to && vs &; the former is only used for control-flow, the latter is normal bitwise and.

What does double dot (..) in Julia Programming Language mean?

For example in the code below, x is defining the domain, but why is there the double dot between 0 and 4pi?
using ApproxFun
x=Fun(identity,0..4π)
.. is an operator (like e.g. +) but it does not have a default definition. You can define it to to whatever you want:
julia> ..(a, b) = println(a, ", ", b)
.. (generic function with 1 method)
julia> "hello" .. "world"
hello, world
The Julia package IntervalArithmetic uses it to construct an interval, e.g.
julia> using IntervalArithmetic
julia> 4..5
[4, 5]
julia> typeof(4..5)
Interval{Float64}
and I suspect this is what it is used for in your code example.
.. is not part of Julia, rather part of the packages used by ApproxFun.
It is used to represent intervals, see the code below
julia> u = 1..3
1..3
julia> dump(u)
Interval{:closed,:closed,Int64}
left: Int64 1
right: Int64 3
So this is just a convenience constructor for the Interval object, see:
julia> 1..3 === Interval{:closed,:closed,Int64}(1,3)
true

Sequences of ASCII characters available for use as operators in macros

The RecipesBase.jl #recipe macro makes use of a couple special operators constructed out of ASCII characters, namely --> and :=. These character sequences seem to have some special attribute that allows them to be parsed into an Expr. Compare --> to --:
julia> 1 --> 2
ERROR: syntax: invalid syntax 1 --> 2
julia> 1 -- 2
ERROR: syntax: invalid operator "--"
julia> :(1 --> 2)
:($(Expr(:-->, 1, 2)))
julia> :(1 -- 2)
ERROR: syntax: invalid operator "--"
Interestingly, 1 --> 2 is parsed with an expression head of :-->, whereas other binary operators, including Unicode binary operators such as ↑ (typed as \uparrow + TAB), are parsed with an expression head of :call:
julia> dump(:(1 --> 2))
Expr
head: Symbol -->
args: Array{Any}((2,))
1: Int64 1
2: Int64 2
julia> dump(:(1 ↑ 2))
Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol ↑
2: Int64 1
3: Int64 2
So, I have a few related questions:
What's up with --> and :=? (EDIT: In other words, why are those character sequences specially parsed?)
Are there other sequences of ASCII characters that behave similarly to --> and := and that can therefore be used as operators in macros?
Is there documentation somewhere that lists the various "special" sequences of ASCII characters?
--> and := are specially parsed by the Julia parser.
Take a look at this file:
https://github.com/JuliaLang/julia/blob/f54cdf45a9e04f1450ba22142ddac8234389fe05/src/julia-parser.scm
It lists all of the specially parsed character sequences, and I'm pretty sure you can also get the associativity from it.

Julia splat operator unpacking

In Python, one can use the * operator in the unpacking of an iterable.
In [1]: head, *tail = [1, 2, 3, 4, 5]
In [2]: head
Out[2]: 1
In [3]: tail
Out[3]: [2, 3, 4, 5]
I would like to produce the same behavior in Julia. I figured that the equivalent ... operator would work, but it seems to just produce an error in this context.
julia> head, tail... = [1, 2, 3, 4, 5]
ERROR: syntax: invalid assignment location "tail..."
I was able to produce the results I want using the following, but this is an ugly solution.
julia> head, tail = A[1], A[2:end]
(1,[2,3,4,5])
Can I unpack the array such that tail would contain the rest of the items after head using the splat (...) operator? If not, what is the cleanest alternative?
Edit: This feature has been proposed in #2626. It looks like it will be part of the 1.0 release.
As of Julia 1.6
It is now possible to use ... on the left-hand side of destructured assignments for taking any number of items from the front of an iterable collection, while also collecting the rest.
Example of assigning the first two items while slurping the rest:
julia> a, b, c... = [4, 8, 15, 16, 23, 42]
# 6-element Vector{Int64}:
# 4
# 8
# 15
# 16
# 23
# 42
julia> a
# 4
julia> b
# 8
julia> c
# 4-element Vector{Int64}:
# 15
# 16
# 23
# 42
This syntax is implemented using Base.rest, which can be overloaded to customize its behavior.
Example of overloading Base.rest(s::Union{String, SubString{String}}, i::Int) to slurp a Vector{Char} instead of the default SubString:
julia> a, b... = "hello"
julia> b
# "ello"
julia> Base.rest(s::Union{String, SubString{String}}, i=1) = collect(SubString(s, i))
julia> a, b... = "hello"
julia> b
# 4-element Vector{Char}:
# 'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase)
# 'l': ASCII/Unicode U+006C (category Ll: Letter, lowercase)
# 'l': ASCII/Unicode U+006C (category Ll: Letter, lowercase)
# 'o': ASCII/Unicode U+006F (category Ll: Letter, lowercase)
That does indeed sound like a job for a macro:
function unpack(lhs, rhs)
len = length(lhs.args)
if len == 1
# just remove the splatting
l, is_splat = remove_splat(lhs.args[1])
return :($l = $(esc(rhs)))
else
new_lhs = :()
new_rhs = quote
tmp = $(esc(rhs))
$(Expr(:tuple))
end
splatted = false
for (i, e) in enumerate(lhs.args)
l, is_splat = remove_splat(e)
if is_splat
splatted && error("Only one splatting operation allowed on lhs")
splatted = true
r = :(tmp[$i:end-$(len-i)])
elseif splatted
r = :(tmp[end-$(len-i)])
else
r = :(tmp[$i])
end
push!(new_lhs.args, l)
push!(new_rhs.args[4].args, r)
end
return :($new_lhs = $new_rhs)
end
end
remove_splat(e::Symbol) = esc(e), false
function remove_splat(e::Expr)
if e.head == :(...)
return esc(e.args[1]), true
else
return esc(e), false
end
end
macro unpack(expr)
if Meta.isexpr(expr, :(=))
if Meta.isexpr(expr.args[1], :tuple)
return unpack(expr.args[1], expr.args[2])
else
return unpack(:(($(expr.args[1]),)), expr.args[2])
end
else
error("Cannot parse expression")
end
end
It is not very well tested, but basic things work:
julia> #unpack head, tail... = [1,2,3,4]
(1,[2,3,4])
julia> #unpack head, middle..., tail = [1,2,3,4,5]
(1,[2,3,4],5)
A few Julia gotchas:
x,y = [1,2,3] #=> x = 1, y = 2
a = rand(3)
a[1:3], y = [1,2,3] #=> a = [1.0,1.0,1.0], y = 2
The macro follows this behavior
#unpack a[1:3], y... = [1,2,3]
#=> a=[1.0,1.0,1.0], y=[2,3]

Resources