Is it possible to overload functions in Scilab? - 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.

Related

Iterating over different functions with different number of parameters in Julia

I'm trying to run a loop over different functions with different number of arguments. The variables are created at runtime inside the loop, and I want to use eval at each iteration to instantiate a Struct using the variable :symbol. However, I can't do this since eval only works in the global scope. This is the MWE for the case that works:
function f1(x); return x; end
function f2(x1,x2); return x1+x2; end
handles = [f1,f2]
args =[:(x1),:(x1,x2)]
x1 = 1; x2 = 1;
for (i,f) in enumerate(handles)
params = eval(args[i])
#show f(params...)
end
f(params...) = 1
f(params...) = 2
However, if I move the variable definitions inside the loop, which is what I actually want, it doesn't work after restarting Julia to clear the workspace.
function f1(x); return x; end
function f2(x1,x2); return x1+x2; end
handles = [f1,f2]
args =[:(x1),:(x1,x2)]
for (i,f) in enumerate(handles)
x1 = 1; x2 = 1;
params = eval(args[i])
#show f(params...)
end
ERROR: UndefVarError: x1 not defined
I've tried several of the answers, such as this one, but I can't seem to make it work. I could write a custom dispatch function that takes[x1,x2] and calls f1 or f2 with the correct arguments. But still, is there any way to do this with eval or with an alternative elegant solution?
EDIT: here are more details as to what I'm trying to do in my code. I have a config struct for each algorithm, and in this I want to define beforehand the arguments it takes
KMF_config = AlgConfig(
name = "KMF",
constructor = KMC.KMF,
parameters = :(mu,N,L,p),
fit = KMC.fit!)
MF_config = AlgConfig(
name = "MF",
constructor = KMC.MF,
parameters = :(mu,N,L),
fit = KMC.fit!)
alg_config_list = [KMF_config, MF_config]
for (i,alg_config) in enumerate(alg_config_list)
mu,N,L,p,A,B,C,D,data = gen_vars() #this returns a bunch of variables that are used in different algorithms
method = alg_config.constructor(eval(method.parameters)...)
method.fit(data)
end
One possible solution is to have a function take all the variables and method, and return a tuple with a subset of variables according to method.name. But I'm not sure if it's the best way to do it.
Here's an approach using multiple dispatch rather than eval:
run_a(x, y) = x + 10*y
run_b(x, y, z) = x + 10*y + 100*z
extract(p, ::typeof(run_a)) = (p.x, p.y)
extract(p, ::typeof(run_b)) = (p.x, p.y, p.z)
genvars() = (x=1, y=2, z=3)
function doall()
todo = [
run_a,
run_b,
]
for runalg in todo
v = genvars()
p = extract(v, runalg)
#show runalg(p...)
end
end
In your example you would replace run_a and run_b with KMC.KMF and KMC.MF.
Edit: Cleaned up example to avoid structs that don't exist in your example.

ndgrid - input and output from cell array

