scilab - how to return matrices from a function with if-statements? - function

I have a scilab function that looks something like this (very simplified code just to get the concept of how it works):
function [A, S, Q]=myfunc(a)
A = a^2;
S = a+a+a;
if S > A then
Q = "Bigger";
else
Q = "Lower";
end
endfunction
And I get the expected result if I run:
--> [A,S,Q]=myfunc(2)
Q =
Bigger
S =
6.
A =
4.
But if I put matrices into the function I expect to get equivalent matrices back as an answer with a result but instead I got this:
--> [A,S,Q]=myfunc([2 4 6 8])
Q =
Lower
S =
6. 12. 18. 24.
A =
4. 16. 36. 64.
Why isn't Q returning matrices of values like S and A? And how do I achieve that it will return "Bigger. Lower. Lower. Lower." as an answer? That is, I want to perform the operation on each element of the matrix.

Because in your program you wrote Q = "Bigger" and Q = "Lower". That means that Q will only have one value. If you want to store the comparisons for every value in A and S, you have to make Scilab do that.
You can achieve such behavior by using loops. This is how you can do it by using two for loops:
function [A, S, Q]=myfunc(a)
A = a^2;
S = a+a+a;
//Get the size of input a
[nrows, ncols] = size(a)
//Traverse all rows of the input
for i = 1 : nrows
//Traverse all columns of the input
for j = 1 : ncols
//Compare each element
if S(i,j) > A(i,j) then
//Store each result
Q(i,j) = "Bigger"
else
Q(i,j) = "Lower"
end
end
end
endfunction
Beware of A = a^2. It can break your function. It has different behaviors if input a is a vector (1-by-n or n-by-1 matrix), rectangle matrix (m-by-n matrix, m ≠ n ), or square matrix (n-by-n matrix):
Vector: it works like .^, i.e. it raises each element individually (see Scilab help).
Rectangle: it won't work because it has to follow the rule of matrix multiplication.
Square: it works and follows the rule of matrix multiplication.

I will add that in Scilab, the fewer the number of loop, the better : so #luispauloml answer may rewrite to
function [A, S, Q]=myfunc(a)
A = a.^2; // used element wise power, see luispauloml advice
S = a+a+a;
Q(S > A) = "Bigger"
Q(S <= A) = "Lower"
Q = matrix(Q,size(a,1),size(a,2)) // a-like shape
endfunction

Related

Input vector to a symbolic system of functions

Suppose that I have written a function containing 3 separable functions(a system of equations).
I want to calculate the value of this function for 3 different values of my variables but I do not want to use "subs" function. What I want to do is enter a vector containing the desired values of my variables and calculate the main function which is a vector. How could I do that?. Notice that I do not want to call the function by each variable. Here is my code:
syms x y z
f1 = symfun(x.^2+3.*x.*y,[x,y,z]);
f2 = symfun(z.^3+y-x.^3-12,[x,y,z]);
f3 = symfun(2*z+x.*y+z.*x+1,[x,y,z]);
f = [f1;f2;f3];
What I mean is to calculate the f function by for example: f([12 4 6]) not byf(12 4 5)
Not the most elegant, but the best I could think of at the moment is to put it in a function wrapper. This might be one way to pass inputs as an array. This will bridge the gap between indexing the array input to be passed into the symfcn (symbolic functions).
f([12 4 6])
function [Results] = f(Inputs)
syms x y z
f1(x,y,z) = x.^2+3.*x.*y;
f2(x,y,z) = z.^3+y-x.^3-12;
f3(x,y,z) = 2*z+x.*y+z.*x+1;
Sym_Functions = [f1;f2;f3];
Results = Sym_Functions(Inputs(1),Inputs(2),Inputs(3));
end

Schwefel function trying to find global minimum with three variables, but I am receiving a error from function

