Abstract typing and multiple dispatch for functions in julia - julia

I want to have objects interact with specific interactions depending on their type.
Example problem: I have four particles, two are type A, and 2 are type B. when type A's interact I want to use the function
function interaction(parm1, parm2)
return parm1 + parm2
end
when type B's interact I want to use the function
function interaction(parm1, parm2)
return parm1 * parm2
end
when type A interacts with type B I want to use function
function interaction(parm1, parm2)
return parm1 - parm2
end
These functions are purposefully over simple.
I want to calculate a simple summation that depends on pairwise interactions:
struct part
parm::Float64
end
# part I need help with:
# initialize a list of length 4, where the entries are `struct part`, and the abstract types
# are `typeA` for the first two and `typeB` for the second two. The values for the parm can be
# -1.0,3, 4, 1.5 respectively
energy = 0.0
for i in range(length(particles)-1)
for j = i+1:length(particles)
energy += interaction(particles[i].parm, particles[j].parm)
end
end
println(energy)
assuming the use of parameters being particle[1].parm = -1, particle[2].parm = 3, particle[3].parm = 4, particle[4].parm = 1.5, energy should account for the interactions of
(1,2) = -1 + 3 = 2
(1,3) = -1 - 4 = -5
(1,4) = -1 - 1.5 = -2.5
(2,3) = 3 - 4 = -1
(2,4) = 3 - 1.5 = 1.5
(3,4) = 4 * 1.5 = 6
energy = 1
Doing this with if statements is almost trivial but not extensible. I am after a clean, tidy Julia approach...

You can do this (I use the simplest form of the implementation as in this case it is enough and it is explicit what happens I hope):
struct A
parm::Float64
end
struct B
parm::Float64
end
interaction(p1::A, p2::A) = p1.parm + p2.parm
interaction(p1::B, p2::B) = p1.parm * p2.parm
interaction(p1::A, p2::B) = p1.parm - p2.parm
interaction(p1::B, p2::A) = p1.parm - p2.parm # I added this rule, but you can leave it out and get MethodError if such case happens
function total_energy(particles)
energy = 0.0
for i in 1:length(particles)-1
for j = i+1:length(particles)
energy += interaction(particles[i], particles[j])
end
end
return energy
end
particles = Union{A, B}[A(-1), A(3), B(4), B(1.5)] # Union makes sure things are compiled to be fast
total_energy(particles)

I have no idea how to do this in your language, but what you need is an analogue to what we call the strategy pattern in object-oriented programming. A strategy is a pluggable, reusable algorithm. In Java I’d make an interface like:
interface Interaction<A, B>
{
double interact(A a, B b)
}
Then implement this three times and reuse those parts wherever you need things to interact. Another method can take an Interaction and use it without knowing how it’s implemented. I think this is the effect you’re after. Sorry I don’t know how to translate into your dialect.

Related

Acess methods for struct initialisation

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)

Refer to struct fields without dot notation (in Julia)

