I would like to do something like this:
Base.#kwdef mutable struct Setup
# physics
lx = 20.0
dc = 1.0
n = 4
# inital condition
ic(x) = exp(-(x-lx/4)^2)
# numerics
nx = 200
nvis = 50
# derived numerics
dx = lx/nx
dt = dx^2/dc/10
nt = nx^2 ÷ 5
# arrays
xc = LinRange(dx/2,lx-dx/2,nx)
C0 = ic.(xc)
C = copy(C)
q = zeros(nx-1)
# collections for easy use
dgl_params=[dc,n]
end
The problem here is that it says ic was undefined. Makes sense, because ic is not in the global scope.
Then I tried writing an outside constructor instead (I am not writing an inside constructor as that would overwrite the default constructor).
Base.#kwdef mutable struct Setup
# physics
lx = 20.0
dc = 1.0
n = 4
# inital condition
ic(x) = exp(-(x-lx/4)^2)
# numerics
nx = 200
nvis = 50
# derived numerics
dx = lx/nx
dt = dx^2/dc/10
nt = nx^2 ÷ 5
# arrays
xc = LinRange(dx/2,lx-dx/2,nx)
# C0 = ic.(xc)
C0
C = copy(C)
q = zeros(nx-1)
# collections for easy use
dgl_params=[dc,n]
end
function Setup()
Setup(Setup.ic(Setup.xc))
end
Setup()
But now it says DataType has no field ic which of course makes sense, I want the ic of the object itself. However there appears to be no selfor this keyword in julia.
Strangely enough the above seems to work fine with dx or dt which are also depending on other variables
Normally the design is to have multiple dispatch and functions outside of the object
When creating structs always provide the datatype of elements
For this large structs usually you will find out that using Parameters package will be more convenient when later debugging
The easiest way to circumvent the limitation is to have a lambda function in a field such as (this is however not the recommended Julia style):
#with_kw mutable struct Setup
lx::Float64 = 20.0
ic::Function = x -> lx * x
end
This can be now used as:
julia> s = Setup(lx=30)
Setup
lx: Float64 30.0
ic: #10 (function of type var"#10#14"{Int64})
julia> s.ic(10)
300
Actually, it is not in the design to have what in Java or C++ you would call "member functions". Part of this is Julia's will to benefit from the multiple dispatch programming paradigm. In Julia, mutables are pointers, so you pass them directly to a function, e.g.
function ic(setup::Setup, x)
return exp(-(x-setup.lx/4)^2)
end
That said, there is still a way to have more Java-esque classes, though not super recommended. Check this thread and, particularly, the answered marked as solution, given by one of Julia's authors themself.
Okay, I found the solution.
This does not work, because there are no methods in julia:
Base.#kwdef mutable struct S
n = 5
m
f(x) = x + 100
A = f.(randn(n,m))
end
s = S(m=5) # ERROR: UndefVarError: f not defined
s.A
s.f(5)
But this does work, because here f is a variable and not a function
Base.#kwdef mutable struct S
n = 5
m
f= x-> x + 100
A = f.(randn(n,m))
end
s = S(m=5)
s.A
s.f(5)
I have a model with many parameters where I am passing them as a named tuple. Is there a way to promote the values into the variable scope in my function?
parameters = (
τ₁ = 0.035,
β₁ = 0.00509,
θ = 1,
τ₂ = 0.01,
β₂ = 0.02685,
...
)
And then used like so currently:
function model(init,params) # params would be the parameters above
foo = params.β₁ ^ params.θ
end
Is there a way (marco?) to get the parameters into my variable scope directly so that I can do this:
function model(init,params) # params would be the parameters above
#promote params # hypothetical macro to bring each named tuple field into scope
foo = β₁ ^ θ
end
The latter looks a lot nicer with some math-heavy code.
You can use #unpack from the UnPack.jl package1:
julia> nt = (a = 1, b = 2, c = 3);
julia> #unpack a, c = nt; # selectively unpack a and c
julia> a
1
julia> c
3
1 This was formerly part of the Parameters.jl package, which still exports #unpack and has other similar functionality you might find useful.
Edit: As noted in the comments, writing a general macro #unpack x is not possible since the fieldnames are runtime information. You could however define a macro specific to your own type/namedtuple that unpacks
julia> macro myunpack(x)
return esc(quote
a = $(x).a
b = $(x).b
c = $(x).c
nothing
end)
end;
julia> nt = (a = 1, b = 2, c = 3);
julia> #myunpack nt
julia> a, b, c
(1, 2, 3)
However, I think it is more clear to use the #unpack since this version "hides" assignments and it is not clear where the variables a, b and c comes from when reading the code.
How can I access the body of a function?
Context: I have functions inside modules which I execute with specific parameter values. I want to "keep a record" of these parameter values and corresponding functional forms. Below my attempt:
module MyModule
using Parameters # Parameters provides unpack() macro
using DataFrames # DataFrames used to store results in a DataFrame
struct ModelParameters
γ::Float64
U::Function
end
function ModelParameters(;
γ = 2.0,
U = c -> if γ == 1.0; log(c); else (c^(1-γ)-1)/(1-γ) end
)
ModelParameters(γ, U)
end
function show_constants(mp::ModelParameters)
#unpack γ = mp
d = DataFrame(
Name = ["γ"],
Description = ["parameter of U"],
Value = [γ]
)
return(d)
end
function show_functions(mp::ModelParameters)
#unpack U = mp
d = DataFrame(
Name = ["U"],
Description = ["function with parameter γ"],
Value = [U]
)
return d
end
export
ModelParameters
show_constants,
show_functions
end # end of MyModule
Keeping a record:
using Main.MyModule
mp = ModelParameters()
MyModule.show_constants(mp)
1×3 DataFrame
Row │ Name Description Value
│ String String Float64
─────┼─────────────────────────────────
1 │ γ parameter of U 2.0
MyModule.show_functions(mp)
1×3 DataFrame
Row │ Name Description Value
│ String String #2#4…
─────┼──────────────────────────────────────────
1 │ U function with parameter γ #2
This is quite useful to store scalars and arrays value, but not for functions. How could I replace #2 with something useful?
Examples of what would be useful:
c -> if γ == 1.0; log(c); else (c^(1-γ)-1)/(1-γ) end,
or
(c^(1-2.0)-1)/(1-2.0)
or (magically simplified):
1-c^(-1.0)
My question is somewhat related to Julia: show body of function (to find lost code).
You can find a similar discussion here, the best solution for functions that fit in a single line in my opinion is something like this:
type mytype
f::Function
s::String
end
mytype(x::String) = mytype(eval(parse(x)), x)
Base.show(io::IO, x::mytype) = print(io, x.s)
instead of handing over a function as an expression you give it as a String:
t = mytype("x -> x^2")
you call the function like this
t.f(3)
and access the String representation like this:
t.s
I've got this small snippet for reducing a large system:
# set up the multipliers
g1 = (s+9)/((s)*(s+6)*(s+12)*(s+14))
g2 = ((6)*(s+9)*(s+17))/((s+12)*(s+32)*(s+68))
h1 = 13
h2 = 1/(s+7)
# reduce the system in parts
s1 = (g2)/(1 + (g2)*(h1))
s2 = (s1)*(g1)
s3 = (s2)/(1 + (s2)*(h2))
# now we have a unity feedback
g = s3
show(g)
g should be the reduced equation from doing the operations above. However, I get a bunch of errors when I run the code:
Error : object 's' not found
Error : object 's' not found
Error : object 's' not found
Error : object 'g2' not found
Error : object 's1' not found
Error : object 's2' not found
Error : object 's3' not found
Error : error in evaluating the argument 'object' in selecting a method for function 'show': Error: object 'g' not found
Am I not using equations correctly?
edit: my intentions are to have s as a free variable
In order to evaluate your first line of code, there must be an object s that is already defined.
It sounds like your goal is to create a function that outputs g from a single input s. The below code wraps your calculations in a function called make_g:
make_g <- function(s){
# set up the multipliers
g1 = (s+9)/((s)*(s+6)*(s+12)*(s+14))
g2 = ((6)*(s+9)*(s+17))/((s+12)*(s+32)*(s+68))
h1 = 13
h2 = 1/(s+7)
# reduce the system in parts
s1 = (g2)/(1 + (g2)*(h1))
s2 = (s1)*(g1)
s3 = (s2)/(1 + (s2)*(h2))
# now we have a unity feedback
g = s3
g
}
Now, you can call the functions using whatever value for s you like:
make_g(s = 1)
I solved this my self. I'll post the solution when were past due date for my homework.
Okay, I'm going to build a parser or an evaluator. The de facto standard when parsing with prefix notation is to just use a stack. Add to the stack if input is a number, if it is an operator you can pop twice apply operator and put the result back on the stack.
The stack here would be a list, so I need to know how I can apply the operators. The input would be a string. "(11+2*)" This would 1+1=2*2=4. First it would read 1, and 1 to the stack. Read another 1 and add it to the stack. Now it reads "+", so it removes(pop) twice from the stack and apply + and puts the result back. Read 2, put 2 on the stack. Read *, pop twice and apply *.
Hope this makes sense. How would the predicate look like? I need one variable for the input string, one to maintain the stack, and one for the result? Three?
I'm especially wondering about push and pop on the stack as well as removing as I go from the input string.
I'll post the teacher's solution:
% Løsning oblig 3, INF121, Høsten 2009.
% Skrevet av: Dag Hovland
% Opphavsrett: Universitetet i Bergen
% Lisensiert under GPL v3, www.gnu.org. Etter tillatelse fra administrasjonen.
% Oppgave 1
alignment([],[],[]).
alignment([X|Xs],[X|Ys],[X|A]) :- alignment(Xs,Ys,A).
alignment(Xs,[_|Ys],A) :- alignment(Xs,Ys,A).
alignment([_|Xs],Ys,A) :- alignment(Xs,Ys,A).
maximum([X|Xs],Max) :- maximum(Xs,X,Max).
maximum([],(X,_),X).
maximum([X|Xs],(_,LM),MX) :- length(X,LX), LX > LM, !, maximum(Xs, (X,LX), MX).
maximum([X|Xs],(M,LM),MX) :- length(X,LX), LX < LM, !, maximum(Xs, (M,LM), MX).
% Pga. kuttene over vet vi at dersom tilfellene under brukes, så er
% X akkurat like lang som lengste sett så langt
maximum([X|Xs],_,MX) :- length(X,LX), maximum(Xs, (X,LX), MX).
maximum([_|Xs],M,MX) :- maximum(Xs, M, MX).
maxAlignment(Xs,Ys,A) :- findall((N,A),alignment(Xs,Ys,N,A),All),!,
maximum(All,(_,A)).
% Oppgave 2
path(S,S,_).
path(S,End,Edges) :- select((S,Next),Edges,EdgesRest),
path(Next, End, EdgesRest).
% select er innebygd. Skriv "listing(select) for å se definisjonen:
%select(A, [A|B], B).
%select(B, [A|C], [A|D]) :-
% select(B, C, D).
% polish(I,V,S) evaluates expression I to value V with stack S.
polish([],V,[V]).
polish(I,V,S) :- append(" ",I1,I),polish(I1,V,S).
polish([NC|I],V,S) :- name(N,[NC]),integer(N),polish(I,V,[N|S]).
polish(I,V,[F1,F2|S]) :- append("+",I1,I),Sum is F1+F2,polish(I1,V,[Sum|S]).
polish(I,V,[F1,F2|S]) :- append("-",I1,I),Sum is F2-F1,polish(I1,V,[Sum|S]).
polish(I,V,[F1,F2|S]) :- append("/",I1,I),Sum is F2/F1,polish(I1,V,[Sum|S]).
polish(I,V,[F1,F2|S]) :- append("*",I1,I),Sum is F1*F2,polish(I1,V,[Sum|S]).
evalPost(S,E) :- polish(S,E,[]).
I'm posting the whole file as it is. The following shows how it works:
?- evalPost("1 2 3 * +", V).
V = 7
?- evalPost("1 3 2 * 2 + +",V).
V = 9
?- evalPost("1 2 3 * 4 + +",V).
V = 11
?- evalPost("1 2 3 * 4 + -",V).
V = -9
?- evalPost("4 2 / 1 +",V).
V = 3