I am writing a Schwefel function with three variables x1, x2 and x3 with x (-400,400), I am trying to find the global minimum of a Schwefel function. Can anybody tell me what's wrong with the function code.
function output = objective_function(in)
x1 = in(1);
x2 = in(2);
x3 = in(3);
output=(-x1.*sin(sqrt(mod(x1)))+(-x2.*sin(sqrt(mod(x2)))+(-x3.*sin(sqrt(mod(x3)));
ouput=[F1 F2];
Current Problems:
1: Mismatched delimiters in line:
output=(-x1.*sin(sqrt(mod(x1)))+(-x2.*sin(sqrt(mod(x2)))+(-x3.*sin(sqrt(mod(x3)));
2: Modulus requires a second argument. The second argument inputted into the mod() function needs to be the divisor. The modulus can only return the remainder if it knows the number being divided (dividend) and the number that is dividing (divisor). Calling the mod() function can follow the form:
mod(dividend,divisor);
Aside:
mod() is often used accidentally in replace of abs()
Modulus → mod() : Returns the remainder after division.
Example: mod(10,3) = 1 → 10/3 = 3 with remainder 1
Absolute → abs(): Returns the absolute/magnitude of the number.
Example: abs(-10) = 10 or abs(1 + 1i) = 1.4142
3: Variables F1 and F2 are not defined or initialized before being used. The variable called ouput may be a typo.
ouput=[F1 F2];
Playground Script:
Not sure what the function is supposed to exactly do but here is a script that you can modify to meet your needs. This gets rid of the errors but might need to be reconfigured to suit your exact functionality and output equation.
in = [1 2 3];
[output] = objective_function(in);
function [output] = objective_function(in)
x1 = in(1);
x2 = in(2);
x3 = in(3);
%Splitting into terms will help with debugging bracket balancing issues%
Divisor = 2;
Term_1 = (-x1.*sin(sqrt(mod(x1,Divisor))));
Term_2 = (-x2.*sin(sqrt(mod(x2,Divisor))));
Term_3 = (-x3.*sin(sqrt(mod(x3,Divisor))));
output = Term_1 + Term_2 + Term_3;
end
Ran using MATLAB R2019b

Generating reversible permutations over a set

I want to traverse all the elements in the set Q = [0, 2^16) in a non sequential manner. To do so I need a function f(x) Q --> Q which gives the order in which the set will be sorted. for example:
f(0) = 2345
f(1) = 4364
f(2) = 24
(...)
To recover the order I would need the inverse function f'(x) Q --> Q which would output:
f(2345) = 0
f(4364) = 1
f(24) = 2
(...)
The function must be bijective, for each element of Q the function uniquely maps to another element of Q.
How can I generate such a function or are there any know functions that do this?
EDIT: In the following answer, f(x) is "what comes after x", not "what goes in position x". For example, if your first number is 5, then f(5) is the next element, not f(1). In retrospect, you probably thought of f(x) as "what goes in position x". The function defined in this answer is much weaker if used as "what goes in position x".
Linear congruential generators fit your needs.
A linear congruential generator is defined by the equation
f(x) = a*x+c (mod m)
for some constants a, c, and m. In this case, m = 65536.
An LCG has full period (the property you want) if the following properties hold:
c and m are relatively prime.
a-1 is divisible by all prime factors of m.
If m is a multiple of 4, a-1 is a multiple of 4.
We'll go with a = 5, c = 1.
To invert an LCG, we solve for f(x) in terms of x:
x = (a^-1)*(f(x) - c) (mod m)
We can find the inverse of 5 mod 65536 by the extended Euclidean algorithm, or since we just need this one computation, we can plug it into Wolfram Alpha. The result is 52429.
Thus, we have
f(x) = (5*x + 1) % 65536
f^-1(x) = (52429 * (x - 1)) % 65536
There's many approaches to solving this.
Since your set size is small, the requirement for generating the function and its inverse can simply be done via memory lookup. So once you choose your permutation, you can store the forward and reverse directions in lookup tables.
One approach to creating a permutation is mapping out all elements in an array and then randomly swapping them "enough" times. C code:
int f[PERM_SIZE], inv_f[PERM_SIZE];
int i;
// start out with identity permutation
for (i=0; i < PERM_SIZE; ++i) {
f[i] = i;
inv_f[i] = i;
}
// seed your random number generator
srand(SEED);
// look "enough" times, where we choose "enough" = size of array
for (i=0; i < PERM_SIZE; ++i) {
int j, k;
j = rand()%PERM_SIZE;
k = rand()%PERM_SIZE;
swap( &f[i], &f[j] );
}
// create inverse of f
for (i=0; i < PERM_SIZE; ++i)
inv_f[f[i]] = i;
Enjoy

How to compute Fourier coefficients with MATLAB

I'm trying to compute the Fourier coefficients for a waveform using MATLAB. The coefficients can be computed using the following formulas:
T is chosen to be 1 which gives omega = 2pi.
However I'm having issues performing the integrals. The functions are are triangle wave (Which can be generated using sawtooth(t,0.5) if I'm not mistaking) as well as a square wave.
I've tried with the following code (For the triangle wave):
function [ a0,am,bm ] = test( numTerms )
b_m = zeros(1,numTerms);
w=2*pi;
for i = 1:numTerms
f1 = #(t) sawtooth(t,0.5).*cos(i*w*t);
f2 = #(t) sawtooth(t,0.5).*sin(i*w*t);
am(i) = 2*quad(f1,0,1);
bm(i) = 2*quad(f2,0,1);
end
end
However it's not getting anywhere near the values I need. The b_m coefficients are given for a
triangle wave and are supposed to be 1/m^2 and -1/m^2 when m is odd alternating beginning with the positive term.
The major issue for me is that I don't quite understand how integrals work in MATLAB and I'm not sure whether or not the approach I've chosen works.
Edit:
To clairify, this is the form that I'm looking to write the function on when the coefficients have been determined:
Here's an attempt using fft:
function [ a0,am,bm ] = test( numTerms )
T=2*pi;
w=1;
t = [0:0.1:2];
f = fft(sawtooth(t,0.5));
am = real(f);
bm = imag(f);
func = num2str(f(1));
for i = 1:numTerms
func = strcat(func,'+',num2str(am(i)),'*cos(',num2str(i*w),'*t)','+',num2str(bm(i)),'*sin(',num2str(i*w),'*t)');
end
y = inline(func);
plot(t,y(t));
end
Looks to me that your problem is what sawtooth returns the mathworks documentation says that:
sawtooth(t,width) generates a modified triangle wave where width, a scalar parameter between 0 and 1, determines the point between 0 and 2π at which the maximum occurs. The function increases from -1 to 1 on the interval 0 to 2πwidth, then decreases linearly from 1 to -1 on the interval 2πwidth to 2π. Thus a parameter of 0.5 specifies a standard triangle wave, symmetric about time instant π with peak-to-peak amplitude of 1. sawtooth(t,1) is equivalent to sawtooth(t).
So I'm guessing that's part of your problem.
After you responded I looked into it some more. Looks to me like it's the quad function; not very accurate! I recast the problem like this:
function [ a0,am,bm ] = sotest( t, numTerms )
bm = zeros(1,numTerms);
am = zeros(1,numTerms);
% 2L = 1
L = 0.5;
for ii = 1:numTerms
am(ii) = (1/L)*quadl(#(x) aCos(x,ii,L),0,2*L);
bm(ii) = (1/L)*quadl(#(x) aSin(x,ii,L),0,2*L);
end
ii = 0;
a0 = (1/L)*trapz( t, t.*cos((ii*pi*t)/L) );
% now let's test it
y = ones(size(t))*(a0/2);
for ii=1:numTerms
y = y + am(ii)*cos(ii*2*pi*t);
y = y + bm(ii)*sin(ii*2*pi*t);
end
figure; plot( t, y);
end
function a = aCos(t,n,L)
a = t.*cos((n*pi*t)/L);
end
function b = aSin(t,n,L)
b = t.*sin((n*pi*t)/L);
end
And then I called it like:
[ a0,am,bm ] = sotest( t, 100 );
and I got:
Sweetness!!!
All I really changed was from quad to quadl. I figured that out by using trapz which worked great until the time vector I was using didn't have enough resolution, which led me to believe it was a numerical issue rather than something fundamental. Hope this helps!
To troubleshoot your code I would plot the functions you are using and investigate, how the quad function samples them. You might be undersampling them, so make sure your minimum step size is smaller than the period of the function by at least factor 10.
I would suggest using the FFTs that are built-in to Matlab. Not only is the FFT the most efficient method to compute a spectrum (it is n*log(n) dependent on the length n of the array, whereas the integral in n^2 dependent), it will also give you automatically the frequency points that are supported by your (equally spaced) time data. If you compute the integral yourself (might be needed if datapoints are not equally spaced), you might calculate frequency data that are not resolved (closer spacing than 1/over the spacing in time, i.e. beyond the 'Fourier limit').

MatLab - nargout

I am learning MatLab on my own, and I have this assignment in my book which I don't quite understand. Basically I am writing a function that will calculate sine through the use of Taylor series. My code is as follows so far:
function y = sine_series(x,n);
%SINE_SERIES: computes sin(x) from series expansion
% x may be entered as a vector to allow for multiple calculations simultaneously
if n <= 0
error('Input must be positive')
end
j = length(x);
k = [1:n];
y = ones(j,1);
for i = 1:j
y(i) = sum((-1).^(k-1).*(x(i).^(2*k -1))./(factorial(2*k-1)));
end
The book is now asking me to include an optional output err which will calculate the difference between sin(x) and y. The book hints that I may use nargout to accomplish this, but there are no examples in the book on how to use this, and reading the MatLab help on the subject did not make my any wiser.
If anyone can please help me understand this, I would really appreciate it!
The call to nargout checks for the number of output arguments a function is called with. Depending on the size of nargout you can assign entries to the output argument varargout. For your code this would look like:
function [y varargout]= sine_series(x,n);
%SINE_SERIES: computes sin(x) from series expansion
% x may be entered as a vector to allow for multiple calculations simultaneously
if n <= 0
error('Input must be positive')
end
j = length(x);
k = [1:n];
y = ones(j,1);
for i = 1:j
y(i) = sum((-1).^(k-1).*(x(i).^(2*k -1))./(factorial(2*k-1)));
end
if nargout ==2
varargout{1} = sin(x)'-y;
end
Compare the output of
[y] = sine_series(rand(1,10),3)
and
[y err] = sine_series(rand(1,10),3)
to see the difference.