Updating a list of StaticArrays - julia

Suppose I have this function, implemented without StaticArrays
function example_svector_bad(G)
vector_list = [ randn(G) for q in 1:1000]
for i in size(vector_list)
for g in 1:G
vector_list[i][g] = vector_list[i][g] * g
end
end
return vector_list
end
I'm hoping to implement it using StaticArrays for speed gains. However, I don't know how to do it without losing the flexibility of specifying G. For example, I could do
function example_svector()
vector_list = [#SVector randn(3) for q in 1:1000]
for i in size(vector_list)
vector_list[i] = SVector(vector_list[i][1] * 1, vector_list[i][1] * 2,
vector_list[i][1] * 3)
end
return vector_list
end
if I knew that G = 3 and I had to write out SVector(vector_list[i][1] * 1, vector_list[i][1] * 2, vector_list[i][1] * 3).
Is there a way to implement this for any arbitrary number of G?

The size of a static vector or array must be known at the compile time.
At the compile time only types are known (rather than values).
Hence your function could look like this:
function myRandVec(::Val{G}) where G
SVector{G}(rand(G))
end
Note that G is passed as type rather than as value and hence can be used to create a static vector.
This function could be used as:
julia> myRandVec(Val{2}())
2-element SVector{2, Float64} with indices SOneTo(2):
0.7618992223709563
0.5979657793050613

Firstly, there is a mistake in how you are indexing vector_list, where you do
for i in size(vector_list)
Let's see what that does:
julia> x = 1:10;
julia> size(x)
(10,)
The size of x is its length in each dimension, for a vector that is just (10,) since it has only one dimension. Let's try iterating:
julia> for i in size(x)
println(i)
end
10
It just prints out the number 10.
You probably meant
for i in 1:length(vector_list)
but it's better to write
for i in eachindex(vector_list)
since it is more general and safer.
As for your actual question, you can use StaticArrays.SOneTo which provides a static version of [1,2,3]:
function example_svector()
vector_list = [#SVector randn(3) for q in 1:1000]
N = length(eltype(vector_list))
c = SOneTo(N)
for i in eachindex(vector_list)
vector_list[i] = vector_list[i] .* c
end
return vector_list
end

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

Julia - generate an array of functions programmatically

I want to generate an array of functions programmatically, with a loop so that each successive function depends on the previous.
For example in pseudo-code:
f_array = [f1, f2, f3]
with:
f1(x) = x
f2(x) = 3 * f1(x)
f3(x) = 3 * f2(x)
so that I could call:
f_array[3](x)
and get the result of f3(x)
Here is what I have tried:
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = fill(f, N)
# now we update each function
for i in 2:N
f_array[i] = (f(x)= 3 * f_array[i-1](x))
end
I get an error:
ERROR: MethodError: Cannot convert an object of type getfield(Main,
Symbol("#f#15")){Int64} to an object of type typeof(f)
I cannot find a solution at the moment. Any help would be appreciated.
When you use fill with f it sets expected type for the elements of f_array to f, in the code below I am switching to abstract type to make it possible to have any function in the array
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = Array{Function}(undef, N);
f_array[1] = f;
# now we update each function
for i in 2:N
f_array[i] = x -> 3 * f_array[i-1](x)
end
print(f_array[3](2))
which produces a value of 18
In the mean time, I also found a way using metaprogramming. I post this here as it could be useful for others:
f1(x) = x
for i in 2:N
prog = "f$i(x) = 3 * f$(i-1)(x)"
exp = Meta.parse(prog)
eval(exp)
end
f3(2)
# 18
I'd write Yegor's answer as
f_array = Function[identity]
for i in 2:3
push!(f_array, x -> 3f_array[i-1](x))
end
But more importantly, this is a well known pattern: iterated function application. And it is already implemented, not in Base, but for example in IterTools.jl, by which you should be able to write:
f_array(start, N) = collect(Iterators.take(iterated(x -> 3x, start), N))
(I didn't test this, though.)

Changing the input (i.e. x+2y) of a macro to an expression ( :(x+2y)), How to produce the same output?

The code at the end of this post constructs a function which is bound to the variables of a given dictionary. Furthermore, the function is not bound to the actual name of the dictionary (as I use the Ref() statement).
An example:
julia> D = Dict(:x => 4, :y => 5)
julia> f= #mymacro4(x+2y, D)
julia> f()
14
julia> DD = D
julia> D = nothing
julia> f()
14
julia> DD[:x] = 12
julia> f()
22
Now I want to be able to construct exactly the same function when I only have access to the expression expr = :(x+2y).
How do I do this? I tried several things, but was not able to find a solution.
julia> f = #mymacro4(:(x+2y), D)
julia> f() ### the function evaluation should also yield 14. But it yields:
:(DR.x[:x] + 2 * DR.x[:y])
(I actually want to use it within another macro in which the dictionary is automatically created. I want to store this dictionary and the function within a struct, such that I'm able to call this function at a later point in time and manipulate the objects in the dictionary. If necessary, I may post the complete example and explain the complete problem.)
_freevars2(literal) = literal
function _freevars2(s::Symbol)
try
if typeof(eval(s)) <: Function
return s
else
return Meta.parse("DR.x[:$s]")
end
catch
return Meta.parse("DR.x[:$s]")
end
end
function _freevars2(expr::Expr)
for (it, s) in enumerate(expr.args)
expr.args[it] = _freevars2(s)
end
return expr
end
macro mymacro4(expr, D)
expr2 = _freevars2(expr)
quote
let DR = Ref($(esc(D)))
function mysym()
$expr2
end
end
end
end

Get a number from an array of digits

To split a number into digits in a given base, Julia has the digits() function:
julia> digits(36, base = 4)
3-element Array{Int64,1}:
0
1
2
What's the reverse operation? If you have an array of digits and the base, is there a built-in way to convert that to a number? I could print the array to a string and use parse(), but that sounds inefficient, and also wouldn't work for bases > 10.
The previous answers are correct, but there is also the matter of efficiency:
sum([x[k]*base^(k-1) for k=1:length(x)])
collects the numbers into an array before summing, which causes unnecessary allocations. Skip the brackets to get better performance:
sum(x[k]*base^(k-1) for k in 1:length(x))
This also allocates an array before summing: sum(d.*4 .^(0:(length(d)-1)))
If you really want good performance, though, write a loop and avoid repeated exponentiation:
function undigit(d; base=10)
s = zero(eltype(d))
mult = one(eltype(d))
for val in d
s += val * mult
mult *= base
end
return s
end
This has one extra unnecessary multiplication, you could try to figure out some way of skipping that. But the performance is 10-15x better than the other approaches in my tests, and has zero allocations.
Edit: There's actually a slight risk to the type handling above. If the input vector and base have different integer types, you can get a type instability. This code should behave better:
function undigits(d; base=10)
(s, b) = promote(zero(eltype(d)), base)
mult = one(s)
for val in d
s += val * mult
mult *= b
end
return s
end
The answer seems to be written directly within the documentation of digits:
help?> digits
search: digits digits! ndigits isdigit isxdigit disable_sigint
digits([T<:Integer], n::Integer; base::T = 10, pad::Integer = 1)
Return an array with element type T (default Int) of the digits of n in the given base,
optionally padded with zeros to a specified size. More significant digits are at higher
indices, such that n == sum([digits[k]*base^(k-1) for k=1:length(digits)]).
So for your case this will work:
julia> d = digits(36, base = 4);
julia> sum([d[k]*4^(k-1) for k=1:length(d)])
36
And the above code can be shortened with the dot operator:
julia> sum(d.*4 .^(0:(length(d)-1)))
36
Using foldr and muladd for maximum conciseness and efficiency
undigits(d; base = 10) = foldr((a, b) -> muladd(base, b, a), d, init=0)

How do I evaluate the function in only one of its variables in Scilab

How do I evaluate the function in only one of its variables, that is, I hope to obtain another function after evaluating the function. I have the following piece of code.
deff ('[F] = fun (x, y)', 'F = x ^ 2-3 * y ^ 2 + x * y ^ 3');
fun (4, y)
I hope to get 16-3y ^ 2 + 4y ^ 3
If what you want to do is to write x = f(4,y), and later just do x(2) to get -36, that is called partial application:
Intuitively, partial function application says "if you fix the first arguments of the function, you get a function of the remaining arguments".
This is a very useful feature, and very common Functional Programming Languages, such as Haskell, but even JS and Python now are able to do it. It is also possible to do this in MATLAB and GNU/Octave using anonymous functions (see this answer). In Scilab, however, this feature is not available.
Workround
Nonetheless, Scilab itself uses a workarounds to carry a function with its arguments without fully evaluating. You see this being used in ode(), fsolve(), optim(), and others:
Create a list containing the function and the arguments to partial evaluation: list(f,arg1,arg2,...,argn)
Use another function to evaluate such list and the last argument: evalPartList(list(...),last_arg)
The implementation of evalPartList() can be something like this:
function y = evalPartList(fList,last_arg)
//fList: list in which the first element is a function
//last_arg: last argument to be applied to the function
func = fList(1); //extract function from the list
y = func(fList(2:$),last_arg); //each element of the list, from second
//to last, becomes an argument
endfunction
You can test it on Scilab's console:
--> deff ('[F] = fun (x, y)', 'F = x ^ 2-3 * y ^ 2 + x * y ^ 3');
--> x = list(fun,4)
x =
x(1)
[F]= x(1)(x,y)
x(2)
4.
--> evalPartList(x,2)
ans =
36.
This is a very simple implementation for evalPartList(), and you have to be careful not to exceed or be short on the number of arguments.
In the way you're asking, you can't.
What you're looking is called symbolic (or formal) computational mathematics, because you don't pass actual numerical values to functions.
Scilab is numerical software so it can't do such thing. But there is a toolbox scimax (installation guide) that rely on a the free formal software wxmaxima.
BUT
An ugly, stupid but still sort of working solution is to takes advantages of strings :
function F = fun (x, y) // Here we define a function that may return a constant or string depending on the input
fmt = '%10.3E'
if (type(x)==type('')) & (type(y)==type(0)) // x is string is
ys = msprintf(fmt,y)
F = x+'^2 - 3*'+ys+'^2 + '+x+'*'+ys+'^3'
end
if (type(y)==type('')) & (type(x)==type(0)) // y is string so is F
xs = msprintf(fmt,x)
F = xs+'^2 - 3*'+y+'^2 + '+xs+'*'+y+'^3'
end
if (type(y)==type('')) & (type(x)==type('')) // x&y are strings so is F
F = x+'^2 - 3*'+y+'^2 + '+x+'*'+y+'^3'
end
if (type(y)==type(0)) & (type(x)==type(0)) // x&y are constant so is F
F = x^2 - 3*y^2 + x*y^3
end
endfunction
// Then we can use this 'symbolic' function
deff('F2 = fun2(y)',' F2 = '+fun(4,'y'))
F2=fun2(2) // does compute fun(4,2)
disp(F2)

Resources