Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
MODELS
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Tadah
MODELS
Compare revisions
60419dc5eb3f49bc34c9e5ba562b2baeecf7cc15 to 49cea667b84678ce8b7f96670c79557a1b32d724
Compare revisions
Changes are shown as if the
source
revision was being merged into the
target
revision.
Learn more about comparing revisions.
Source
tadah/models
Select target project
No results found
49cea667b84678ce8b7f96670c79557a1b32d724
Select Git revision
Branches
develop
feature/structure_readers
hpc
main
Swap
Target
tadah/models
Select target project
tadah/models
1 result
60419dc5eb3f49bc34c9e5ba562b2baeecf7cc15
Select Git revision
Branches
develop
feature/structure_readers
hpc
main
Show changes
Only incoming changes from source
Include changes to target since source was created
Compare
Commits on Source (3)
New linear regression classes and SVD class
· bc1f7db6
mkirsz
authored
1 year ago
bc1f7db6
Closes
#3
, Related
#5
· 2ad27b99
mkirsz
authored
1 year ago
2ad27b99
Closes
#2
, Related
#3
· 49cea667
mkirsz
authored
1 year ago
49cea667
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
ea.h
+69
-28
69 additions, 28 deletions
ea.h
ekm.h
+49
-19
49 additions, 19 deletions
ekm.h
ols.h
+50
-0
50 additions, 0 deletions
ols.h
ridge_regression.h
+64
-0
64 additions, 0 deletions
ridge_regression.h
svd.h
+199
-0
199 additions, 0 deletions
svd.h
with
431 additions
and
47 deletions
ea.h
View file @
49cea667
#ifndef M_EA_H
#define M_EA_H
#include
"../LIBS/Eigen/Dense"
#include
"../CORE/config/config.h"
#include
"../CORE/eigen_types.h"
#include
"svd.h"
#include
"ridge_regression.h"
#include
"../CORE/core_types.h"
#include
"../CORE/lapack.h"
class
EA
{
private:
Config
&
config
;
const
Config
&
config
;
const
SVD
&
svd
;
const
t_type
&
T
;
int
verbose
;
public:
EA
(
Config
&
c
)
:
EA
(
const
Config
&
c
,
const
SVD
&
svd
,
const
t_type
&
T
)
:
config
(
c
),
svd
(
svd
),
T
(
T
),
verbose
(
c
.
get
<
int
>
(
"VERBOSE"
))
{}
int
run
(
const
mat
&
Phi
,
const
vec
&
T
,
const
mat
&
S
,
const
mat
&
U
,
const
mat
&
V
,
double
&
alpha
,
double
&
beta
)
{
int
run
(
double
&
alpha
,
double
&
beta
)
{
// Phi = USV^T
size_t
N
=
Phi
.
rows
()
;
size_t
N
=
svd
.
shapeA
().
first
;
size_t
maxsteps
=
40
;
const
double
EPS2
=
5e-12
;
int
convergence_status
=
1
;
...
...
@@ -31,40 +34,41 @@ class EA {
size_t
counter
=
0
;
double
lambda
=
alpha
/
beta
;
double
*
s
=
svd
.
getS
();
// square of the S matrix contains all eigenvalues
// of Phi^T*Phi = (VSU^T)(USV^T) = VS^2V^T = S^2
const
vec
eval
=
S
.
array
().
pow
(
2
);
double
*
eval
=
new
double
[
svd
.
sizeS
()];
for
(
size_t
i
=
0
;
i
<
svd
.
sizeS
();
++
i
)
eval
[
i
]
=
s
[
i
]
*
s
[
i
];
if
(
verbose
)
printf
(
"%9s %9s %9s %9s %9s %9s
\n
"
,
"del alpha"
,
"del beta"
,
"alpha"
,
"beta"
,
"lambda"
,
"gamma"
);
// D is a filter factors matrix
mat
D
(
S
.
rows
(),
S
.
rows
()
)
;
D
.
setZero
();
double
*
d
=
new
double
[
svd
.
sizeS
()
]
;
int
outprec
=
config
.
get
<
int
>
(
"OUTPREC"
);
double
*
t
=
new
double
[
svd
.
shapeA
().
first
];
double
*
x
=
new
double
[
svd
.
shapeA
().
second
];
while
(
test1
>
EPS2
||
test2
>
EPS2
)
{
for
(
long
int
i
=
0
;
i
<
S
.
rows
();
++
i
)
{
double
s
=
S
(
i
,
0
);
if
(
s
>
std
::
numeric_limits
<
double
>::
min
())
D
(
i
,
i
)
=
(
s
)
/
(
s
*
s
+
lambda
);
else
D
(
i
,
i
)
=
0.0
;
}
// regularised least square problem (Tikhonov Regularization):
vec
m_n
=
V
*
D
*
U
.
transpose
()
*
T
;
t_type
m_n
((
size_t
)
svd
.
sizeS
());
RidgeRegression
::
solve
(
svd
,
T
,
m_n
,
lambda
);
double
gamma
=
0.0
;
for
(
long
int
j
=
0
;
j
<
S
.
rows
();
j
++
)
{
// exlude eigenvalues which are smaller than ~1e-10
// for numerical stability b/c matrix is not regularized
if
(
beta
*
eval
(
j
)
>
std
::
numeric_limits
<
double
>::
min
())
{
gamma
+=
(
beta
*
eval
(
j
))
/
(
beta
*
eval
(
j
)
+
alpha
);
for
(
size_t
j
=
0
;
j
<
svd
.
sizeS
();
j
++
)
{
if
(
beta
*
eval
[
j
]
>
std
::
numeric_limits
<
double
>::
min
())
{
gamma
+=
(
beta
*
eval
[
j
])
/
(
beta
*
eval
[
j
]
+
alpha
);
}
}
alpha
=
gamma
/
m_n
.
dot
(
m_n
);
alpha
=
gamma
/
(
m_n
*
m_n
);
double
temp
=
(
T
-
Phi
*
m_n
).
dot
(
T
-
Phi
*
m_n
);
t_type
Tpred
=
svd
.
predict
(
m_n
,
t
,
x
);
double
temp
=
(
T
-
Tpred
)
*
(
T
-
Tpred
);
//double temp = (T-U*S.asDiagonal()*V.transpose()*m_n).dot(T-U*S.asDiagonal()*V.transpose()*m_n);
beta
=
(
static_cast
<
double
>
(
N
)
-
gamma
)
/
temp
;
test1
=
fabs
(
alpha_old
-
alpha
)
/
alpha
;
...
...
@@ -82,8 +86,45 @@ class EA {
}
if
(
convergence_status
&&
verbose
)
std
::
cout
<<
"Number of steps for convergence: "
+
to_string
(
counter
,
outprec
)
<<
std
::
endl
;
if
(
!
convergence_status
&&
verbose
)
std
::
cout
<<
"Max number of steps reached: "
+
to_string
(
counter
,
outprec
)
<<
std
::
endl
;
delete
[]
eval
;
delete
[]
d
;
delete
[]
t
;
delete
[]
x
;
return
convergence_status
;
};
Matrix
get_sigma
(
double
alpha
,
double
beta
)
{
double
*
vt
=
svd
.
getVT
();
double
*
s
=
svd
.
getS
();
int
n
=
static_cast
<
int
>
(
svd
.
shapeVT
().
first
);
Matrix
Sigma
((
size_t
)
n
,(
size_t
)
n
);
Sigma
.
setZero
();
double
*
sigma
=
&
Sigma
.
data
()[
0
];
// Build P_inv matrix
for
(
size_t
i
=
0
;
i
<
svd
.
sizeS
();
++
i
)
{
Sigma
(
i
,
i
)
=
1.0
/
(
beta
*
s
[
i
]
*
s
[
i
]
+
alpha
);
}
//Sigma = V*P_inv*V.transpose();
char
transa
=
'T'
;
char
transb
=
'N'
;
double
alpha_
=
1.0
;
double
beta_
=
0.0
;
double
*
work
=
new
double
[
n
*
n
];
dgemm_
(
&
transb
,
&
transb
,
&
n
,
&
n
,
&
n
,
&
alpha_
,
sigma
,
&
n
,
vt
,
&
n
,
&
beta_
,
work
,
&
n
);
dgemm_
(
&
transa
,
&
transb
,
&
n
,
&
n
,
&
n
,
&
alpha_
,
vt
,
&
n
,
work
,
&
n
,
&
beta_
,
sigma
,
&
n
);
delete
[]
work
;
return
Sigma
;
}
};
#endif
...
...
This diff is collapsed.
Click to expand it.
ekm.h
View file @
49cea667
#ifndef EKM_H
#define EKM_H
#include
"../LIBS/Eigen/Dense"
#include
"../CORE/eigen_types.h"
#include
"../CORE/core_types.h"
template
<
typename
K
>
...
...
@@ -10,17 +8,17 @@ class EKM {
private:
K
kernel
;
public:
Eigen
::
Matrix
Xd
KK
;
Matrix
KK
;
template
<
typename
T
>
EKM
(
T
&
t
)
:
kernel
(
t
)
{}
void
configure
(
aeds_type2
&
basis
)
{
// KK is temp matrix
KK
=
Eigen
::
MatrixXd
(
basis
.
size
(),
basis
.
size
());
void
configure
(
Matrix
&
basis
)
{
KK
=
Matrix
(
basis
.
cols
(),
basis
.
cols
());
for
(
long
int
i
=
0
;
i
<
KK
.
rows
();
i
++
)
{
for
(
long
int
j
=
0
;
j
<
KK
.
cols
();
j
++
)
{
// Compute lower diagonal part only
for
(
size_t
i
=
0
;
i
<
KK
.
cols
();
i
++
)
{
for
(
size_t
j
=
i
+
1
;
j
<
KK
.
cols
();
j
++
)
{
double
val
=
kernel
(
basis
.
col
(
i
),
basis
.
col
(
j
));
KK
(
i
,
j
)
=
val
;
}
...
...
@@ -28,21 +26,53 @@ class EKM {
// KK is a kernel matrix
// we compute cholesky for KK^-1
// then KK = L^-1
KK
=
KK
.
inverse
();
Eigen
::
LLT
<
Eigen
::
MatrixXd
>
llt
(
KK
);
KK
=
llt
.
matrixL
();
KK
.
transposeInPlace
();
inverse
(
KK
);
cholesky
(
KK
,
'L'
);
}
void
inverse
(
Matrix
&
A
)
{
double
*
a
=
&
A
.
data
()[
0
];
int
n
=
A
.
rows
();
// A is square
int
*
ipiv
=
new
int
[
n
];
int
lwork
=
n
*
n
;
double
*
work
=
new
double
[
lwork
];
int
info
;
dgetrf_
(
&
n
,
&
n
,
a
,
&
n
,
ipiv
,
&
info
);
dgetri_
(
&
n
,
a
,
&
n
,
ipiv
,
work
,
&
lwork
,
&
info
);
delete
[]
ipiv
;
delete
[]
work
;
}
void
cholesky
(
Matrix
&
A
,
char
uplo
)
{
// matrix must be either U or L
int
n
=
A
.
cols
();
// A is square
double
*
a
=
&
A
.
data
()[
0
];
int
info
;
dpotrf_
(
&
uplo
,
&
n
,
a
,
&
n
,
&
info
);
}
void
project
(
phi_type
&
Phi
)
{
for
(
long
int
i
=
0
;
i
<
Phi
.
rows
();
++
i
)
{
Phi
.
row
(
i
)
=
KK
*
Phi
.
row
(
i
).
transpose
();
}
char
transa
=
'N'
;
char
transb
=
'N'
;
int
m
=
Phi
.
rows
();
int
n
=
Phi
.
cols
();
double
*
a
=
&
Phi
.
data
()[
0
];
double
*
b
=
&
KK
.
data
()[
0
];
double
*
c
=
new
double
[
m
*
n
];
double
alpha
=
1.0
;
double
beta
=
0.0
;
dgemm_
(
&
transa
,
&
transb
,
&
m
,
&
n
,
&
n
,
&
alpha
,
a
,
&
m
,
b
,
&
n
,
&
beta
,
c
,
&
m
);
Phi
=
Matrix
(
c
,
m
,
n
);
delete
[]
c
;
}
aed_type2
project
(
aed_type2
&
aed
,
aeds_type2
&
basis
)
{
aed_type2
temp
(
basis
.
size
());
for
(
long
in
t
b
=
0
;
b
<
basis
.
cols
();
b
++
)
{
aed_type2
project
(
aed_type2
&
aed
,
Matrix
&
basis
)
{
aed_type2
temp
(
basis
.
cols
());
for
(
size_
t
b
=
0
;
b
<
basis
.
cols
();
b
++
)
{
temp
(
b
)
=
kernel
(
aed
,
basis
[
b
]);
}
return
KK
*
temp
;
...
...
This diff is collapsed.
Click to expand it.
ols.h
0 → 100644
View file @
49cea667
#ifndef OLS_H
#define OLS_H
#include
"../CORE/core_types.h"
class
OLS
{
public:
template
<
typename
M
,
typename
V
>
static
void
solve
(
M
&
A
,
V
&
B
,
V
&
weights
)
{
// A will be destroyed on exit
// B will contain solution
int
m
=
A
.
rows
();
//IN
int
n
=
A
.
cols
();
//IN
int
nrhs
=
1
;
// number of colums in B (targets T) //IN
double
*
a
=
&
A
.
data
()[
0
];
//IN
int
lda
=
m
;
double
*
b
=
&
B
.
data
()[
0
];
// IN/OUT
int
ldb
=
std
::
max
(
m
,
n
);
double
*
s
=
new
double
[
std
::
min
(
m
,
n
)];
// size: rows
double
rcond
=
1e-8
;
// 1 use machine precision
int
rank
;
double
*
work
;
int
lwork
=-
1
;
// QUERRY
int
liwork
=
std
::
max
(
0
,
int
(
std
::
log2
(
std
::
min
(
m
,
n
)
/
(
25
+
1
)))
+
1
)
+
11
*
std
::
min
(
m
,
n
);
int
smlsiz
=
25
;
int
nlvl
=
std
::
max
(
0
,
int
(
std
::
log2
(
std
::
min
(
m
,
n
)
/
(
smlsiz
+
1
)
)
)
+
1
);
int
*
iwork
=
new
int
[
3
*
std
::
min
(
m
,
n
)
*
nlvl
+
11
*
std
::
min
(
m
,
n
)];
int
info
;
double
wkopt
;
dgelsd_
(
&
m
,
&
n
,
&
nrhs
,
a
,
&
lda
,
b
,
&
ldb
,
s
,
&
rcond
,
&
rank
,
&
wkopt
,
&
lwork
,
iwork
,
&
info
);
lwork
=
(
int
)
wkopt
;
work
=
new
double
[
lwork
];
dgelsd_
(
&
m
,
&
n
,
&
nrhs
,
a
,
&
lda
,
b
,
&
ldb
,
s
,
&
rcond
,
&
rank
,
work
,
&
lwork
,
iwork
,
&
info
);
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
std
::
cout
<<
B
(
i
)
<<
" "
;
std
::
cout
<<
std
::
endl
;
weights
=
B
.
copy
(
A
.
cols
());
delete
[]
s
;
delete
[]
work
;
delete
[]
iwork
;
}
};
#endif
This diff is collapsed.
Click to expand it.
ridge_regression.h
0 → 100644
View file @
49cea667
#ifndef RIDGE_REGRESSION_H
#define RIDGE_REGRESSION_H
#include
"../CORE/core_types.h"
#include
"../CORE/maths.h"
#include
"../CORE/lapack.h"
#include
"svd.h"
class
RidgeRegression
{
public:
template
<
typename
V
,
typename
W
>
static
void
solve
(
const
SVD
&
svd
,
V
/*&*/
T
,
W
&
weights
,
const
double
lambda
)
{
double
*
u
=
svd
.
getU
();
double
*
s
=
svd
.
getS
();
double
*
vt
=
svd
.
getVT
();
double
*
d
=
new
double
[
svd
.
sizeS
()];
for
(
size_t
i
=
0
;
i
<
svd
.
sizeS
();
++
i
)
{
double
sv
=
s
[
i
];
if
(
sv
>
std
::
numeric_limits
<
double
>::
min
())
d
[
i
]
=
(
sv
)
/
(
sv
*
sv
+
lambda
);
else
d
[
i
]
=
0.0
;
}
int
m
=
svd
.
shapeA
().
first
;
int
n
=
svd
.
shapeA
().
second
;
int
ldu
=
svd
.
shapeU
().
first
;
int
ucol
=
svd
.
shapeU
().
second
;
int
lda
=
m
;
int
ldvt
=
svd
.
shapeVT
().
first
;
// SOLVE: V D U^T T
//STEP1: U^T T
char
trans
=
'T'
;
double
alpha_
=
1.0
;
double
*
x
=
&
T
.
data
()[
0
];
double
*
y
=
new
double
[
lda
];
int
incx
=
1
;
double
beta_
=
0.0
;
dgemv_
(
&
trans
,
&
ldu
,
&
ucol
,
&
alpha_
,
u
,
&
lda
,
x
,
&
incx
,
&
beta_
,
y
,
&
incx
);
// STEP2 : D (U^T T)
for
(
int
r
=
0
;
r
<
ldvt
;
++
r
)
{
y
[
r
]
*=
d
[
r
];
}
// STEP3: V (D U^T T)
trans
=
'T'
;
dgemv_
(
&
trans
,
&
ldvt
,
&
n
,
&
alpha_
,
vt
,
&
ldvt
,
y
,
&
incx
,
&
beta_
,
x
,
&
incx
);
weights
=
t_type
(
x
,
(
size_t
)
ldvt
);
delete
[]
d
;
delete
[]
y
;
}
};
#endif
This diff is collapsed.
Click to expand it.
svd.h
0 → 100644
View file @
49cea667
#ifndef SVD_H
#define SVD_H
#include
"../CORE/core_types.h"
#include
"../CORE/maths.h"
#include
"../CORE/lapack.h"
class
SVD
{
/** Compute Compact SVD
*
* M = USV^T
*/
private:
char
jobz
=
'S'
;
// compute the first min(M,N) columns of U
int
m
;
int
n
;
int
lda
;
int
ldu
;
int
ldvt
;
int
ucol
;
int
lwork
;
int
info
;
// arrays
double
*
a
=
nullptr
;
double
*
s
=
nullptr
;
double
*
u
=
nullptr
;
double
*
vt
=
nullptr
;
double
*
work
=
nullptr
;
int
*
iwork
=
nullptr
;
bool
work_alloc
=
false
;
public:
~
SVD
()
{
delete
[]
s
;
delete
[]
u
;
delete
[]
vt
;
if
(
work_alloc
)
delete
[]
iwork
;
if
(
work_alloc
&&
lwork
>
0
)
delete
[]
work
;
}
SVD
(
const
SVD
&
other
)
{
std
::
cout
<<
"Copy-constructor"
<<
std
::
endl
;
jobz
=
other
.
jobz
;
m
=
other
.
m
;
n
=
other
.
n
;
lda
=
other
.
lda
;
ldu
=
other
.
ldu
;
ldvt
=
other
.
ldvt
;
ucol
=
other
.
ucol
;
lwork
=
other
.
lwork
;
info
=
other
.
info
;
// allocate all
s
=
new
double
[
sizeS
()];
u
=
new
double
[
sizeU
()];
vt
=
new
double
[
sizeVT
()];
// We don't need this arrays
a
=
nullptr
;
work
=
nullptr
;
iwork
=
nullptr
;
work_alloc
=
false
;
std
::
cout
<<
sizeS
()
<<
std
::
endl
;;
std
::
cout
<<
sizeU
()
<<
std
::
endl
;;
std
::
cout
<<
sizeVT
()
<<
std
::
endl
;;
// hard copy
std
::
memcpy
(
s
,
other
.
s
,
sizeS
()
*
sizeof
(
double
));
std
::
memcpy
(
u
,
other
.
u
,
sizeU
()
*
sizeof
(
double
));
std
::
memcpy
(
vt
,
other
.
vt
,
sizeVT
()
*
sizeof
(
double
));
}
//SVD &operator=(const SVD &other)
//{
// //if (this == &other)
// // return *this;
// std::cout << "Copy-assignment" << std::endl;
//}
SVD
(
Matrix
&
Phi
)
:
m
(
Phi
.
rows
()),
n
(
Phi
.
cols
()),
lda
(
Phi
.
rows
()),
ldu
(
Phi
.
rows
()),
ldvt
(
std
::
min
(
m
,
n
)),
ucol
(
std
::
min
(
m
,
n
)),
a
(
&
Phi
.
data
()[
0
]),
s
(
new
double
[
sizeS
()]),
u
(
new
double
[
sizeU
()]),
vt
(
new
double
[
sizeVT
()]),
iwork
(
new
int
[
8
*
std
::
min
(
m
,
n
)]),
work_alloc
(
true
)
{
lwork
=-
1
;
// QUERRY
double
wkopt
;
dgesdd_
(
&
jobz
,
&
m
,
&
n
,
a
,
&
lda
,
s
,
u
,
&
ldu
,
vt
,
&
ldvt
,
&
wkopt
,
&
lwork
,
iwork
,
&
info
);
lwork
=
(
int
)
wkopt
;
work
=
new
double
[
lwork
];
dgesdd_
(
&
jobz
,
&
m
,
&
n
,
a
,
&
lda
,
s
,
u
,
&
ldu
,
vt
,
&
ldvt
,
work
,
&
lwork
,
iwork
,
&
info
);
// Filter out v.small singularvalues from S and its inverse
for
(
size_t
i
=
0
;
i
<
sizeS
();
++
i
)
{
if
(
s
[
i
]
<
std
::
numeric_limits
<
double
>::
min
())
{
s
[
i
]
=
0.0
;
}
}
}
int
get_info
()
const
{
return
info
;
}
double
*
getA
()
const
{
return
a
;
}
double
*
getU
()
const
{
return
u
;
}
double
*
getVT
()
const
{
return
vt
;
}
double
*
getS
()
const
{
return
s
;
}
size_t
sizeA
()
const
{
return
m
*
n
;
}
size_t
sizeU
()
const
{
return
ldu
*
ucol
;
}
size_t
sizeVT
()
const
{
return
ldvt
*
n
;
}
size_t
sizeS
()
const
{
return
std
::
min
(
m
,
n
);
}
std
::
pair
<
size_t
,
size_t
>
shapeA
()
const
{
return
std
::
pair
<
size_t
,
size_t
>
(
m
,
n
);
}
std
::
pair
<
size_t
,
size_t
>
shapeU
()
const
{
return
std
::
pair
<
size_t
,
size_t
>
(
ldu
,
ucol
);
}
std
::
pair
<
size_t
,
size_t
>
shapeVT
()
const
{
return
std
::
pair
<
size_t
,
size_t
>
(
ldvt
,
n
);
}
std
::
pair
<
size_t
,
size_t
>
shapeS
()
const
{
return
std
::
pair
<
size_t
,
size_t
>
(
std
::
min
(
m
,
n
),
1
);
}
template
<
typename
T
>
T
predict
(
const
T
&
w
)
const
{
/* Return U S V^T w */
double
*
t
=
new
double
[
shapeA
().
first
];
double
*
x
=
new
double
[
shapeA
().
second
];
T
res
=
predict
(
w
,
t
,
x
);
delete
[]
t
;
delete
[]
x
;
return
res
;
}
template
<
typename
T
>
T
predict
(
const
T
&
w
,
double
*
t
,
double
*
x
)
const
{
/* Return U S V^T w */
const
double
*
w_ptr
=
&
w
.
data
()[
0
];
// 1. V^T w
char
trans
=
'N'
;
int
m
=
static_cast
<
int
>
(
shapeA
().
first
);
int
n
=
static_cast
<
int
>
(
shapeA
().
second
);
double
alpha_
=
1.0
;
double
beta_
=
0.0
;
int
incx
=
1
;
dgemv_
(
&
trans
,
&
n
,
&
n
,
&
alpha_
,
vt
,
&
n
,
w_ptr
,
&
incx
,
&
beta_
,
x
,
&
incx
);
// 2. S (V^T w)
for
(
int
i
=
0
;
i
<
n
;
++
i
)
{
x
[
i
]
*=
s
[
i
];
}
// 3. U (S V^T w)
dgemv_
(
&
trans
,
&
m
,
&
n
,
&
alpha_
,
u
,
&
m
,
x
,
&
incx
,
&
beta_
,
t
,
&
incx
);
return
T
(
t
,
m
);
}
};
#endif
This diff is collapsed.
Click to expand it.