Building a recursion function for LU decomposition in Julia - julia

I am very new to Julia and tried troubleshooting some code I wrote for a recursive LU decomposition.
This is all of my code:
`using LinearAlgebra
function recurse_lu(A)
n=size(A)[1]
L=zeros(n,n)
U=zeros(n,n)
k=n/2
convert(Int, k)
A11=A[1:(k),1:(k)]
A12=A[1:(k),(k+1):n]
A21=A[(k+1):n,1:(k)]
A22=A[(k+1):n,(k+1):n]
if n>2
L11,U11=recurse_lu(A11)
L12=zeros(size(A11)[1],size(A11)[1])
U21=zeros(size(A11)[1],size(A11)[1])
U12=inv(L11)*A12
L21=inv(U11)*A21
L22,U22=recurse_lu(A22-L21*U12)
else
L11=1
L21=A21/A11
L22=1
L12=0
U21=0
U12=A12
U22=A22-L21*A12
U11=A11
end
L[1:(k),1:(k)]=L11
L[1:(k),(k+1):n]=L12
L[(k)+1:n,1:(k)]=L21
L[(k)+1:n,(k+1):n]=L22
U[1:(k),1:(k)]=U11
U[1:(k),(k+1):n]=U12
U[(k+1):n,1:(k)]=U21
U[(k+1):n,(k+1):n]=U22
return L,U
end`
This runs into
ArgumentError: invalid index: 1.0 of type Float64 when I try to compute the function for a matrix. I would really appreciate any tips for the future as well as how to resolve this. I am guessing I am working with the wrong variable type as some point, but Julia doesn't let you know where exactly the problem is.
Thanks a lot.

The error is because you try to index an array with a floating point number, example:
julia> x = [1, 2, 3]; x[1.0]
ERROR: ArgumentError: invalid index: 1.0 of type Float64
It looks like it origins from these two lines:
k=n/2
convert(Int, k)
which probably should be
k=n/2
k = convert(Int, k)
Alternatively you can use integer division directly:
k = div(n, 2) # or n ÷ 2
which will return an Int which you can index with.

Related

Function that sets an exponent in string in Julia

I am looking for a function that does the following rending:
f("2") = 2²
f("15") = 2¹⁵
I tried f(s) = "2\^($s)" but this doesn't seem to be a valid exponent as I can't TAB.
You can try e.g.:
julia> function f(s::AbstractString)
codes = Dict(collect("1234567890") .=> collect("¹²³⁴⁵⁶⁷⁸⁹⁰"))
return "2" * map(c -> codes[c], s)
end
f (generic function with 1 method)
julia> f("2")
"2²"
julia> f("15")
"2¹⁵"
(I have not optimized it for speed, but I hope this is fast enough with the benefit of being easy to read the code)
this should be a little faster, and uses replace:
function exp2text(x)
two = '2'
exponents = ('⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹')
#'⁰':'⁹' does not contain the ranges
exp = replace(x,'0':'9' =>i ->exponents[Int(i)-48+1])
#Int(i)-48+1 returns the number of the character if the character is a number
return two * exp
end
in this case, i used the fact that replace can accept a Pair{collection,function} that does:
if char in collection
replace(char,function(char))
end

Recursion function to calculate factorial not working properly for larger numbers

