Related
How can I do below calculations (finding C) without using "for loop"?
[4, 2, 1, 7;
A = 0, 3, 4, 0;
8, 0, 10, 12;
11, 6, 2, 5];
[1, 0, 0, 4;
B = 0, 3, 2, 0;
5, 0, 8, 10;
7, 2, 1, 2];
C(i,j)= B(i,j-1) - B(i,j+1) + A(i,j+1); %if j is not equal to 4(number of columns) and it is not equal to 1
C(i,j)= B(i,4) - B(i,j+1) + A(i,j+1); %if j is equal to 1
C(i,j)= B(i,j-1) - B(i,1) + A(i,1); %if j is equal to 4(number of columns)
You can specify an array as index to work on multiple element at the same time:
A=[4,2,1,7;0,3,4,0;8,0,10,12;11,6,2,5];
B=[1,0,0,4;0,3,2,0;5,0,8,10;7,2,1,2];
C = zeros(size(A));
C(:,2:end-1) = B(:,1:end-2) - B(:,3:end) + A(:,3:end); %if j is not equal to 4(number of columns) and it is not equal to 1
j = 1;
C(:,j)= B(:,4) - B(:,j+1) + A(:,j+1); %if j is equal to 1
j = 4;
C(:,j)= B(:,j-1) - B(:,1) + A(:,1); %if j is equal to 4(number of columns)
I have the following MATLAB code which does the following.
Suppose I have 3 investments of 10 units. Matrix exits has a value of 1 if the investment is exited. Matrix pos tells me the return of each of the three investments. Then the last line of the code computes the total money earned on exited investments.
I am trying to write a similar lines of code in Fortran. Also below my Fortran attempt.
clear all
X = 10;
ret(1,1) = -0.05;
ret(2,1) = 0.15;
exits = [1 0 1];
pos = [1 1 2];
ret1 = (pos == 1) .* ret(1,1) + (pos == 2) .* ret(2,1);
inv = sum(X * ones(1,3) .* (exits) .* exp(ret1));
My Fortran code:
PROGRAM Matlab_replication
IMPLICIT NONE
INTEGER, DIMENSION(1,1) :: X = 10
REAL, DIMENSION(2,1) :: ret
INTEGER, DIMENSION(1,3) :: exits
INTEGER, DIMENSION(1,3) :: pos
REAL, DIMENSION(1,3) :: ret1
REAL, DIMENSION(1,3) :: ret2
REAL, DIMENSION(1,3) :: ones = 1.0
REAL, DIMENSION(1,3) :: X1
REAL :: inv
ret(1,1) = -0.05
ret(2,1) = 0.15
exits(1,1) = 1
exits(1,2) = 0
exits(1,3) = 1
pos(1,1) = 1
pos(1,2) = 1
pos(1,3) = 2
X1(1,:) = X(1,1) * ones(1,:)
ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)
ret2(1,:) = exp(ret1(1,:))
inv = sum(X1(1,:) * exits(1,:)* ret2(1,:))
end program
Somehow the line ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1) is not delivering what I am looking for. Also I had to create two additional variables versus the MATLAB code X1 and ret2. Any way to avoid this?
This may be an extended comment rather than an answer ...
The expression
(pos == 1) * ret(1,1) + (pos == 2) * ret(2,1)
mixes types in a way unacceptable to Fortran. The first term, (pos == 1) is of type logical and evaluates to either .true. or .false.. That is not something that can then be multiplied by a number, or by anything else for that matter.
Actually, matters are slightly worse than I first realised, since pos is an array. Do you expect an array of results, or for a single result from that term ?
I'm not sure what you are trying to do, but you'll need to transform (pos == 1) to a number somehow if you want to multiply it. It is fairly easy to write a Fortran function to return 1 (or whatever you want) for a .true. input, and another number for a .false. input.
Finally I'm surprised that your Fortran code is returning anything at all as you assert in your comment. I'm surprised that it compiles.
pos == 1 in Matlab returns an array consisting of 1 and 0, while it returns an array consisting of .true. and .false. in Fortran (as suggested by #HighPerformanceMark). So, you need to take care of this difference somehow. There are various ways for this, and one such example is like this:
real :: ret( 2 ), vtmp( 3 ), inv, x
integer :: exits( 3 ), pos( 3 )
x = 10.0
ret = [ -0.05, 0.15 ]
exits = [ 1, 0, 1 ]
pos = [ 1, 1, 2 ]
vtmp = abs([ integer:: pos == 1 ]) * ret( 1 ) + abs([ integer:: pos == 2 ]) * ret( 2 )
inv = sum( x * exits * exp( vtmp ) )
where I have assumed gfortran or Intel fortran and changed all 2-D arrays in the original code to 1-D arrays for simplicity.
For other compilers, the above code may be syntactically not allowed; in that case it may be useful to define some utility functions like
module filter_mod
implicit none
interface filter
module procedure filter1D, filter2D
end interface
contains
function filter1D( mask ) result( ints )
logical :: mask(:)
integer :: ints( size( mask ) )
ints = 0 ; where( mask ) ints = 1
end function
function filter2D( mask ) result( ints )
logical :: mask(:,:)
integer :: ints( size( mask, 1 ), size( mask, 2 ) )
ints = 0 ; where( mask ) ints = 1
end function
end module
and modify the original code as
PROGRAM Matlab_replication
use filter_mod
IMPLICIT NONE
...
ret1 = filter( pos == 1 ) * ret(1,1) + filter( pos == 2 ) * ret(2,1)
inv = sum( X(1,1) * exits * exp( ret1 ) )
which hopefully makes the translation from Matlab straight-forward.
EDIT: Actually, use of merge() function seems to be the simplest solution (thanks to #francescalus). With this function the first and second codes can be rewritten as
vtmp = merge( ret(1), 0.0, pos == 1 ) + merge( ret(2), 0.0, pos == 2 )
and
ret1 = merge( ret(1,1), 0.0, pos == 1 ) + merge( ret(2,1), 0.0, pos == 2 )
Because merge() returns an array with the same shape as pos, it is very straight-forward to use even for multi-dimensional arrays.
I tried the following:
spline= interpolate.InterpolatedUnivariateSpline(X, Y, k=3)
coefs= spline.get_coeffs()
With five values in each of X and Y, I ended up with coefs also having
five values. Given that five data points implies four spline sections, and
that a cubic polynomial has four coefficients, I would have expected to get
four times four= 16 coefficients. Does anyone know how to interpret the values that are returned by the get_coeffs method? Is there any place where this is documented?
These are not the coefficients of x, x**2, and so forth: such monomials are ill-suited to representing splines. Rather, they are coefficients of B-splines which are computed for the specific grid on which interpolation is done. The number of B-splines involved is equal to the number of data points, and so is the number of coefficients. As an example, suppose we want to interpolate these data:
xv = [0, 1, 2, 3, 4, 5]
yv = [3, 6, 5, 7, 9, 1]
Begin with the simpler case of degree k=1 (piecewise linear spline). Then the B-splines are these "triangular hat" functions:
There are 6 of them. Each of them is equal to 1 at "its" grid point, and 0 at all other grid points. This makes it really easy to write the interpolating spline: it is y[0]*b[0] + ... + y[5]*b[5]. And indeed, get_coeffs shows the coefficients are the the y-values themselves.
InterpolatedUnivariateSpline(xv, yv, k=1).get_coeffs() # [ 3., 6., 5., 7., 9., 1.]
Cubic splines
Now it gets hairy, because we need "hats" that are smooth, rather than pointy as those above. The smoothness requirement forces them to be wider, so each B-spline has nonzero values on several grid points. (Technicality: a cubic B-spline has nonzero values at up to 3 knots, but on the chart below, 1 and 4, despite being grid points, are not knots due to so-called "not a knot" condition. Never mind this.) Here are the B-splines for our grid:
To get these, I used older methods splrep and splev of scipy.interpolate, which call the same fitpack routines under the hood. The coefficient vector here is the second entry of the tuple tck; I modify it to have one 1 and the rest 0, thus creating a basis spline (b-spline).
k = 3
tck = splrep(xv, yv, s=0, k=k)
xx = np.linspace(min(xv), max(xv), 500)
bsplines = []
for j in range(len(xv)):
tck_mod = (tck[0], np.arange(len(xv)+2*k-2) == j, k)
bsplines.append(splev(xx, tck_mod))
plt.plot(xx, bsplines[-1])
Now that we have a list bsplines, we can use the coefficients returned by get_coeffs to put them together ourselves into an interpolating spline:
coeffs = InterpolatedUnivariateSpline(xv, yv, k=3).get_coeffs()
interp_spline = sum([coeff*bspline for coeff, bspline in zip(coeffs, bsplines)])
plt.plot(xx, interp_spline)
If you want a formula for the pieces of these B-splines, the Cox-de Boor recursion formula on B-splines can help but these are a chore to compute by hand.
SymPy can give formulas for B-splines, but there is a little twist. One should pass in a padded set of knots, by repeating the end values like
[0, 0, 0, 0, 2, 3, 5, 5, 5, 5]
This is because at 0 and 5 all four coefficients change values, while at 1 and 4 none of them do, so they are omitted ("not a knot"). (Also, the current version of SymPy (1.1.1) has an issue with repeated knots, but this will be fixed in the next version.)
from sympy import symbols, bspline_basis_set, plot
x = symbols('x')
xv_padded = [0, 0, 0, 0, 2, 3, 5, 5, 5, 5]
bs = bspline_basis_set(3, xv_padded, x)
Now bs is an array of scary-looking piecewise formulas:
[Piecewise((-x**3/8 + 3*x**2/4 - 3*x/2 + 1, (x >= 0) & (x <= 2)), (0, True)),
Piecewise((19*x**3/72 - 5*x**2/4 + 3*x/2, (x >= 0) & (x <= 2)), (-x**3/9 + x**2 - 3*x + 3, (x >= 2) & (x <= 3)), (0, True)),
Piecewise((-31*x**3/180 + x**2/2, (x >= 0) & (x <= 2)), (11*x**3/45 - 2*x**2 + 5*x - 10/3, (x >= 2) & (x <= 3)), (-x**3/30 + x**2/2 - 5*x/2 + 25/6, (x >= 3) & (x <= 5)), (0, True)),
Piecewise((x**3/30, (x >= 0) & (x <= 2)), (-11*x**3/45 + 5*x**2/3 - 10*x/3 + 20/9, (x >= 2) & (x <= 3)), (31*x**3/180 - 25*x**2/12 + 95*x/12 - 325/36, (x >= 3) & (x <= 5)), (0, True)),
Piecewise((x**3/9 - 2*x**2/3 + 4*x/3 - 8/9, (x >= 2) & (x <= 3)), (-19*x**3/72 + 65*x**2/24 - 211*x/24 + 665/72, (x >= 3) & (x <= 5)), (0, True)),
Piecewise((x**3/8 - 9*x**2/8 + 27*x/8 - 27/8, (x >= 3) & (x <= 5)), (0, True))]
How do I create a user defined function in PostgreSQL that acts like the C function pair defined below?
Also, which type of function should I use and why?
(A) query language (SQL) function
(B) procedural language function
(C) internal function
(D) C-language function
(E) None of the above
Bonus points for implementations in both SQL & PL/pgSQL languages.
#include <stdio.h>
#include <math.h>
int pair(int x, int y)
{
int z;
if (x < y) {
z = x * (y-1);
y = y - x - 2;
} else {
z = (x-1) * y;
y = x - y - 2;
}
return z + pow(y, 2) / 4;
}
// TESTING
void test(int x, int y, int z)
{
printf("%s", pair(x, y) == z ? "." : "F");
}
int main(void)
{
test(1, 2, 1);
test(1, 3, 2);
test(1, 4, 3);
test(1, 5, 5);
test(1, 6, 7);
test(1, 7, 10);
test(1, 8, 13);
test(1, 9, 17);
test(2, 3, 4);
test(2, 4, 6);
test(2, 5, 8);
test(2, 6, 11);
test(2, 7, 14);
test(2, 8, 18);
test(2, 9, 22);
printf("\n");
return 0;
}
Use an SQL CASE statement:
CASE WHEN x < y THEN
x * (y - 1) + ((y - x - 2)^2)::int / 4
ELSE
(x - 1) * y + ((x - y - 2)^2)::int / 4
END
The operator ^ as well as the function power() return double precision. So I cast to int to match your question.
Wrapped into a plain SQL function (with operator ^):
CREATE OR REPLACE FUNCTION pair1(x int, y int)
RETURNS int AS
$func$
SELECT CASE WHEN x < y THEN
x * (y - 1) + ((y - x - 2)^2)::int / 4
ELSE
(x - 1) * y + ((x - y - 2)^2)::int / 4
END
$func$ LANGUAGE sql IMMUTABLE;
In Postgres 9.1 or older you have tro reference input columns with positional parameters $1, $2 instead.
The same as PL/pgSQL function (with function power()):
CREATE OR REPLACE FUNCTION pair2(x int, y int)
RETURNS int AS
$func$
BEGIN
RETURN CASE WHEN x < y THEN
x * (y - 1) + power(y - x - 2, 2)::int / 4
ELSE
(x - 1) * y + power(x - y - 2, 2)::int / 4
END;
END
$func$ LANGUAGE plpgsql IMMUTABLE;
SQL Fiddle demo.
I depends, but generally I would use a simple SQL function. And don't forget to declare it IMMUTABLE. This allows various performance optimizations in bigger queries and using it in functional indexes. Example with more details:
Does PostgreSQL support "accent insensitive" collations?
SQL is simpler. If x < y it will return the first element of the array else the second
create or replace function pair(x int, y int)
returns double precision as $$
select (array[
x * (y - 1) + power(y - x - 2, 2) / 4,
(x - 1) * y + power(x - y - 2, 2) / 4
])[(not x < y)::int + 1]
;
$$ language sql;
select
pair(1, 2) = 1,
pair(1, 3) = 2,
pair(1, 4) = 3,
pair(1, 5) = 5,
pair(1, 6) = 7,
pair(1, 7) = 10,
pair(1, 8) = 13,
pair(1, 9) = 17,
pair(2, 3) = 4,
pair(2, 4) = 6,
pair(2, 5) = 8,
pair(2, 6) = 11,
pair(2, 7) = 14,
pair(2, 8) = 18,
pair(2, 9) = 22
;
A boolean casted to integer yields 1 or 0. As Postgresql array index starts at 1 then 1 is added to the result of the casting.
So I want all 6 elements of the third column to go into a vector of 6 elements. How would I do this?
You can use the (:) operator to collapse an nD matrix to a single vector. For your example, do something like this:
mat = (50 < seals(:, 3, 1)) & (seals(:, 3, 1) < 100)
vec = mat(:);
First of all, you cannot use the comparison operator to compare against an interval the way you do. I suggest you try to run this bit of code:
x = 1:10;
4 < x < 7
On my system I get the answer
ans =
1 1 1 1 1 1 1 1 1 1
which, I suspect, is not what you want. The solution is to divide your condition like this
(4 < x) & (x < 7)
giving
ans =
0 0 0 0 1 1 0 0 0 0
as expected.
Now, back to your actual question. If you know how many elements the resulting vector should have, then you can use reshape:
mask = (50 < seals(:, 3, 1)) & (seals(:, 3, 1) < 100)
x = nanmean(seals(mask, :, :));
v = reshape(x(:, 3, :), 6, 1);
However, in this case you're using a search criteria to find which values to select and therefore probably don't know beforehand how long the final vector will be. Another option is then to first retrieve the values you want and then reshape them into a vector using the colon operator (:) like this:
mask = (50 < seals(:, 3, 1)) & (seals(:, 3, 1) < 100)
x = nanmean(seals(mask, :, :));
y = x(:, 3, :);
v = y(:);
In both cases I've also introduced a separate selection mask to slightly increase readability.