You'll have to be easy on me, I am new to matlab and SO. I am having an issue using the matlab solver to calculate internal rate of return(IRR). I saw that the financial toolbox in matlab had a function for this, however I don't believe I have it installed and did not want to get the trial version on their site.
Given the simple nature of my particular IRR calculation, I figured it would be easy enough to simply code in matlab. It is the same yearly cashflow, so what I put into matlab was as follows:
syms x k;
IRR = solve(investment == yrSavings* symsum((1+x)^-k,1, nYears));
It doesn't fail, and in fact gives a number. The only problem is the the result is incorrect! I type in the IRR manually and it never equals the investment. Using wolframalpha I found the actual solution, went back and manually typed in wolframalpha's answer, and the symsum function returned the correct result. I'm not sure what's up with the solver!
The way you have the formula written, the symbolic assumption is that you are using x as the iterator variable. I believe you want to use k. Try this:
syms x k;
IRR = solve(investment == yrSavings* symsum((1+x)^-k,k,1, nYears));
Another approach would be to use the MATLAB function roots to compute the discount factor and then convert that to an IRR. I happened to write such a function the other day, so I thought I might as well post it here for reference. It is heavily commented but the actual code is only three lines.
% Compute the IRR of a stream of cashflows represented as a vector. For example:
% > irr([-123400, 36200, 54800, 48100])
% ans = 0.059616
%
% If the provided stream of cashflows starts with a negative cashflow and all
% other cashflows are positive then `irr` will return a single scalar result.
%
% If multiple IRRs exist, all possible IRRs are returned as a column vector. For
% example:
% > irr([-1.0, 1.0, 1.1, 1.3, 1.0, -3.7])
% ans =
% 0.050699
% 0.824254
%
% If no IRRs exist, or if infinitely many IRRs exist, an empty array is
% returned. For example:
% > irr([1.0, 2.0, 3.0])
% ans = [](0x1)
%
% > irr([0.0])
% ans = [](0x1)
%
% Unlike Excel's IRR function no initial guess can be provided because all
% possible IRRs are returned anyway
%
% This function is not vectorized and will fail if called with a matrix argument
function irrs = irr(cashflows)
%% Overview
% The IRR is defined as the rate, r, such that:
%
% c0 + c1 / (1 + r) + c2 / (1 + r) ^ 2 + ... + cn / (1 + r) ^ n = 0
%
% where c0, c1, c2, ..., cn are the cashflows
%
% We define discount factors, d = 1 / (1 + r), so that the above becomes a
% polynomial in terms of the discount factors:
%
% c0 + c1 * d + c2 * d^2 + ... + cn * d^n = 0
%
% Such a polynomial will have n complex roots but between 0 and n real roots.
% In the important special case that c0 < 0 and c1, c2, ..., cn > 0 there
% will be exactly one real root.
%% Check that input is a vector, not a matrix
assert(isvector(cashflows), 'Input to irr must be a vector of cashflows');
%% Calculation of IRRs
% We use the built-in functions `roots` to compute all roots of the
% polynomial, which are the discount factors `d`. The user will provide a
% vector as [c0, c1, c2, ..., cn] but roots expects something of the form
% [cn, ..., c2, c2, c0] so we reverse the order of cashflows using (end:-1:1).
% At this stage `d` has n elements, most of which are likely complex.
d = roots(cashflows(end:-1:1));
% The function `roots` provides all roots, including complex ones. We are only
% interested in the real roots, so we filter out the complex roots here. There
% many also be spurious real roots less or equal to 0, which we also filter
% out. Now `rd` could have between 0 and n elements but is likely to have a
% single element
rd = d(imag(d) == 0.0 & real(d) > 0);
% We have solved everything in terms of discount factors, so we convert to
% rates by inverting the defining formula. Since the discount factors are
% real and positive, the IRRs are real and greater than -100%.
irrs = 1.0 ./ rd - 1.0;
end
Related
I'm trying to run a program in matlab to obtain the direct and inverse DFT for a grey scale image, but I'm not able to recover the original image after applying the inverse. I'm getting complex numbers as my inverse output. Is like i'm losing information. Any ideas on this? Here is my code:
%2D discrete Fourier transform
%Image Dimension
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1)=(1/M*N)*F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N)));
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
There are a couple of issues with your code:
You are not applying the definition of the DFT (or IDFT) correctly: you need to sum over the original variable(s) to obtain the transform. See the formula here; notice the sum.
In the IDFT the normalization constant should be 1/(M*N) (not 1/M*N).
Note also that the code could be made mucho more compact by vectorization, avoiding the loops; or just using the fft2 and ifft2 functions. I assume you want to compute it manually and "low-level" to verify the results.
The code, with the two corrections, is as follows. The modifications are marked with comments.
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
F = zeros(M,N); % initiallize to 0
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1) = F(u+1,v+1) + ...
f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N))); % add term
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
z = zeros(M,N);
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1) = z(x+1,y+1) + (1/(M*N)) * ... % corrected scale factor
F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N))); % add term
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
Now the original and recovered image differ only by very small values, of the order of eps, due to the usual floating-point inaccuacies:
>> f-z
ans =
1.0e-15 *
Columns 1 through 2
0.180411241501588 + 0.666133814775094i -0.111022302462516 - 0.027755575615629i
0.000000000000000 + 0.027755575615629i 0.277555756156289 + 0.212603775716506i
0.000000000000000 - 0.194289029309402i 0.000000000000000 + 0.027755575615629i
Column 3
-0.194289029309402 - 0.027755575615629i
-0.222044604925031 - 0.055511151231258i
0.111022302462516 - 0.111022302462516i
Firstly, the biggest error is that you are computing the Fourier transform incorrectly. When computing F, you need to be summing over x and y, which you are not doing. Here's how to rectify that:
F = zeros(M, N);
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=F(u+1,v+1) + f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Secondly, in the inverse transform, your bracketing is incorrect. It should be 1/(M*N) not (1/M*N).
As an aside, at the cost of a bit more memory, you can speed up the computation by not nesting so many loops. Namely, when computing the FFT, do the following instead
x = (1:1:M)'; % x is a column vector
y = (1:1:N) ; % y is a row vector
for u = 0:1:M-1
for v = 0:1:N-1
F2(u+1,v+1) = sum(f .* exp(-2i * pi * (u*(x-1)/M + v*(y-1)/N)), 'all');
end
end
To take this method to the extreme, i.e. not using any loops at all, you would do the following (though this is not recommended, since you would lose code readability and the memory cost would increase exponentially)
x = (1:1:M)'; % x is in dimension 1
y = (1:1:N) ; % y is in dimension 2
u = permute(0:1:M-1, [1, 3, 2]); % x-freqs in dimension 3
v = permute(0:1:N-1, [1, 4, 3, 2]); % y-freqs in dimension 4
% sum the exponential terms in x and y, which are in dimensions 1 and 2.
% If you are using r2018a or older, the below summation should be
% sum(sum(..., 1), 2)
% instead of
% sum(..., [1,2])
F3 = sum(f .* exp(-2i * pi * (u.*(x-1)/M + v.*(y-1)/N)), [1, 2]);
% The resulting array F3 is 1 x 1 x M x N, to make it M x N, simply shiftdim or squeeze
F3 = squeeze(F3);
I'm using MATLAB to make a function that returns the probability mass function (PMF) for a Geometric distribution when I enter the values of p, q, and the number of attempts (x) as the inputs.
My function:
function Probability = Geometric(p, q, x)
Probability = p*q^x-1
Now whenever I try to calculate the probability by typing in the values of p, q, and x, such as:
Geometric(0.5, 0.5, 1),
The exact error:
Geometric(0.5,0.5,1)
??? Undefined function or method 'Geometric' for input arguments of type 'double'.
I've tried changing functions, and reducing them to one input and one output.
I expect the probabilities to be calculated, but they just don't.
What's going wrong?
p*q^x-1 % Your original code
Your original code is taking q, raising it the xth power, multiplying it by p, then subtracting 1. This is equivalent to the following code which you certainly didn't intend.
(p*(q^x)) - 1 % What your code was doing written differently
Considering order of operations, the correction is easy.
p*q^(x-1) % Your corrected code
Another possible error source is your function is not saved as a standalone m-file "Geometric.m" which must also be on your MATLAB path (MATLAB has to "see" it). If you have your function file "MyFunction.m" stored in a folder, you can add that folder to MATLAB's visible path with one line (or manually navigate there). For more details, see how to create a function.
mypathtoMyFunction = 'C:\Users\SonnyJordan\Documents\SweetCode\FunctionFolder';
path(path,'mypathtoMyFunction')
A Full Solution (3 approaches)
From your parameterization of the Geometric distribution, you're wanting the support on {1, 2, 3, 4, ...}.
Two things. (1) I'd recommend an anonymous function for something like this. (2) There really isn't a need to separate p and q as separate variables since p + q = 1 and therefore one determines the other (i.e. q = 1-p).
Approach 1: Anonymous function
% MATLAB R2018b
geopmfh =#(p,k) p.*((1-p).^(k-1)); % Define pmf
k = 5; % Number of trials
p = 0.2; % Prob("Success" on trial)
geopmfh(p,k) % Probability
Above code is fully vectorized so you could pass it vectors and/or arrays of inputs.
A quick check to validate it is a valid probability mass function (pmf).
M = 500;
sum(geopmfh(p,[1:M])) % should return 1 if M large enough
Approach 2: Function (w/ error checking)
As an aside, making a function in MATLAB would make a lot of sense if you wanted to add error checking on the function inputs to ensure k is a positive integer and that p is between [0 1].
function [pmf] = geopmf(p,k)
%GEOPMF Calculates pmf for Geometric(p,k) distribution on {1,2,3,...}
% pmf = geopmf(p,k)
% p = n x d matrix of n d-dimensional success probabilities; must be [0,1]
% k = m x d matrix of m d-dimensional numbers of trials
% pmf = n x m matrix of probabilities
%
% Examples:
% k = 4; p = .5;
% pmf = geopmf(p,k) % pmf = 0.0625
% Input Error Checking ****************************************************
if isempty(p) | isempty(k), pmf = []; return, end
if nargin ~= 2, error('Function requires two inputs.'), end
if p < 0 | p > 1, error('p must be between 0 and 1.'), end
if k < 1 | ~isint(k), error('k must be positive integer & k > 0.'), end % with this parameterization
n = size(p,1); d = size(p,2);
m = size(k,1);
if isempty(p) | ~isnumeric(p) | ~ismatrix(p)
error('p must be non-empty numeric scalar, vector, or 2-D matrix.');
elseif isempty(k) | ~isnumeric(k) | ~ismatrix(k)
error('k must be non-empty numeric scalar, vector, or 2-D matrix.');
elseif size(k,2) ~=d
error('Rows of p and k must have same dimensions.');
end
% End (Input Error Checking) **********************************************
pmf = p.*((1-p).^(k-1));
end
Approach 3: MATLAB's built-in function
If you have the Statistics toolbox, MATLAB has a function for this already called geopdf but note it is parameterized according to the other "version" with support {0, 1, 2, ...} (see wiki page).
p.*((1-p).^k) % The other parameterization
geopdf(k,p) % Note order of inputs
You can correct for that by adjusting your input.
geopdf(k-1,p) % Subtract 1 trial
Code tested with MATLAB R2018b.
My question may be a simple one but I could not think of a logical explanation for my question:
When I use
rref(hilb(8)), rref(hilb(9)), rref(hilb(10)), rref(hilb(11))
it gives me the result that I expected, a unit matrix.
However when it comes to the
rref(hilb(12))
it does not give a nonsingular matrix as expected. I used Wolfram and it gives the unit matrix for the same case so I am sure that it should have given a unit matrix. There may be a round off error or something like that but then 1/11 or 1/7 have also some troublesome decimals
so why does Matlab behave like this when it comes to 12?
It indeed seems like a precision error. This makes sense as the determinant of Hilbert matrix of order n tends to 0 as n tends to infinity (see here). However, you can use rref with tol parameter:
[R,jb] = rref(A,tol)
and take tol to be very small to get more precise results. For example, rref(hilb(12),1e-20)
will give you identity matrix.
EDIT- more details regarding the role of the tol parameter.
The source code of rref is provided at the bottom of the answer. The tol is used when we search for a maximal element in absolute value in a certain part of a column, to find the pivot row.
% Find value and index of largest element in the remainder of column j.
[p,k] = max(abs(A(i:m,j))); k = k+i-1;
if (p <= tol)
% The column is negligible, zero it out.
A(i:m,j) = zeros(m-i+1,1);
j = j + 1;
If all the elements are smaller than tol in absolute value, the relevant part of the column is filled by zeros. This seems to be where the precision error for rref(hilb(12)) occurs. By reducing the tol we avoid this issue in rref(hilb(12),1e-20).
source code:
function [A,jb] = rref(A,tol)
%RREF Reduced row echelon form.
% R = RREF(A) produces the reduced row echelon form of A.
%
% [R,jb] = RREF(A) also returns a vector, jb, so that:
% r = length(jb) is this algorithm's idea of the rank of A,
% x(jb) are the bound variables in a linear system, Ax = b,
% A(:,jb) is a basis for the range of A,
% R(1:r,jb) is the r-by-r identity matrix.
%
% [R,jb] = RREF(A,TOL) uses the given tolerance in the rank tests.
%
% Roundoff errors may cause this algorithm to compute a different
% value for the rank than RANK, ORTH and NULL.
%
% Class support for input A:
% float: double, single
%
% See also RANK, ORTH, NULL, QR, SVD.
% Copyright 1984-2005 The MathWorks, Inc.
% $Revision: 5.9.4.3 $ $Date: 2006/01/18 21:58:54 $
[m,n] = size(A);
% Does it appear that elements of A are ratios of small integers?
[num, den] = rat(A);
rats = isequal(A,num./den);
% Compute the default tolerance if none was provided.
if (nargin < 2), tol = max(m,n)*eps(class(A))*norm(A,'inf'); end
% Loop over the entire matrix.
i = 1;
j = 1;
jb = [];
while (i <= m) && (j <= n)
% Find value and index of largest element in the remainder of column j.
[p,k] = max(abs(A(i:m,j))); k = k+i-1;
if (p <= tol)
% The column is negligible, zero it out.
A(i:m,j) = zeros(m-i+1,1);
j = j + 1;
else
% Remember column index
jb = [jb j];
% Swap i-th and k-th rows.
A([i k],j:n) = A([k i],j:n);
% Divide the pivot row by the pivot element.
A(i,j:n) = A(i,j:n)/A(i,j);
% Subtract multiples of the pivot row from all the other rows.
for k = [1:i-1 i+1:m]
A(k,j:n) = A(k,j:n) - A(k,j)*A(i,j:n);
end
i = i + 1;
j = j + 1;
end
end
% Return "rational" numbers if appropriate.
if rats
[num,den] = rat(A);
A=num./den;
end
This question already has answers here:
Random numbers that add to 100: Matlab
(4 answers)
Closed 7 years ago.
I am looking how to pick 10 positive non-zero elements in 1x10 array randomly whose sum is 1
Example :
A=[0.0973 0.1071 0.0983 0.0933 0.1110 0.0942 0.1062 0.0970 0.0981 0.0974]
Note: If we sum the elements in above matrix it will be 1. I need matlab to generate a matrix like this randomly
Try using Roger's fex submission: http://www.mathworks.com/matlabcentral/fileexchange/9700-random-vectors-with-fixed-sum
Here is a copy of the content of the file (in case the link dies).
All the credit obviously goes to the original poster Roger Stafford:
function [x,v] = randfixedsum(n,m,s,a,b)
% [x,v] = randfixedsum(n,m,s,a,b)
%
% This generates an n by m array x, each of whose m columns
% contains n random values lying in the interval [a,b], but
% subject to the condition that their sum be equal to s. The
% scalar value s must accordingly satisfy n*a <= s <= n*b. The
% distribution of values is uniform in the sense that it has the
% conditional probability distribution of a uniform distribution
% over the whole n-cube, given that the sum of the x's is s.
%
% The scalar v, if requested, returns with the total
% n-1 dimensional volume (content) of the subset satisfying
% this condition. Consequently if v, considered as a function
% of s and divided by sqrt(n), is integrated with respect to s
% from s = a to s = b, the result would necessarily be the
% n-dimensional volume of the whole cube, namely (b-a)^n.
%
% This algorithm does no "rejecting" on the sets of x's it
% obtains. It is designed to generate only those that satisfy all
% the above conditions and to do so with a uniform distribution.
% It accomplishes this by decomposing the space of all possible x
% sets (columns) into n-1 dimensional simplexes. (Line segments,
% triangles, and tetrahedra, are one-, two-, and three-dimensional
% examples of simplexes, respectively.) It makes use of three
% different sets of 'rand' variables, one to locate values
% uniformly within each type of simplex, another to randomly
% select representatives of each different type of simplex in
% proportion to their volume, and a third to perform random
% permutations to provide an even distribution of simplex choices
% among like types. For example, with n equal to 3 and s set at,
% say, 40% of the way from a towards b, there will be 2 different
% types of simplex, in this case triangles, each with its own
% area, and 6 different versions of each from permutations, for
% a total of 12 triangles, and these all fit together to form a
% particular planar non-regular hexagon in 3 dimensions, with v
% returned set equal to the hexagon's area.
%
% Roger Stafford - Jan. 19, 2006
% Check the arguments.
if (m~=round(m))|(n~=round(n))|(m<0)|(n<1)
error('n must be a whole number and m a non-negative integer.')
elseif (s<n*a)|(s>n*b)|(a>=b)
error('Inequalities n*a <= s <= n*b and a < b must hold.')
end
% Rescale to a unit cube: 0 <= x(i) <= 1
s = (s-n*a)/(b-a);
% Construct the transition probability table, t.
% t(i,j) will be utilized only in the region where j <= i + 1.
k = max(min(floor(s),n-1),0); % Must have 0 <= k <= n-1
s = max(min(s,k+1),k); % Must have k <= s <= k+1
s1 = s - [k:-1:k-n+1]; % s1 & s2 will never be negative
s2 = [k+n:-1:k+1] - s;
w = zeros(n,n+1); w(1,2) = realmax; % Scale for full 'double' range
t = zeros(n-1,n);
tiny = 2^(-1074); % The smallest positive matlab 'double' no.
for i = 2:n
tmp1 = w(i-1,2:i+1).*s1(1:i)/i;
tmp2 = w(i-1,1:i).*s2(n-i+1:n)/i;
w(i,2:i+1) = tmp1 + tmp2;
tmp3 = w(i,2:i+1) + tiny; % In case tmp1 & tmp2 are both 0,
tmp4 = (s2(n-i+1:n) > s1(1:i)); % then t is 0 on left & 1 on right
t(i-1,1:i) = (tmp2./tmp3).*tmp4 + (1-tmp1./tmp3).*(~tmp4);
end
% Derive the polytope volume v from the appropriate
% element in the bottom row of w.
v = n^(3/2)*(w(n,k+2)/realmax)*(b-a)^(n-1);
% Now compute the matrix x.
x = zeros(n,m);
if m == 0, return, end % If m is zero, quit with x = []
rt = rand(n-1,m); % For random selection of simplex type
rs = rand(n-1,m); % For random location within a simplex
s = repmat(s,1,m);
j = repmat(k+1,1,m); % For indexing in the t table
sm = zeros(1,m); pr = ones(1,m); % Start with sum zero & product 1
for i = n-1:-1:1 % Work backwards in the t table
e = (rt(n-i,:)<=t(i,j)); % Use rt to choose a transition
sx = rs(n-i,:).^(1/i); % Use rs to compute next simplex coord.
sm = sm + (1-sx).*pr.*s/(i+1); % Update sum
pr = sx.*pr; % Update product
x(n-i,:) = sm + pr.*e; % Calculate x using simplex coords.
s = s - e; j = j - e; % Transition adjustment
end
x(n,:) = sm + pr.*s; % Compute the last x
% Randomly permute the order in the columns of x and rescale.
rp = rand(n,m); % Use rp to carry out a matrix 'randperm'
[ig,p] = sort(rp); % The values placed in ig are ignored
x = (b-a)*x(p+repmat([0:n:n*(m-1)],n,1))+a; % Permute & rescale x
return
If I have a function for example :
k=1:100
func=#(s) sum(c(k)-exp((-z(k).^2./s)))
where c and z are matrices with same size (for example 1x100) , is there any way to use fminsearch to find the "s" value?
fminsearch needs an initial condition in the second parameter, not boundary conditions (though some of the options may support boundaries).
Just call
fminsearch(func,-0.5)
Where you saw examples passing in a vector, was a multidimensional search across multiple coefficients, and the vector was the initial value of each coefficient. Not limits on the search space.
You can also use
fminbnd(func, -0.5, 1);
which performs constrained minimization.
But I think you should minimize the norm of the error, not the sum (minimizing the sum leads to a large error magnitude -- very very negative).
If you have the Optimization Toolbox, then lsqnonlin could be useful.
I guess you would like to find argmin of your symbolic function, use
Index of max and min value in an array
OR
ARGMAX/ARGMIN by Marco Cococcioni:
function I = argmax(X, DIM)
%ARGMAX Argument of the maximum
% For vectors, ARGMAX(X) is the indix of the smallest element in X. For matrices,
% MAX(X) is a row vector containing the indices of the smallest elements from each
% column. This function is not supported for N-D arrays with N > 2.
%
% It is an efficient replacement to the use of [Y,I] = MAX(X,[],DIM);
% See ARGMAX_DEMO for a speed comparison.
%
% I = ARGMAX(X,DIM) operates along the dimension DIM (DIM can be
% either 1 or 2).
%
% When complex, the magnitude ABS(X) is used, and the angle
% ANGLE(X) is ignored. This function cannot handle NaN's.
%
% Example:
% clc
% disp('If X = [2 8 4; 7 3 9]');
% disp('then argmax(X,1) should be [2 1 2]')
% disp('while argmax(X,2) should be [2 3]''. Now we check it:')
% disp(' ');
% X = [2 8 4;
% 7 3 9]
% argmax(X,1)
% argmax(X,2)
%
% See also ARGMIN, ARGMAXMIN_MEX, ARGMAX_DEMO, MIN, MAX, MEDIAN, MEAN, SORT.
% Copyright Marco Cococcioni, 2009.
% $Revision: 1.0 $ $Date: 2009/02/16 19:24:01$
if nargin < 2,
DIM = 1;
end
if length(size(X)) > 2,
error('Function not provided for N-D arrays when N > 2.');
end
if (DIM ~=1 && DIM ~= 2),
error('DIM has to be either 1 or 2');
end
if any(isnan(X(:))),
error('Cannot handle NaN''s.');
end
if not(isreal(X)),
X = abs(X);
end
max_NOT_MIN = 1; % computes argmax
I = argmaxmin_mex(X, DIM, max_NOT_MIN);