I am taking a course in data-structures and trying to replicate the same in Julia.
I am using the below code in Julia -
function factorial(n)
if n <= 1
return 1
else
return n*factorial(n-1)
end
end
It is working fine with number less than or equal to 20, but for 21 and greater I am getting negative value. Same logic is working fine in Python, below is the code -
def factorial(n):
assert n >= 0 and int(n) == n, 'The number must be positive integer only'
if n <= 1:
return 1
else:
return n*factorial(n-1)
can you pleas help me understand what might be the problem?
As 张实唯 mentioned in the comments, you could pass in a BigInt as an input to calculate larger numbers.
To keep your code type stable, return one(n) instead of 1. This will make sure that whatever type was sent as input will be returned, keeping your code type stable.
julia> function factorial(n)
if n <= 1
return one(n)
else
return factorial(n - 1) * n
end
end
factorial (generic function with 1 method)
Outputs
julia> typeof(factorial(10))
Int64
julia> typeof(factorial(BigInt(10)))
BigInt
julia> typeof(factorial(big"100"))
BigInt
julia> factorial(big"100")
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Alternative one-liner
You could also write the above function as a line-liner, using Julia's ternary operator.
factorial(n) = n <= 1 ? one(n) : factorial(n-1) * n
As explained here:
In Julia, exceeding the maximum representable value of a given type results in a wraparound behavior
And the range for Int64 type (used by default on 64-bit machines to store integers) is:
julia> typemin(Int64)
-9223372036854775808
julia> typemax(Int64)
9223372036854775807
Instead use BigInt that implements arbitrary precision integers. You can convert any integer into BigInt using the big function. The downside of this approach is that the function will be slower:
function factorial(n)
if n <= 1
return big(1)
else
return big(n) * factorial(n-1)
end
end
And now you have:
julia> factorial(21)
51090942171709440000
julia> factorial(100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
EDIT
The example showing that the code of OP is not type stable:
julia> using Test
julia> function factorial(n)
if n <= 1
return 1
else
return n*factorial(n-1)
end
end
factorial (generic function with 1 method)
julia> #inferred factorial(big"21")
ERROR: return type BigInt does not match inferred return type Union{Int64, BigInt}

Restricting function signatures while using ForwardDiff in Julia

I am trying to use ForwardDiff in a library where almost all functions are restricted to only take in Floats. I want to generalise these function signatures so that ForwardDiff can be used while still being restrictive enough so functions only take numeric values and not things like Dates. I have alot of functions with the same name but different types (ie functions that take in "time" as either a float or a Date with the same function name) and do not want to remove the type qualifiers throughout.
Minimal Working Example
using ForwardDiff
x = [1.0, 2.0, 3.0, 4.0 ,5.0]
typeof(x) # Array{Float64,1}
function G(x::Array{Real,1})
return sum(exp.(x))
end
function grad_F(x::Array)
return ForwardDiff.gradient(G, x)
end
G(x) # Method Error
grad_F(x) # Method error
function G(x::Array{Float64,1})
return sum(exp.(x))
end
G(x) # This works
grad_F(x) # This has a method error
function G(x)
return sum(exp.(x))
end
G(x) # This works
grad_F(x) # This works
# But now I cannot restrict the function G to only take numeric arrays and not for instance arrays of Dates.
Is there are a way to restict functions to only take numeric values (Ints and Floats) and whatever dual number structs that ForwardDiff uses but not allow Symbols, Dates, etc.
ForwardDiff.Dual is a subtype of the abstract type Real. The issue you have, however, is that Julia's type parameters are invariant, not covariant. The following, then, returns false.
# check if `Array{Float64, 1}` is a subtype of `Array{Real, 1}`
julia> Array{Float64, 1} <: Array{Real, 1}
false
That makes your function definition
function G(x::Array{Real,1})
return sum(exp.(x))
end
incorrect (not suitable for your use). That's why you get the following error.
julia> G(x)
ERROR: MethodError: no method matching G(::Array{Float64,1})
The correct definition should rather be
function G(x::Array{<:Real,1})
return sum(exp.(x))
end
or if you somehow need an easy access to the concrete element type of the array
function G(x::Array{T,1}) where {T<:Real}
return sum(exp.(x))
end
The same goes for your grad_F function.
You might find it useful to read the relevant section of the Julia documentation for types.
You might also want to type annotate your functions for AbstractArray{<:Real,1} type rather than Array{<:Real, 1} so that your functions can work other types of arrays, like StaticArrays, OffsetArrays etc., without a need for redefinitions.
This would accept any kind of array parameterized by any kind of number:
function foo(xs::AbstractArray{<:Number})
#show typeof(xs)
end
or:
function foo(xs::AbstractArray{T}) where T<:Number
#show typeof(xs)
end
In case you need to refer to the type parameter T inside the body function.
x1 = [1.0, 2.0, 3.0, 4.0 ,5.0]
x2 = [1, 2, 3,4, 5]
x3 = 1:5
x4 = 1.0:5.0
x5 = [1//2, 1//4, 1//8]
xss = [x1, x2, x3, x4, x5]
function foo(xs::AbstractArray{T}) where T<:Number
#show xs typeof(xs) T
println()
end
for xs in xss
foo(xs)
end
Outputs:
xs = [1.0, 2.0, 3.0, 4.0, 5.0]
typeof(xs) = Array{Float64,1}
T = Float64
xs = [1, 2, 3, 4, 5]
typeof(xs) = Array{Int64,1}
T = Int64
xs = 1:5
typeof(xs) = UnitRange{Int64}
T = Int64
xs = 1.0:1.0:5.0
typeof(xs) = StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}
T = Float64
xs = Rational{Int64}[1//2, 1//4, 1//8]
typeof(xs) = Array{Rational{Int64},1}
T = Rational{Int64}
You can run the example code here: https://repl.it/#SalchiPapa/Restricting-function-signatures-in-Julia

Julia+JuMP: variable number of arguments to function

I'm trying to use JuMP to solve a non-linear problem, where the number of variables are decided by the user - that is, not known at compile time.
To accomplish this, the #NLobjective line looks like this:
#eval #JuMP.NLobjective(m, Min, $(Expr(:call, :myf, [Expr(:ref, :x, i) for i=1:n]...)))
Where, for instance, if n=3, the compiler interprets the line as identical to:
#JuMP.NLobjective(m, Min, myf(x[1], x[2], x[3]))
The issue is that #eval works only in the global scope, and when contained in a function, an error is thrown.
My question is: how can I accomplish this same functionality -- getting #NLobjective to call myf with a variable number of x[1],...,x[n] arguments -- within the local, not-known-at-compilation scope of a function?
def testme(n)
myf(a...) = sum(collect(a).^2)
m = JuMP.Model(solver=Ipopt.IpoptSolver())
JuMP.register(m, :myf, n, myf, autodiff=true)
#JuMP.variable(m, x[1:n] >= 0.5)
#eval #JuMP.NLobjective(m, Min, $(Expr(:call, :myf, [Expr(:ref, :x, i) for i=1:n]...)))
JuMP.solve(m)
end
testme(3)
Thanks!
As explained in http://jump.readthedocs.io/en/latest/nlp.html#raw-expression-input , objective functions can be given without the macro. The relevant expression:
JuMP.setNLobjective(m, :Min, Expr(:call, :myf, [x[i] for i=1:n]...))
is even simpler than the #eval based one and works in the function. The code is:
using JuMP, Ipopt
function testme(n)
myf(a...) = sum(collect(a).^2)
m = JuMP.Model(solver=Ipopt.IpoptSolver())
JuMP.register(m, :myf, n, myf, autodiff=true)
#JuMP.variable(m, x[1:n] >= 0.5)
JuMP.setNLobjective(m, :Min, Expr(:call, :myf, [x[i] for i=1:n]...))
JuMP.solve(m)
return [getvalue(x[i]) for i=1:n]
end
testme(3)
and it returns:
julia> testme(3)
:
EXIT: Optimal Solution Found.
3-element Array{Float64,1}:
0.5
0.5
0.5

Re. partitions()

Why is
julia> collect(partitions(1,2))
0-element Array{Any,1}
returned instead of
2-element Array{Any,1}:
[0,1]
[1,0]
and do I really have to
x = collect(partitions(n,m));
y = Array(Int64,length(x),length(x[1]));
for i in 1:length(x)
for j in 1:length(x[1])
y[i,j] = x[i][j];
end
end
to convert the result to a two-dimensional array?
From the wikipedia:
In number theory and combinatorics, a partition of a positive integer n, also called an integer partition, is a way of writing n as a sum of positive integers.
For array conversion, try:
julia> x = collect(partitions(5,3))
2-element Array{Any,1}:
[3,1,1]
[2,2,1]
or
julia> x = partitions(5,3)
Base.FixedPartitions(5,3)
then
julia> hcat(x...)
3x2 Array{Int64,2}:
3 2
1 2
1 1
Here's another approach to your problem that I think is a little simpler, using the Combinatorics.jl library:
multisets(n, k) = map(A -> [sum(A .== i) for i in 1:n],
with_replacement_combinations(1:n, k))
This allocates a bunch of memory, but I think your current approach does too. Maybe it would be useful to make a first-class version and add it to Combinatorics.jl.
Examples:
julia> multisets(2, 1)
2-element Array{Array{Int64,1},1}:
[1,0]
[0,1]
julia> multisets(3, 5)
21-element Array{Array{Int64,1},1}:
[5,0,0]
[4,1,0]
[4,0,1]
[3,2,0]
[3,1,1]
[3,0,2]
[2,3,0]
[2,2,1]
[2,1,2]
[2,0,3]
⋮
[1,2,2]
[1,1,3]
[1,0,4]
[0,5,0]
[0,4,1]
[0,3,2]
[0,2,3]
[0,1,4]
[0,0,5]
The argument order is backwards from yours to match mathematical convention. If you prefer the other way, that can easily be changed.
one robust solution can be achieved using lexicographic premutations generation algorithm, originally By Donald Knuth plus classic partitions(n).
that is lexicographic premutations generator:
function lpremutations{T}(a::T)
b=Vector{T}()
sort!(a)
n=length(a)
while(true)
push!(b,copy(a))
j=n-1
while(a[j]>=a[j+1])
j-=1
j==0 && return(b)
end
l=n
while(a[j]>=a[l])
l-=1
end
tmp=a[l]
a[l]=a[j]
a[j]=tmp
k=j+1
l=n
while(k<l)
tmp=a[k]
a[k]=a[l]
a[l]=tmp
k+=1
l-=1
end
end
end
The above algorithm will generates all possible unique
combinations of an array elements with repetition:
julia> lpremutations([2,2,0])
3-element Array{Array{Int64,1},1}:
[0,2,2]
[2,0,2]
[2,2,0]
Then we will generate all integer arrays that sum to n using partitions(n) (forget the length of desired arrays m), and resize them to the lenght m using resize_!
function resize_!(x,m)
[x;zeros(Int,m-length(x))]
end
And main function looks like:
function lpartitions(n,m)
result=[]
for i in partitions(n)
append!(result,lpremutations(resize_!(i, m)))
end
result
end
Check it
julia> lpartitions(3,4)
20-element Array{Any,1}:
[0,0,0,3]
[0,0,3,0]
[0,3,0,0]
[3,0,0,0]
[0,0,1,2]
[0,0,2,1]
[0,1,0,2]
[0,1,2,0]
[0,2,0,1]
[0,2,1,0]
[1,0,0,2]
[1,0,2,0]
[1,2,0,0]
[2,0,0,1]
[2,0,1,0]
[2,1,0,0]
[0,1,1,1]
[1,0,1,1]
[1,1,0,1]
[1,1,1,0]
The MATLAB script from http://www.mathworks.com/matlabcentral/fileexchange/28340-nsumk actually behaves the way I need, and is what I though that partitions() would do from the description given. The Julia version is
# k - sum, n - number of non-negative integers
function nsumk(k,n)
m = binomial(k+n-1,n-1);
d1 = zeros(Int16,m,1);
d2 = collect(combinations(collect((1:(k+n-1))),n-1));
d2 = convert(Array{Int16,2},hcat(d2...)');
d3 = ones(Int16,m,1)*(k+n);
dividers = [d1 d2 d3];
return diff(dividers,2)-1;
end
julia> nsumk(3,2)
4x2 Array{Int16,2}:
0 3
1 2
2 1
3 0
using daycaster's lovely hcat(x...) tidbit :)
I still wish there would be a more compact way of doing this.
The the first mention of this approach seem to be https://au.mathworks.com/matlabcentral/newsreader/view_thread/52610, and as far as I can understand it is based on the "stars and bars" method https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)

Resources