Wrong Results for Matrix Diagonalization - fortran

I try and diagonalize the matrix:
In my analysis, I set $\hbar = 1$. The code is:
MODULE FUNCTION_CONTAINER
IMPLICIT NONE
SAVE
INTEGER, PARAMETER :: DBL = SELECTED_REAL_KIND(P = 15,R = 200)
COMPLEX(KIND = DBL), PARAMETER :: IMU = (0.0D0, 1.0D0)
REAL(KIND = DBL), PARAMETER :: S = 1.0D0
INTEGER, PARAMETER :: TEMP1 = NINT((2.0D0 * S) + 1.0D0)
INTEGER, PARAMETER :: DIMJ = TEMP1
INTEGER, PARAMETER :: TEMP2 = TEMP1*TEMP1
INTEGER, PARAMETER :: DIMMAT = TEMP2
CONTAINS
INTEGER FUNCTION KRONDELTAR(K,L)
IMPLICIT NONE
REAL(KIND = DBL), INTENT(IN)::K,L
REAL(KIND = DBL) :: TEMP
TEMP = DABS(K - L)
IF (TEMP < 0.000001D0) THEN
KRONDELTAR = 1
ELSE
KRONDELTAR = 0
END IF
END FUNCTION KRONDELTAR
SUBROUTINE MATJplus(MATOUT)
IMPLICIT NONE
COMPLEX(KIND = DBL),DIMENSION(DIMJ,DIMJ),INTENT(OUT)::MATOUT
INTEGER::K,L
REAL(KIND = DBL)::M,MP
DO K = 1,DIMJ
DO L = 1,DIMJ
MP = (S + 1.0D0) - L
M = (S + 1.0D0) - K
MATOUT(K,L) = DSQRT(S * (S + 1.0D0) - M * (M + 1.0D0)) * KRONDELTAR(MP,M + 1)
END DO
END DO
END SUBROUTINE MATJplus
SUBROUTINE MATJminus(MATOUT)
IMPLICIT NONE
COMPLEX(KIND = DBL),DIMENSION(DIMJ,DIMJ),INTENT(OUT)::MATOUT
INTEGER::K,L
REAL(KIND = DBL)::MP,M
DO K = 1,DIMJ
DO L = 1,DIMJ
MP = (S + 1) - L
M = (S + 1) - K
MATOUT(K,L) = DSQRT(S* (S + 1.0D0) - M * (M - 1.0D0)) * KRONDELTAR(MP,M - 1)
END DO
END DO
END SUBROUTINE MATJminus
SUBROUTINE MATJy(MATOUT)
IMPLICIT NONE
COMPLEX(KIND = DBL),DIMENSION(DIMJ,DIMJ),INTENT(OUT)::MATOUT
COMPLEX(KIND = DBL),DIMENSION(DIMJ,DIMJ)::Jp,Jm
CALL MATJplus(Jp)
CALL MATJminus(Jm)
MATOUT = (Jp - Jm)/(2.0D0 * IMU)
END SUBROUTINE MATJy
SUBROUTINE DIAGONALIZEJy(EIGENSTATESJy,EIGENVALUESJY)
IMPLICIT NONE
COMPLEX(KIND = DBL),DIMENSION(DIMJ,DIMJ),INTENT(OUT)::EIGENSTATESJy
REAL(KIND = DBL), DIMENSION(DIMJ),INTENT(OUT)::EIGENVALUESJY
COMPLEX(KIND = DBL),DIMENSION(DIMJ,DIMJ)::JyTEMP,Jy
COMPLEX(KIND = DBL),DIMENSION(2*DIMJ)::D1
REAL(KIND = DBL),DIMENSION(3*DIMJ - 2)::D2
INTEGER::D3
CALL MATJy(Jy)
JyTEMP = Jy
CALL ZHEEV('V','U',DIMJ,JyTEMP,DIMJ,EIGENVALUESJy,D1,2*DIMJ,D2,D3)
EIGENSTATESJy = JyTEMP
END SUBROUTINE DIAGONALIZEJy
END MODULE FUNCTION_CONTAINER
PROGRAM TEST
USE FUNCTION_CONTAINER
IMPLICIT NONE
COMPLEX(KIND = DBL), DIMENSION(DIMJ,DIMJ) :: EIGENSTATESJy, MatrixJy
REAL(KIND = DBL), DIMENSION(DIMJ) :: EIGENVALUESJy
CALL DIAGONALIZEJy(EIGENSTATESJy,EIGENVALUESJY)
CALL MATJy(MatrixJy)
OPEN(1, FILE = 'EIGENVALUESJy.DAT')
OPEN(2, FILE = 'EIGENSTATESJyREAL.DAT')
OPEN(3,FILE = 'EIGENSTATESJyCOMPLEX.DAT')
WRITE (1,*) EIGENVALUESJy
WRITE (2,*) REAL(EIGENSTATESJy)
WRITE (3,*) AIMAG(EIGENSTATESJy)
CLOSE(1)
CLOSE(2)
CLOSE(3)
END PROGRAM TEST
Up till the subroutine DIAGONALIZEJy, I am simply constructing the matrix stated above. One can easily check Fortran constructs is neatly by simply writing the result from the subroutine MatJy. I transfer the data to Mathematica. The results are:
{{-1., -9.19403*10^-17, 1.}}
This is the list of eigenvalues. The list of eigenvectors is:
{{-0.5 + 0. I, 0. - 0.707107 I, 0.5 + 0. I}, {0.707107 + 0. I,
0. + 1.04083*10^-16 I, 0.707107 + 0. I}, {-0.5 + 0. I,
0. + 0.707107 I, 0.5 + 0. I}}
The first eigenvector corresponds to the first eigenvalue (at least that's what I get by printing the column vectors from EigenvectorsJy one by one).
Clearly, the result is wrong. See:
http://www.wolframalpha.com/widgets/view.jsp?id=9aa01caf50c9307e9dabe159c9068c41
I hope the link shows the results for the eigenvalues problem done using a widget. The eigenvalues are correct but all the eigenvectors are way off.
Also, when I run only the subroutine that diagonlizes the matrix in my main program which contains a whole host of other stuff, the results are:
{{0.885212, 0., -0.920222}}
and
{{0.0439691 + 0. I, -0.388918 + 0. I, 0.5 + 0. I}, {0.707107 + 0. I,
0. + 1.04083*10^-16 I, 0.707107 + 0. I}, {-0.5 + 0. I,
0. + 0.707107 I, 0.5 + 0. I}}
As you can see, the non zero eigenvalues are a bit off and the eigenvectors are too (and still incorrect). Why is the main program giving a different result, perhaphs exacerbating the error? Also, in the first place (minimal example, see above), why am I getting wrong answers?
Edit: Apparently, the link doesn't show the results so here's a snippet:

In short, your Jy matrix in the code seems to be the complex conjugate of what is desired (i.e., the image posted in the Question), which results in the eigenvectors that are complex conjugate of the correct ones.
The above error seems to originate from the OP's assumption that list-directed output (as write(*,*) A) prints the matrix elements in the "row-major" order, while in fact they are printed in the "column-major" order (see the comments below). By noting this and correcting the program accordingly, I think the program will work as expected.
More specifically, adding the following utility routine to print a matrix
subroutine printmat( msg, mat )
implicit none
character(*), intent(in) :: msg
complex(DBL), intent(in) :: mat( dimJ, dimJ )
integer i1, i2
print *
print *, msg
do i1 = 1, dimJ
print "(3('(',f10.6,',',f10.6,' ) '))", ( mat( i1, i2 ), i2 = 1,dimJ )
enddo
end subroutine
and checking the value of Jp, Jm, Jy in the subroutine MATJy()
Jp:
( 0.000000, 0.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, 0.000000 )
( 1.414214, 0.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, 0.000000 )
( 0.000000, 0.000000 ) ( 1.414214, 0.000000 ) ( 0.000000, 0.000000 )
Jm:
( 0.000000, 0.000000 ) ( 1.414214, 0.000000 ) ( 0.000000, 0.000000 )
( 0.000000, 0.000000 ) ( 0.000000, 0.000000 ) ( 1.414214, 0.000000 )
( 0.000000, 0.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, 0.000000 )
Jy * sqrt(2):
( 0.000000, 0.000000 ) ( 0.000000, 1.000000 ) ( 0.000000, 0.000000 )
( 0.000000, -1.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, 1.000000 )
( 0.000000, 0.000000 ) ( 0.000000, -1.000000 ) ( 0.000000, 0.000000 )
eigenvaluesJy(1) = -1.000000
eigvec:
( -0.500000, 0.000000 )
( 0.000000, -0.707107 )
( 0.500000, 0.000000 )
eigenvaluesJy(2) = -0.000000
eigvec:
( 0.707107, 0.000000 )
( 0.000000, 0.000000 )
( 0.707107, 0.000000 )
eigenvaluesJy(3) = 1.000000
eigvec:
( -0.500000, 0.000000 )
( 0.000000, 0.707107 )
( 0.500000, 0.000000 )
we see that the above Jy matrix is the complex conjugate of the desired matrix (given as an image in the Question). The reason seems to be that the Jp and Jm matrices are given as the transpose of the correct ones (according to some pages like this and this). For example, if we change their index as
SUBROUTINE MATJplus(MATOUT)
IMPLICIT NONE
COMPLEX(KIND = DBL),DIMENSION(DIMJ,DIMJ),INTENT(OUT)::MATOUT
INTEGER::K,L
REAL(KIND = DBL)::M,MP
DO K = 1,DIMJ
DO L = 1,DIMJ
MP = (S + 1.0D0) - L !! 1, 0, -1 ("m_prime")
M = (S + 1.0D0) - K !! 1, 0, -1 ("m")
!>>> Here, we swap the indices K and L in the LHS
!! MATOUT(K,L) = DSQRT(S * (S + 1.0D0) - M * (M + 1.0D0)) * KRONDELTAR(MP, M + 1)
MATOUT(L,K) = DSQRT(S * (S + 1.0D0) - M * (M + 1.0D0)) * KRONDELTAR(MP, M + 1)
END DO
END DO
call printmat( "Jplus:", matout )
END SUBROUTINE
(and modifying MATJminus() similarly), we obtain the expected result:
Jp:
( 0.000000, 0.000000 ) ( 1.414214, 0.000000 ) ( 0.000000, 0.000000 )
( 0.000000, 0.000000 ) ( 0.000000, 0.000000 ) ( 1.414214, 0.000000 )
( 0.000000, 0.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, 0.000000 )
Jm:
( 0.000000, 0.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, 0.000000 )
( 1.414214, 0.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, 0.000000 )
( 0.000000, 0.000000 ) ( 1.414214, 0.000000 ) ( 0.000000, 0.000000 )
Jy * sqrt(2):
( 0.000000, 0.000000 ) ( 0.000000, -1.000000 ) ( 0.000000, 0.000000 )
( 0.000000, 1.000000 ) ( 0.000000, 0.000000 ) ( 0.000000, -1.000000 )
( 0.000000, 0.000000 ) ( 0.000000, 1.000000 ) ( 0.000000, 0.000000 )
eigenvaluesJy(1) = -1.000000
eigvec:
( -0.500000, 0.000000 )
( 0.000000, 0.707107 )
( 0.500000, 0.000000 )
eigenvaluesJy(2) = -0.000000
eigvec:
( 0.707107, 0.000000 )
( 0.000000, -0.000000 )
( 0.707107, 0.000000 )
eigenvaluesJy(3) = 1.000000
eigvec:
( -0.500000, 0.000000 )
( 0.000000, -0.707107 )
( 0.500000, 0.000000 )
For convenience, here are some matrices taken from the above pages (which can be compared directly with the above Jp, Jm, Jy):

Related

Eigen and glm products produce different results

I am trying to replace glm with eigen in an application I am writing, but I am running into an esoteric problem.
This would be the relevant code:
glm::mat4 EigenToGlmMat(const Eigen::Matrix4f& v)
{
glm::mat4 ret;
ret[0][0] = v(0,0);
ret[0][1] = v(0,1);
ret[0][2] = v(0,2);
ret[0][3] = v(0,3);
ret[1][0] = v(1,0);
ret[1][1] = v(1,1);
ret[1][2] = v(1,2);
ret[1][3] = v(1,3);
ret[2][0] = v(2,0);
ret[2][1] = v(2,1);
ret[2][2] = v(2,2);
ret[2][3] = v(2,3);
ret[3][0] = v(3,0);
ret[3][1] = v(3,1);
ret[3][2] = v(3,2);
ret[3][3] = v(3,3);
return ret;
}
Eigen::Matrix4f mp = camera->GetProjectionMatrix();
Eigen::Matrix4f mv = camera->GetViewMatrix();
mat4 vp_mat = EigenToGlmMat(mp) * EigenToGlmMat(mv);
mat4 tmp = EigenToGlmMat(mp * mv);
cout << glm::to_string(vp_mat) << endl << endl;
cout << glm::to_string(tmp) << endl << endl;
Now consider the lines:
auto mp = camera->GetProjectionMatrix();
auto mv = camera->GetViewMatrix();
mat4 vp_mat = EigenToGlmMat(mp) * EigenToGlmMat(mv);
mat4 tmp = EigenToGlmMat(mp * mv);
Those 2 results should be equivalent, after all they are merely computing a product of matrices and the matrix inputs are the same. However this is the output:
mat4x4(
(2.414213, 0.000000, 0.000000, 0.000000),
(0.000000, -2.414213, 0.000000, 0.000000),
(0.000000, 0.000000, 1.002002, 1.000000),
(0.000000, 0.000000, 4.308809, 4.500000))
mat4x4(
(2.414213, 0.000000, -0.000000, 0.000000),
(0.000000, -2.414213, -0.000000, 0.000000),
(0.000000, 0.000000, 5.502002, -1.000000),
(0.000000, 0.000000, 0.200200, 0.000000))
The only functional difference is that computes the product using glm and the other eigen. How is it possible I am getting different results? Is this an error in Eigen?
It is not a transposition problem btw, this is the output of the 2 matrices before and after being cast by EigenToGlmMat
2.41421 0 0 0
0 2.41421 0 0
0 0 -1.002 -1
0 0 -0.2002 0
1 0 -0 0
0 -1 -0 0
-0 0 -1 0
-0 -0 -6 1
mat4x4(
(2.414213, 0.000000, 0.000000, 0.000000),
(0.000000, 2.414213, 0.000000, 0.000000),
(0.000000, 0.000000, -1.002002, -1.000000),
(0.000000, 0.000000, -0.200200, 0.000000))
mat4x4(
(1.000000, 0.000000, -0.000000, 0.000000),
(0.000000, -1.000000, -0.000000, 0.000000),
(-0.000000, 0.000000, -1.000000, 0.000000),
(-0.000000, -0.000000, -6.000000, 1.000000))
You are unknowingly transposing matrices. When accessing an Eigen::Matrix4f using (i, j), you are accessing row i and column j. glm::mat4's subscript operator returns you a column, so with [i][j] you are accessing column i and row j.
Here's the solution:
glm::mat4 EigenToGlmMat(const Eigen::Matrix4f& v)
{
glm::mat4 result;
for (size_t i = 0; i < 4; ++i) {
for (size_t j = 0; j < 4; ++j) {
result[i][j] = v(j, i);
}
}
return result;
}

OpenVino model outputs zeroes

I have an acoustic model that successfully converted from ONNX to OpenVino. However, in OpenVino this model outputs tensor that consists of zeroes from some position.
#include <iostream>
#include <fstream>
#include <iterator>
#include <inference_engine.hpp>
typedef struct {
float* data;
size_t size;
size_t timeLen;
} Fbank;
using namespace InferenceEngine;
using std::cout;
using std::endl;
void print_arr(std::string text, const float* arr, int l, int r) {
cout << text << endl;
for (int i = l; i < r; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void doInference(ExecutableNetwork& executable_network, const std::string& input_name, const std::string& output_name, Fbank* fbank) {
InferRequest infer_request = executable_network.CreateInferRequest();
InferenceEngine::TensorDesc tDesc(InferenceEngine::Precision::FP32,
{fbank->size, fbank->timeLen}, InferenceEngine::Layout::HW);
Blob::Ptr blob = InferenceEngine::make_shared_blob<float>(tDesc, fbank->data);
infer_request.SetBlob(input_name, blob);
infer_request.Infer();
Blob::Ptr output_blob = infer_request.GetBlob(output_name);
auto dims = output_blob->getTensorDesc().getDims();
size_t batchSize = dims[0];
size_t T = dims[1];
size_t D = dims[2];
MemoryBlob::CPtr moutput = as<MemoryBlob>(output_blob);
if (!moutput) {
return;
}
auto moutputHolder = moutput->rmap();
const float *pred = moutputHolder.as<const float*>();
print_arr("AM output:", pred, D*29, D*31);
}
int main() {
Fbank* fbank = new Fbank;
fbank->size = 64;
fbank->timeLen = 2000;
fbank->data = new float[64*2000];
Core ie;
CNNNetwork network = ie.ReadNetwork("quartznet_random.xml", "quartznet_random.bin");
std::string input_name = network.getInputsInfo().begin()->first;
std::string output_name = network.getOutputsInfo().begin()->first;
network.getOutputsInfo().begin()->second->setPrecision(Precision::FP32);
ExecutableNetwork executable_network = ie.LoadNetwork(network, "cpu");
doInference(executable_network, input_name, output_name, fbank);
return 0;
}
Outputs:
AM output:
0.138650 -5.833140 -8.023724 -7.637482 -8.001101 -9.033963 -8.029905 -8.132050 -9.186495 -8.537528 -8.788505 -9.240234 -8.547676 -8.673388 0.000000 0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000
If I run ONNX model in Python using onnxruntime, the output will be correct. (Example).
Is it possible to fix it?
P.S. Command to convert the model from ONNX: python3 mo_onnx.py —input_model model.onnx —output="output" —input="fbanks[64 2000]"
Tested provided ONNX model in OpenVINO for Linux, couple of findings while testing OpenVINO 2020.1 and new 2020.2 version (released today 4/14/2020, release notes).
Using same command to convert from ONNX. Although its unclear what would be the expected output (probability between 0.0 and 1.0?), OpenVINO 2020.2 seems to affect the output results.
On 2020.1, observed similar results to yours (one can assume this is the OpenVINO version you used).
AM output: -3.55062 -3.5114 -3.50925 -3.52013 -3.51791 -3.54656 -3.53908 -3.54239 -3.53626 -3.50982 -3.54193 -3.55593 -3.52877 -3.53786 -1.546e-07 -6.14673e-08 -8.56817e-08 -1.41561e-07 -6.14673e-08 -1.16415e-07 -9.30158e-08 -9.12696e-08 -1.29454e-07 -1.04774e-07 -6.14673e-08 -5.58794e-08 -1.71363e-07 -1.02445e-07 -5.7742e-08 -1.35042e-07 -9.26666e-08 -1.00583e-07 -1.04308e-07 -1.2666e-07 -1.39698e-07 -7.26432e-08 -9.68575e-08 -1.47149e-07 -9.40636e-08 -9.77889e-08 -9.49949e-08 -1.16415e-07 -9.54606e-08 -8.3819e-08 -1.28523e-07 -1.35973e-07 -7.66013e-08 -1.12224e-07 -1.546e-07 -6.14673e-08 -8.56817e-08 -1.41561e-07 -6.14673e-08 -1.16415e-07 -9.30158e-08 -9.12696e-08 -1.29454e-07 -1.04774e-07 -6.14673e-08 -5.58794e-08 -1.71363e-07 -1.02445e-07 -5.7742e-08 -1.35042e-07 -9.26666e-08 -1.00583e-07 -1.04308e-07 -1.2666e-07
On OpenVINO 2020.2 had to change ExecutableNetwork executable_network = ie.LoadNetwork(network, "cpu"); to ExecutableNetwork executable_network = ie.LoadNetwork(network, "CPU"); as Inference Engine didnt't recognize lowercase CPU device, error was "terminate called after throwing an instance of 'InferenceEngine::details::InferenceEngineException'
what(): Device with "cpu" name is not registered in the InferenceEngine
Aborted (core dumped)"
On OpenVINO 2020.2, the results differ and are not close to zero (although all seem negative).
AM output: -3.55062 -3.5114 -3.50925 -3.52013 -3.51791 -3.54656 -3.53908 -3.54239 -3.53626 -3.50982 -3.54193 -3.55593 -3.52877 -3.53786 -3.52153 -3.52563 -3.51142 -3.54885 -3.52137 -3.54384 -3.53411 -3.55188 -3.5477 -3.52514 -3.51171 -3.5022 -3.5138 -3.50823 -3.50125 -3.51817 -3.53914 -3.50173 -3.50603 -3.51917 -3.55062 -3.5114 -3.50925 -3.52013 -3.51791 -3.54656 -3.53908 -3.54239 -3.53626 -3.50982 -3.54193 -3.55593 -3.52877 -3.53786 -3.52153 -3.52563 -3.51142 -3.54885 -3.52137 -3.54384 -3.53411 -3.55188 -3.5477 -3.52514 -3.51171 -3.5022 -3.5138 -3.50823 -3.50125 -3.51817 -3.53914 -3.50173 -3.50603 -3.51917
It's uncertain if the output results of OpenVINO 2020.2 are expected/correct. I am unable to test Python example with the ONNX model using onnxruntime, script expects /kek/fbank.out file. Clarify/share what output is expected, i.e. correct AM output.
The problem was due to numerical instability in our implementation of LogSoftmax. Without log of softmax all works fine.

Is there a command or subroutine for LU factorization? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
In MatLab, the command lu(A) gives as output the two matrices L and U, that is, the LU factorization of A. I was wondering whether there is some command in Fortran doing exactly the same. I have not been able to find it anywhere. I found a lot of subroutines of LAPACK which solve linear systems by first performing the LU factorization, but for my purpouses I need to specifically perform the LU factorization and store the L and U matrices.
Is there a command or subroutine which has as input a square matrix A and as outputs the matrices L and U of the LU factorization?
There is no built-in command that corresponds to lu in Matlab, but we can write a simple wrapper to dgetrf in LAPACK such that the interface is similar to lu, e.g.,
module linalg
implicit none
integer, parameter :: dp = kind(0.0d0)
contains
subroutine lufact( A, L, U, P )
!... P * A = L * U
!... http://www.netlib.org/lapack/explore-3.1.1-html/dgetrf.f.html
!... (note that the definition of P is opposite to that of the above page)
real(dp), intent(in) :: A(:,:)
real(dp), allocatable, dimension(:,:) :: L, U, P
integer, allocatable :: ipiv(:)
real(dp), allocatable :: row(:)
integer :: i, n, info
n = size( A, 1 )
allocate( L( n, n ), U( n, n ), P( n, n ), ipiv( n ), row( n ) )
L = A
call DGETRF( n, n, L, n, ipiv, info )
if ( info /= 0 ) stop "lufact: info /= 0"
U = 0.0d0
P = 0.0d0
do i = 1, n
U( i, i:n ) = L( i, i:n )
L( i, i:n ) = 0.0d0
L( i, i ) = 1.0d0
P( i, i ) = 1.0d0
enddo
!... Assuming that P = P[ipiv(n),n] * ... * P[ipiv(1),1]
!... where P[i,j] is a permutation matrix for i- and j-th rows.
do i = 1, n
row = P( i, : )
P( i, : ) = P( ipiv(i), : )
P( ipiv(i), : ) = row
enddo
endsubroutine
end module
Then, we can test the routine with a 3x3 matrix shown in the Matlab page for lu():
program test_lu
use linalg
implicit none
real(dp), allocatable, dimension(:,:) :: A, L, U, P
allocate( A( 3, 3 ) )
A( 1, : ) = [ 1, 2, 3 ]
A( 2, : ) = [ 4, 5, 6 ]
A( 3, : ) = [ 7, 8, 0 ]
call lufact( A, L, U, P ) !<--> [L,U,P] = lu( A ) in Matlab
call show( "A =", A )
call show( "L =", L )
call show( "U =", U )
call show( "P =", P )
call show( "P * A =", matmul( P, A ) )
call show( "L * U =", matmul( L, U ) )
call show( "P' * L * U =", matmul( transpose(P), matmul( L, U ) ) )
contains
subroutine show( msg, X )
character(*) :: msg
real(dp) :: X(:,:)
integer i
print "(/,a)", trim( msg )
do i = 1, size(X,1)
print "(*(f8.4))", X( i, : )
enddo
endsubroutine
end program
which gives the expected result:
A =
1.0000 2.0000 3.0000
4.0000 5.0000 6.0000
7.0000 8.0000 0.0000
L =
1.0000 0.0000 0.0000
0.1429 1.0000 0.0000
0.5714 0.5000 1.0000
U =
7.0000 8.0000 0.0000
0.0000 0.8571 3.0000
0.0000 0.0000 4.5000
P =
0.0000 0.0000 1.0000
1.0000 0.0000 0.0000
0.0000 1.0000 0.0000
P * A =
7.0000 8.0000 0.0000
1.0000 2.0000 3.0000
4.0000 5.0000 6.0000
L * U =
7.0000 8.0000 0.0000
1.0000 2.0000 3.0000
4.0000 5.0000 6.0000
P' * L * U =
1.0000 2.0000 3.0000
4.0000 5.0000 6.0000
7.0000 8.0000 0.0000
Here please note that the inverse of P is given by its transpose (i.e., inv(P) = P' = transpose(P)) because P is the product of (elementary) permutation matrices.
I have added an method to compute LU using DOLITTLE method. Which is used by MATLAB to computed LU for faster computation involving larger matrices. The algorithm is as follows. To execute the algorithm you have to provide an input file in the format given below. Since the algorithm is a subroutine, you can add it to your code and call it whenever required. Algorithm, input file, output file are as follows.
PROGRAM DOLITTLE
IMPLICIT NONE
INTEGER :: n
!**********************************************************
! READS THE NUMBER OF EQUATIONS TO BE SOLVED.
OPEN(UNIT=1,FILE='input.dat',ACTION='READ',STATUS='OLD')
READ(1,*) n
CLOSE(1)
!**********************************************************
CALL LU(n)
END PROGRAM
!==========================================================
! SUBROUTINES TO MAIN PROGRAM
SUBROUTINE LU(n)
IMPLICIT NONE
INTEGER :: i,j,k,p,n,z,ii,itr = 500000
REAL(KIND=8) :: temporary,s1,s2
REAL(KIND=8),DIMENSION(1:n) :: x,b,y
REAL(KIND=8),DIMENSION(1:n,1:n) :: A,U,L,TEMP
REAL(KIND=8),DIMENSION(1:n,1:n+1) :: AB
! READING THE SYSTEM OF EQUATIONS
OPEN(UNIT=2,FILE='input.dat',ACTION='READ',STATUS='OLD')
READ(2,*)
DO I=1,N
READ(2,*) A(I,:)
END DO
DO I=1,N
READ(2,*) B(I)
END DO
CLOSE(2)
DO z=1,itr
U(:,:) = 0
L(:,:) = 0
DO j = 1,n
L(j,j) = 1.0d0
END DO
DO j = 1,n
U(1,j) = A(1,j)
END DO
DO i=2,n
DO j=1,n
DO k=1,i1
s1=0
if (k==1)then
s1=0
else
DO p=1,k1
s1=s1+L(i,p)*U(p,k)
end DO
endif
L(i,k)=(A(i,k)-s1)/U(k,k)
END DO
DO k=i,n
s2=0
DO p=1,i-1
s2=s2+l(i,p)*u(p,k)
END DO
U(i,k)=A(i,k)*s2
END DO
END DO
END DO
IF(z.eq.1)THEN
OPEN(UNIT=3,FILE='output.dat',ACTION='write')
WRITE(3,*) ''
WRITE(3,*) '********** SOLUTIONS *********************'
WRITE(3,*) ''
WRITE(3,*) ''
WRITE(3,*) 'UPPER TRIANGULAR MATRIX'
DO I=1,N
WRITE(3,*) U(I,:)
END DO
WRITE(3,*) ''
WRITE(3,*) ''
WRITE(3,*) 'LOWER TRIANGULAR MATRIX'
DO I=1,N
WRITE(3,*) L(I,:)
END DO
END SUBROUTINE
Here goes the input file format for system Ax=B. First line is number of equations, next three lines are the A matrix element, next three lines are B vector ,
3
10 8 3
3 20 1
4 5 15
18
23
9
And the output is generated as,
********** SOLUTIONS *********************
UPPER TRIANGULAR MATRIX
10.000000000000000 8.0000000000000000 3.0000000000000000
0.0000000000000000 17.600000000000001 0.1000000000000009
0.0000000000000000 0.0000000000000000 13.789772727272727
LOWER TRIANGULAR MATRIX
1.0000000000000000 0.0000000000000000 0.0000000000000000
0.2999999999999999 1.0000000000000000 0.0000000000000000
0.4000000000000002 0.1022727272727273 1.0000000000000000
You can try "numerical recipes in fortran 77",
there was LU decomposition subroutine.
There are a lot of useful subroutines, linalg, stasistics, etc.

Convert my list output to a dataframe in pandas

How do i convert my list output to a data frame? below is a sample of the code and data
import pandas as pd
import numpy as np
from datetime import datetime
dat=pd.read_csv()
dat.Date = dat.Date.apply(lambda d: datetime.strptime(d, "%d-%m-%Y"))
dat.index = dat.Date
dat = dat.drop(['Date'], axis=1)
################################################################
#Provide Input parameters
Decay=0.4
Decay_Dur=15 #(in days)
Return_Avg_Dur=15 #(in days)
################################################################
Weights=[]
Weights=[pow(i,((2*Decay)-1)) for i in range(1,Decay_Dur+1)] # Calculate Weights
Weights=Weights[::-1] #Reverse the order
fin_dat=[0]
for j in range(1,(dat.shape[0]-Decay_Dur)):
Sum_Weighted_Index=0
for i in range(j,Decay_Dur+j):
temp=Weights[i-j]*dat.iat[i-1,2] #
Sum_Weighted_Index+=temp
fin_dat.append(Sum_Weighted_Index)
Date SPX Index Surprise Index S&P 500 Daily Return
19-07-2007 1553.08 -0.0563 0.0045
20-07-2007 1534.1 0 -0.0122
23-07-2007 1541.57 0 0.0049
24-07-2007 1511.04 0 -0.0198
25-07-2007 1518.09 0 0.0047
26-07-2007 1482.66 0 -0.0233
27-07-2007 1458.95 0 -0.016
30-07-2007 1473.91 0 0.0103
31-07-2007 1455.27 -0.0867 -0.0126
01-08-2007 1465.81 -0.1529 0.0072
02-08-2007 1472.2 0 0.0044
03-08-2007 1433.06 -0.0848 -0.0266
06-08-2007 1467.67 0 0.0242
07-08-2007 1476.71 0 0.0062
08-08-2007 1497.49 0 0.0141
09-08-2007 1453.09 0 -0.0296
10-08-2007 1453.64 0 0.0004
13-08-2007 1452.92 0.0138 -0.0005
14-08-2007 1426.54 0 -0.0182
15-08-2007 1406.7 0 -0.0139
16-08-2007 1411.27 -0.1289 0.0032
17-08-2007 1445.94 0 0.0246
20-08-2007 1445.55 0 -0.0003
21-08-2007 1447.12 0 0.0011
22-08-2007 1464.07 0 0.0117
23-08-2007 1462.5 0 -0.0011
24-08-2007 1479.37 0 0.0115
27-08-2007 1466.79 0 -0.0085
I tried to use your code and then create new version using pandas functions.
It's all my "notes" - and result at the end.
Check whether the results are correct.
import pandas as pd
#--- generate some data ---
#dates = pd.date_range( '01-01-2010', periods=30, freq='D' )
#values = range(0,30)
#dat = pd.DataFrame( {'Date':dates, 'val1':values, 'val2':values} )
#dat.index = dat.Date
#print dat
data = '''Date SPX Surprise S&P-500
19-07-2007 1553.08 -0.0563 0.0045
20-07-2007 1534.1 0 -0.0122
23-07-2007 1541.57 0 0.0049
24-07-2007 1511.04 0 -0.0198
25-07-2007 1518.09 0 0.0047
26-07-2007 1482.66 0 -0.0233
27-07-2007 1458.95 0 -0.016
30-07-2007 1473.91 0 0.0103
31-07-2007 1455.27 -0.0867 -0.0126
01-08-2007 1465.81 -0.1529 0.0072
02-08-2007 1472.2 0 0.0044
03-08-2007 1433.06 -0.0848 -0.0266
06-08-2007 1467.67 0 0.0242
07-08-2007 1476.71 0 0.0062
08-08-2007 1497.49 0 0.0141
09-08-2007 1453.09 0 -0.0296
10-08-2007 1453.64 0 0.0004
13-08-2007 1452.92 0.0138 -0.0005
14-08-2007 1426.54 0 -0.0182
15-08-2007 1406.7 0 -0.0139
16-08-2007 1411.27 -0.1289 0.0032
17-08-2007 1445.94 0 0.0246
20-08-2007 1445.55 0 -0.0003
21-08-2007 1447.12 0 0.0011
22-08-2007 1464.07 0 0.0117
23-08-2007 1462.5 0 -0.0011
24-08-2007 1479.37 0 0.0115
27-08-2007 1466.79 0 -0.0085'''
from StringIO import StringIO
dat = pd.DataFrame.from_csv( StringIO(data), sep='\s+')
#------------------------------------------
decay = 0.4
decay_dur = 15 # (in days)
return_avg_dur = 15 # (in days)
#--- old version ---
weights = [ pow(i,(2*decay)-1) for i in range(1,decay_dur+1) ] # Calculate Weights
weights = weights[::-1] #Reverse the order
#weights = [ pow(i,(2*decay)-1) for i in range(1,decay_dur+1) ][::-1]
#fin_dat=[0]
dat['old'] = 0.0
for j in range(1,(dat.shape[0]-decay_dur)):
sum_weighted_index = 0
for i in range(j,decay_dur+j):
#sum_weighted_index += weights[i-j] * dat.iat[i-1,2] #
sum_weighted_index += weights[i-j] * dat['S&P-500'].iat[i-1] #
#fin_dat.append(sum_weighted_index)
dat['old'].iat[j] = sum_weighted_index
#print sum_weighted_index
#--- new version ---
#def sum_weighted_index(data):
# result = 0
# for w, d in zip(weights, data):
# result += w * d
# return result
def sum_weighted_index(data):
return sum( w * d for w, d in zip(weights, data) )
dat['new'] = pd.rolling_apply(dat['S&P-500'], decay_dur, sum_weighted_index).shift(-decay_dur+2).fillna(0)
print dat
result
SPX Surprise S&P-500 old new
Date
2007-07-19 1553.08 -0.0563 0.0045 0.000000 0.000000
2007-07-20 1534.10 0.0000 -0.0122 -0.010550 -0.010550
2007-07-23 1541.57 0.0000 0.0049 -0.044731 -0.044731
2007-07-24 1511.04 0.0000 -0.0198 -0.034384 -0.034384
2007-07-25 1518.09 0.0000 0.0047 -0.036309 -0.036309
2007-07-26 1482.66 0.0000 -0.0233 -0.042091 -0.042091
2007-07-27 1458.95 0.0000 -0.0160 -0.055676 -0.055676
2007-07-30 1473.91 0.0000 0.0103 -0.035502 -0.035502
2007-07-31 1455.27 -0.0867 -0.0126 -0.000058 -0.000058
2007-01-08 1465.81 -0.1529 0.0072 -0.008301 -0.008301
2007-02-08 1472.20 0.0000 0.0044 -0.000615 -0.000615
2007-03-08 1433.06 -0.0848 -0.0266 0.006442 0.006442
2007-06-08 1467.67 0.0000 0.0242 0.001076 0.001076
2007-07-08 1476.71 0.0000 0.0062 0.000000 0.027115
2007-08-08 1497.49 0.0000 0.0141 0.000000 0.002560
2007-09-08 1453.09 0.0000 -0.0296 0.000000 0.000000
2007-10-08 1453.64 0.0000 0.0004 0.000000 0.000000
2007-08-13 1452.92 0.0138 -0.0005 0.000000 0.000000
2007-08-14 1426.54 0.0000 -0.0182 0.000000 0.000000
2007-08-15 1406.70 0.0000 -0.0139 0.000000 0.000000
2007-08-16 1411.27 -0.1289 0.0032 0.000000 0.000000
2007-08-17 1445.94 0.0000 0.0246 0.000000 0.000000
2007-08-20 1445.55 0.0000 -0.0003 0.000000 0.000000
2007-08-21 1447.12 0.0000 0.0011 0.000000 0.000000
2007-08-22 1464.07 0.0000 0.0117 0.000000 0.000000
2007-08-23 1462.50 0.0000 -0.0011 0.000000 0.000000
2007-08-24 1479.37 0.0000 0.0115 0.000000 0.000000
2007-08-27 1466.79 0.0000 -0.0085 0.000000 0.000000

fftw and online DFT calculator get different results

I calculated the FFT of array {1,2,3,4,5,6} with fftw/C++ and an online calculator (http://calculator-fx.com/calculator/fast-fourier-transform-calculator-fft/1d-discrete-fourier-transform). And the results seemed to be a bit different.
fftw output:
0 21.000000 0.000000
1 -3.000000 5.196152
2 -3.000000 1.732051
3 -3.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
Online calculator output:
21 + 0j
-3 + 5.196152j
-3 + 1.732051j
-3 + 0j
-3 - 1.732051j
-3 - 5.196152j
As is shown above, the latter two results of fftw turned to be zero.
Can't figure out why. Could anybody help me out? Thanks.
[EDITED]
cpp code:
int main()
{
fftw_complex *out;
fftw_plan plan;
double arr[]={1,2,3,4,5,6};
int n = sizeof(arr)/sizeof(double);
out = (fftw_complex*)fftw_malloc ( sizeof ( fftw_complex ) * n );
plan = fftw_plan_dft_r2c_1d ( n, arr, out, FFTW_ESTIMATE );
fftw_execute ( plan );
for (int i = 0; i < n; i++ )
{
printf ( " %3d %12lf %12lf\n", i, out[i][0], out[i][1] );
}
fftw_free(out);
fftw_destroy_plan(plan);
return 0;
}
Oh, you're using the R2C mode (don't know why I didn't think of that before). That only writes n/2 + 1 results, because of the symmetry.
This behaviour is documented: http://www.fftw.org/doc/One_002dDimensional-DFTs-of-Real-Data.html.