I am converting some code from Matlab to Scilab and ran into trouble trying to use Scilab 'ndgrid' function with input and output from cell array.
Specifically, I use ndgrid with an a priori unknown number of vectors (contained in a cell array) and intend to get the output grid matrices in a cell array.
In Matlab the code looks like that:
v = {0:3,0:3}; // not necessarily of length 2 (dynamically set)
G = cell(1,2);
[G{:}] = ndgrid(v{:});
I can't obtain similar behaviour using Scilab (neither for the input, nor for the output).
For the input, Scilab returns ndgrid: Wrong type for argument #1: Booleans, Integers, Decimals, Complexes, Polynomials, Rationals or Texts expected.
I hope a workaround exists. Thanks for your help!
v = list(0:3, 0:2); // not necessarily of length 2 (dynamically set)
G = list();
c = strcat(msprintf("G(%i)\n",(1:length(v))'),",")
execstr("[" + c + "] = ndgrid(v(:))")
G
does it:
--> c = strcat(msprintf("G(%i)\n",(1:length(v))'),",")
c =
"G(1),G(2)"
--> execstr("[" + c + "] = ndgrid(v(:))")
--> G
G =
(1) : [4x3 constant]
(2) : [4x3 constant]

How do I refactor this function in ELM?

I am trying to pick up functional programming and decided to start with Problem 1 on Project Euler: basically add all numbers less than 1000 divisible by 3 or 5 (link: a link).
This is the code that I have written. It outputs a list of factors of 3 or 5 (still need to figure out how to sum).
import Html exposing (text)
import Array
main =
text (
toString
[findSum_maxZ 3 5 1000]
)
findSum_maxZ x y max_z =
Array.filter isDivisible_x_or_y (Array.initialize max_z identity)
isDivisible_x_or_y x =
if x % 3 == 0 || x % 5 == 0 then True else False
My issue is that I reference 3 and 5 twice but I cannot call isDivisible with the additional parameters of the more abstract 'x' and'y'. My goal is to determine effective methods of removing these artificially mutable values so the end user only has to modify each input value once. Any advice?
I apologize if this question is dumb, there is not a lot of information on ELM available (especially compared to python, c, c++, java, etc which I have used) and I am still not fully comfortable with the functional programming jargon. Any and all help is appreciated.
The cool thing about ML languages is that you are pretty much free to build your own "dialect" to solve problems.
You can use currying to apply just the x and y arguments to your function, creating a new function where the supplied values are already set.
import Html exposing (text)
import Array
main = [findSum 3 5 1000]
|>toString
|>text
findSum x y maxZ =
let
isDivisibleByX = isDivisible x
isDivisibleByY = isDivisible y
in
Array.initialize maxZ identity
|>Array.filter isDivisibleByX
|>Array.filter isDivisibleByY
--as you can see, it is possible to use a list instead of creating
--new functions, it is up to you to check which abstraction works
--the best
isDivisible a b =
b % a == 0
You can also work with a single function, without resorting to currying:
import Html exposing (text)
import Array
main = [findSum 3 5 1000]
|>toString
|>text
findSum x y maxZ =
Array.initialize maxZ identity
|>Array.filter (\n-> isDivisible x n ) --or just (isDivisible x)
|>Array.filter (\n-> isDivisible y n)
isDivisible a b =
b % a == 0
If you want to filter the array with just one line, you can do this:
import Html exposing (text)
main = findSum 3 5 1000
|>toString
|>text
findSum x y maxZ =
let
divisibles = \n-> isDivisible x n && isDivisible y n
in
List.range 0 maxZ
|>List.filter divisibles
isDivisible a b =
b % a == 0
The most direct answer to your question is that you can have isDivisible_x_or_y take the two factors, and then use currying to pass the partially applied function to Array.filter.
That is, you can define isDivisible_x_or_y like this (I also removed the if True then True else False syntax and just return the expression directly):
isDivisible_x_or_y x y val =
val % x == 0 || val % y == 0
Currying is the ability to only supply some of the parameters to a function, and get back a function that takes the rest of the parameters. So, the type definition of isDivisible_x_or_y is Int -> Int -> Int -> Bool (that is, it takes in three Int values and returns a Bool). If we supply values for the x and y arguments (e.g. isDivisible_x_y 3 5), we now get a function with the type definition of Int -> Bool. This is the type expected by Array.filter.
You can see a working example at https://ellie-app.com/sdxWFL9ynka1
Another couple of notes:
List is much more common than Array in Elm. You would only use Array if you need to get items at specific indexes. Instead of Array.initialize, you can use List.range
Using the pipeline operator |> can often make your code a lot simpler to read. Instead of text (toString (getValue)), you have getValue |> toString |> text, which is now in the order that the operations occur, and doesn't have extra parenthesis. This whole program could be one simple pipeline (in a lot of scenarios putting everything into one pipeline can be excessive, though):
main =
List.range 0 max_z
|> List.filter (isDivisible_x_or_y 3 5)
|> toString
|> text
isDivisible_x_or_y x y val =
val % x == 0 || val % y == 0

Guidance on missing() in R

Suppose a function, G, takes two arguments; a and b: G(a = some number, b = some number).
Now two situations (wondering what commands to use in each case?):
1- if a user puts G(b = some number), will the if(missing(a)){do this} recognize the complete absence of a argument? AND more importantly:
2- if a user puts G(a =, b = some number), still will the if(missing(a)){do this} recognize a = but lack of some number in front of it?
Defining the function as below doesn't throw an error in both the cases:
ch <- function(a=NA,b=NA){ if(is.na(a)) return(b) else( return(a+b)) }
> ch(b=2)
[1] 2
> ch(a=,b=2)
[1] 2

Using inttrap and diff to get the length of a curve in Scilab

How can you get the length of the curve down below between 0 and 4*pi? The commands you should use are inttrap and diff. Here is what I have now:
t=linspace(0,4*%pi)
x=(4+sin(a*t)).*cos(3*t)
y=(4+sin(a*t)).*sin(3*t)
z=cos(3*t)
xx=diff(x)
yy=diff(y)
zz=diff(z)
aid=sqrt(xx^2+yy^2+zz^2)
length=inttrap([t],aid)
Getting error message, the last step is not right.
The reason for error message is that t and aid have different sizes. And that is because diff returns a vector with 1 entry fewer than the input. You can see how it works on an example: diff([3 1 5]) is [-2 4].
To fix this, use t(1:$-1), which omits the last entry of t. That is,
len = inttrap(t(1:$-1), aid)
(Please don't use length, which is a function name in Scilab.)
Another problem you have is that diff is just differences, not a derivative. To get the derivative, you need to divide by the step size, which in your case is t(2)-t(1).
Also, the syntax xx^2 is deprecated for elementwise power; use xx.^2 instead
t = linspace(0,4*%pi)
a = 1
x = (4+sin(a*t)).*cos(3*t)
y = (4+sin(a*t)).*sin(3*t)
z = cos(3*t)
step = t(2)-t(1)
xx = diff(x)/step
xy = diff(y)/step
xz = diff(z)/step
aid = sqrt(xx.^2+yy.^2+zz.^2)
len = inttrap(t(1:$-1), aid)

Resources