In Julia I've defined a type and I need to write some functions that work with the fields of that type. Some of the functions contain complicated formulas and it gets messy to use the field access dot notation all over the place. So I end up putting the field values into local variables to improve readability. It works fine, but is there some clever way to avoid having to type out all the a=foo.a lines or to have Julia parse a as foo.a etc?
struct Foo
a::Real
b::Real
c::Real
end
# this gets hard to read
function bar(foo::Foo)
foo.a + foo.b + foo.c + foo.a*foo.b - foo.b*foo.c
end
# this is better
function bar(foo::Foo)
a = foo.a
b = foo.b
c = foo.c
a + b + c + a*b - b*c
end
# this would be great
function bar(foo::Foo)
something clever
a + b + c + a*b - b*c
end
Because Julia generally encourages the use of generalized interfaces to interact with fields rather than accessing the fields directly, a fairly natural way of accomplishing this would be unpacking via iteration. In Julia, objects can be "unpacked" into multiple variables by iteration:
julia> x, y = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> x
1
julia> y
2
We can implement such an iteration protocol for a custom object, like Foo. In v0.7, this would look like:
Base.iterate(foo::Foo, state = 1) = state > 3 ? nothing : (getfield(foo, state), state + 1)
Note that 3 is hardcoded (based on the number of fields in Foo) and could be replaced with fieldcount(Foo). Now, you can simply "unpack" an instance of Foo as follows:
julia> a, b, c = Foo("one", 2.0, 3)
Foo("one", 2.0, 3)
julia> a
"one"
julia> b
2.0
julia> c
3
This could be the "something clever" at the beginning of your function. Additionally, as of v0.7, you can unpack the fields in the function argument itself:
function bar((a, b, c)::Foo)
a + b + c + a*b - b*c
end
Although this does require that you mention the field names again, it comes with two potential advantages:
In the case that your struct is refactored and the fields are renamed, all code accessing the fields will remain intact (as long as the field order doesn't change or the iterate implementation is changed to reflect the new object internals).
Longer field names can be abbreviated. (i.e. rather than using the full apples field name, you can opt to use a.)
If it's important that the field names not be repeated, you could define a macro to generate the required variables (a = foo.a; b = foo.b; c = foo.c); however, this would likely be more confusing for the readers of your code and lack the advantages listed above.
As of Julia 1.6, the macros in this package look relevant: https://github.com/mauro3/UnPack.jl.
The syntax would look like:
function bar(foo::Foo)
# something clever!
#unpack a, b, c = f
a + b + c + a*b - b*c
end
In Julia 1.7, it looks like this feature will be added with the syntax
function bar(foo::Foo)
# something clever!
(; a, b, c) = f
a + b + c + a*b - b*c
end
Here is the merged pull request: https://github.com/JuliaLang/julia/pull/39285

Can I use <- instead of = in Julia?

Like in R:
a <- 2
or even better
a ← 2
which should translate to
a = 2
and if possible respect method overloading.
= is overloaded (not in the multiple dispatch sense) a lot in Julia.
It binds a new variable. As in a = 3. You won't be able to use ← instead of = in this context, because you can't overload binding in Julia.
It gets lowered to setindex!. As in, a[i] = b gets lowered to setindex!(a, b, i). Unfortunately, setindex! takes 3 variables while ← can only take 2 variables. So you can't overload = with 3 variables.
But, you can use only 2 variables and overload a[:] = b, for example. So, you can define ←(a,b) = (a[:] = b) or ←(a,b) = setindex!(a,b,:).
a .= b gets lowered to (Base.broadcast!)(Base.identity, a, b). You can overload this by defining ←(a,b) = (a .= b) or ←(a,b) = (Base.broadcast!)(Base.identity, a, b).
So, there are two potentially nice ways of using ←. Good luck ;)
Btw, if you really want to use ← to do binding (like in 1.), the only way to do it is using macros. But then, you will have to write a macro in front of every single assignment, which doesn't look very good.
Also, if you want to explore how operators get lowered in Julia, do f(a,b) = (a .= b), for example, and then #code_lowered f(x,y).
No. = is not an operator in Julia, and cannot be assigned to another symbol.
Disclaimer: You are fully responsible if you will try my (still beginner's) experiments bellow! :P
MacroHelper is module ( big thanks to #Alexander_Morley and #DanGetz for help ) I plan to play with in future and we could probably try it here :
julia> module MacroHelper
# modified from the julia source ./test/parse.jl
function parseall(str)
pos = start(str)
exs = []
while !done(str, pos)
ex, pos = parse(str, pos) # returns next starting point as well as expr
ex.head == :toplevel ? append!(exs, ex.args) : push!(exs, ex)
end
if length(exs) == 0
throw(ParseError("end of input"))
elseif length(exs) == 1
return exs[1]
else
return Expr(:block, exs...) # convert the array of expressions
# back to a single expression
end
end
end;
With module above you could define simple test "language":
julia> module TstLang
export #tst_cmd
import MacroHelper
macro tst_cmd(a)
b = replace("$a", "←", "=") # just simply replacing ←
# in real life you would probably like
# to escape comments, strings etc
return MacroHelper.parseall(b)
end
end;
And by using it you could probably get what you want:
julia> using TstLang
julia> tst```
a ← 3
println(a)
a +← a + 3 # maybe not wanted? :P
```
3
9
What about performance?
julia> function test1()
a = 3
a += a + 3
end;
julia> function test2()
tst```
a ← 3
a +← a + 3
```
end;
julia> test1(); #time test1();
0.000002 seconds (4 allocations: 160 bytes)
julia> test2(); #time test2();
0.000002 seconds (4 allocations: 160 bytes)
If you like to see syntax highlight (for example in atom editor) then you need to use it differently:
function test3()
#tst_cmd begin
a ← 3
a ← a + a + 3 # parser don't allow you to use "+←" here!
end
end;
We could hope that future Julia IDEs could syntax highlight cmd macros too. :)
What could be problem with "solution" above? I am not so experienced julian so many things. :P (in this moment something about "macro hygiene" and "global scope" comes to mind...)
But what you want is IMHO good for some domain specific languages and not to redefine basic of language! It is because readability very counts and if everybody will redefine everything then it will end in Tower of Babel...

Is it possible to overload functions in Scilab?

I would like to know how to overload a function in scilab. It doesn't seem to be as simple as in C++. For example,
function [A1,B1,np1]=pivota_parcial(A,B,n,k,np)
.......//this is just an example// the code doesn't really matter
endfunction
//has less input/output variables//operates differently
function [A1,np1]=pivota_parcial(A,n,k,np)
.......//this is just an example// the code doesn't really matter
endfunction
thanks
Beginner in scilab ....
You can accomplish something like that by combining varargin, varargout and argn() when you implement your function. Take a look at the following example:
function varargout = pivota_parcial(varargin)
[lhs,rhs] = argn();
//first check number of inputs or outputs
//lhs: left-hand side (number of outputs)
//rhs: right-hand side (number of inputs)
if rhs == 4 then
A = varargin(1); B = 0;
n = varargin(2); k = varargin(3);
np = varargin(4);
elseif rhs == 5 then
A = varargin(1); B = varargin(2);
n = varargin(3); k = varargin(4);
np = varargin(5);
else
error("Input error message");
end
//computation goes on and it may depend on (rhs) and (lhs)
//for the sake of running this code, let's just do:
A1 = A;
B1 = B;
np1 = n;
//output
varargout = list(A1,B1,np1);
endfunction
First, you use argn() to check how many arguments are passed to the function. Then, you rename them the way you need, doing A = varargin(1) and so on. Notice that B, which is not an input in the case of 4 inputs, is now set to a constant. Maybe you actually need a value for it anyways, maybe not.
After everything is said and done, you need to set your output, and here comes the part in which using only varargout may not satisfy your need. If you use the last line the way it is, varargout = list(A1,B1,np1), you can actually call the function with 0 and up to 3 outputs, but they will be provided in the same sequence as they appear in the list(), like this:
pivota_parcial(A,B,n,k,np);: will run and the first output A1 will be delivered, but it won't be stored in any variable.
[x] = pivota_parcial(A,B,n,k,np);: x will be A1.
[x,y] = pivota_parcial(A,B,n,k,np);: x will be A1 and y will be B1.
[x,y,z] = pivota_parcial(A,B,n,k,np);: x will be A1, y will be B1, z will be np1.
If you specifically need to change the order of the output, you'll need to do the same thing you did with your inputs: check the number of outputs and use that to define varargout for each case. Basically, you'll have to change the last line by something like the following:
if lhs == 2 then
varargout = list(A1,np1);
elseif lhs == 3 then
varargout = list(A1,B1,np1);
else
error("Output error message");
end
Note that even by doing this, the ability to call this functions with 0 and up to 2 or 3 outputs is retained.

Assistance with Lua Cosine, wrong results returned

Ok, first up, this is NOT for a class, test, or other student type activity.
I'm a scripter for a game, and am trying to implement the math library for all to use, and unfortunately, all I have available to me is very basic lua. The implemented version cannot be changed, and does not include any libraries. For those wondering, its for scripting in Fold.It.
Here's what I have...
math={}
math.fact = function(b) if(b==1)or(b==0) then return 1 end e=1 for c=b,1,-1 do e=e*c end return e end
math.pow = function(b,p) e=b if(p==0) then return 1 end if(p<0) then p=p*(-1) end for c=p,2,-1 do e=e*b end return e end
math.cos = function(b,p) e=0 p=p or 10 for i=1,p do e=e+(math.pow(-1,i)*math.pow(b,2*i)/math.fact(2*i)) end return e end
To clarify above, math.fact returns factorial, which is returning accurate to about 10 points of precision, and is a new function I've done to aid in cosine calculation.
The math.pow is also a new function to handle returning powers, also working as expected.
The issue is with the cosine function. Its returning unexpected values. Here's an easier to digest version (I've been writing my library stuff ultra lean)...
function math.cos(value,precision)
result=0
precision=precision or 10
for i=1,precision do
result=result+(math.pow(-1,i)*math.pow(value,2*i)/math.fact(2*i))
end
return e
end
The problem is, with those functions, for print(math.cos(90)) it returns 4.77135... when I'm expecting -0.44807... (based on calc in scientific mode, or using an online tool to cos(90)).
I'm also having issues with sin and tan, however they are similarly written to cos, which seems to have been done in many languages. If I can figure out what I'm doing wrong, I can get them all fixed.
EDIT: Corrected typo
First, your lua doesn't run. Second, you need to make your variables local. Third, cosine starts with a one.
The problem is because the Taylor series you are using only converges on the correct values of cosine close to zero. You would have to use a far more terms of the series to get it to handle 90 correctly. You can fix this for your implementation two ways:
Add a pi constant. Then use a while loop to adjust the value such that abs(value) < 2*pi:
math.pi = 3.14159265358
while value > math.pi*2 do
value = value - math.pi * 2
end
while value < -math.pi*2 do
value = value + math.pi * 2
end
Or - find or implement a version of fmod in lua.
Here is the corrected code (you can minify it):
math={}
math.fact = function(b)
if(b==1)or(b==0) then
return 1
end
local e=1
for c=b,1,-1 do
e=e*c
end
return e
end
math.pow = function(b,p)
local e=b
if(p==0) then
return 1
end
if(p<0) then
p=p*(-1)
end
for c=p,2,-1 do
e=e*b
end
return e
end
math.cos = function(b,p)
local e=1
b = math.correctRadians(b)
p=p or 10
for i=1,p do
e=e+(math.pow(-1,i)*math.pow(b,2*i)/math.fact(2*i))
end
return e
end
math.pi = 3.1415926545358
math.correctRadians = function( value )
while value > math.pi*2 do
value = value - math.pi * 2
end
while value < -math.pi*2 do
value = value + math.pi * 2
end
return value
end
interactive lua run:
imac:~ root$ lua -i temp.lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print( math.cos( 90 ) )
-0.44807359244883
>

Resources