Files
osilap/alpha_loop.c
T
2026-06-30 08:59:47 +09:00

255 lines
8.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "ilt.h"
/* ####################################################################### */
/* 最適化したfから圧縮無しのσ^2を求める */
/* ####################################################################### */
double CalcSigma(MATRIX *K1, MATRIX *K2, double *f, HEAD *head, INDATA *d){
int i, incr = 1;
int m1 = K1->m, m2 = K2->m;
int n1 = K1->n, n2 = K2->n;
int nn = n1*n2, mm = m1*m2;
int info;
double one=1.0, one_=-1.0, zero = 0.0, chi, sigma=0;
double *KF, *F, *M;
div_t temp;
if (head->dimension == 2){
KF = malloc(sizeof(double)*m1*n2);
F = malloc(sizeof(double)*nn);
M = malloc(sizeof(double)*m1*m2);
/* fから行列Fを生成 */
for (i=0; i<nn; i++){
temp = div(i, n2);
F[temp.rem*n1 + temp.quot] = f[i];
}
/* K1*Fの計算 */
dgemm_("N", "N", &m1, &n2, &n1, &one, K1->a, &m1,
F, &n1, &zero, KF, &m1, &info);
/* (K1*F)*K2Tの計算 */
dgemm_("N", "T", &m1, &m2, &n2, &one, KF, &m1,
K2->a, &m2, &zero, M, &m1, &info);
/* M = -Mexp + Mcalの計算 */
daxpy_(&mm, &one_, d->m.a, &incr, M, &incr);
/* ||Mcal - Msim|| */
chi = dnrm2_(&mm, M, &incr);
/* sigma = σ^2 = ||KF-M||^2/m */
sigma = chi*chi/mm;
free(KF);
free(F);
free(M);
}
if (head->dimension == 1){
M = malloc(sizeof(double)*m1);
dgemv_("N", &m1, &n1, &one, K1->a, &m1, f, &incr, &zero, M, &incr);
/* M = -Mexp + Mcalの計算 */
daxpy_(&m1, &one_, d->m.a, &incr, M, &incr);
chi = dnrm2_(&m1, M, &incr);
/* sigma = σ^2 = ||KF-M||^2/m */
sigma = chi*chi/m1;
free(M);
}
return sigma;
}
/* ####################################################################### */
/* Scurve法でalpha_optを求める */
/* ####################################################################### */
void ScurveAlphaLoop(MATRIX *K0, MATRIX *Mz, HEAD *head, double *f,
MATRIX *k1, MATRIX *k2, INDATA *d){
int m = K0->m;
int n = K0->n;
int i, j, pnt = 0, incr = 1;
int alpha_num=head->alpha_num;
double *kz, *mz, *cr, *aI, *H;
double alpha, sigma;
double zero = 0.0, one = 1.0;
double alpha_s = head->alpha_start, alpha_e = head->alpha_end;
double s_target=head->s_taget, alpha_log;
double *alpha_list, *sigma_list, *grad;
double *t = NULL;
kz = K0->a;
mz = Mz->a;
cr = malloc(sizeof(double)*m);
aI = malloc(sizeof(double)*m*m);
H = malloc(sizeof(double)*n*n);
alpha_list = (double *)malloc(sizeof(double)*alpha_num);
sigma_list = (double *)malloc(sizeof(double)*alpha_num);
grad = malloc(sizeof(double)*(alpha_num-1));
/* alphaのグリッド生成 */
for (i=0; i<alpha_num; i++){
alpha_log = alpha_s + (double)i*(alpha_e-alpha_s)/(alpha_num-1);
alpha_list[i] = pow(10, alpha_log);
}
/* alphaI (diagonal) とH (diagonal)の初期化 */
for (i=0; i<(n*n); i++) H[i] = 0.0;
for (i=0; i<m*m; i++) aI[i] = 0.0;
/* ここからalphaのloop */
for (j=alpha_num-1; j>=0; j--){
/* alphaI (diagonal)の初期化*/
for (i=0; i<m; i++) aI[i*(m+1)] = alpha_list[j];
/* BRDでcrの最適化 */
BRDnewton_modify(kz, mz, aI, cr, H, head, &m, &n);
/* crからfの計算 f= kz'*cr */
dgemv_("T", &m, &n, &one, kz, &m, cr, &incr, &zero, f, &incr);
/* fi>0 だけが解 */
for (i=0; i<n; i++) (f[i] < 0) ? (f[i] = 0.0) : (f[i] = f[i]);
/* 圧縮前のカーネルを使って圧縮ノイズの標準偏差を求める */
sigma_list[j] = CalcSigma(k1, k2, f, head, d);
head->alpha_loop++;
}
for (i=0; i<alpha_num-1; i++){
grad[i] = (log10(sigma_list[i+1]) - log10(sigma_list[i]))/
(log10(alpha_list[i+1]) - log10(alpha_list[i]));
if (grad[i] > s_target && pnt == 0) pnt = i;
}
double alpha_0, alpha_1, grad_0, grad_1;
double sigma_0, sigma_1;
int step;
alpha_0 = alpha_list[pnt-1];
sigma_0 = sigma_list[pnt-1];
alpha_1 = alpha_list[pnt+1];
sigma_1 = sigma_list[pnt+1];
for (step=1;; step++){
pnt = alpha_num+step;
alpha = alpha_0 + 0.5*(alpha_1 - alpha_0);
if ((t = (double *)realloc(alpha_list, pnt*sizeof(double))) != NULL){
alpha_list = t;
alpha_list[alpha_num+step-1] = alpha;
}
for (i=0; i<m; i++) aI[i*(m+1)] = alpha;
BRDnewton_modify(kz, mz, aI, cr, H, head, &m, &n);
dgemv_("T", &m, &n, &one, kz, &m, cr, &incr, &zero, f, &incr);
for (i=0; i<n; i++) (f[i] < 0) ? (f[i] = 0.0) : (f[i] = f[i]);
sigma = CalcSigma(k1, k2, f, head, d);
if ((t = (double *)realloc(sigma_list, pnt*sizeof(double))) != NULL){
sigma_list = t;
sigma_list[pnt-1] = sigma;
}
grad_0 = (log10(sigma) - log10(sigma_0))/(log10(alpha) - log10(alpha_0));
grad_1 = (log10(sigma_1) - log10(sigma))/(log10(alpha_1) - log10(alpha));
if (fabs(s_target - grad_0) < fabs(s_target - grad_1) ){
alpha_1 = alpha;
sigma_1 = sigma;
}
else {
alpha_0 = alpha;
sigma_0 = sigma;
}
head->alpha = alpha;
if ((alpha_1 - alpha_0) < head->alpha_tol) break;
printf("delta alpha = %g\n", alpha_1 - alpha_0);
printf("grad0 = %g\n", grad_0);
printf("grad1 = %g\n", grad_1);
head->alpha_loop++;
}
head->alpha_list = malloc(pnt*sizeof(double));
head->sigma_list = malloc(pnt*sizeof(double));
head->alpha_num = pnt;
for (i=0; i<pnt; i++){
head->alpha_list[i] = alpha_list[i];
head->sigma_list[i] = sigma_list[i];
}
free(cr);
free(aI);
free(H);
free(alpha_list);
free(sigma_list);
free(grad);
}
void BRDAlphaLoop(MATRIX *K0, MATRIX *Mz, HEAD *head, double *f,
MATRIX *k1, MATRIX *k2, INDATA *d){
int m = K0->m;
int n = K0->n;
int i, incr = 1;
double *kz, *mz;
double *cr, *cr_n;
double *aI, *H;
double zero = 0.0, one = 1.0, one_ = -1.0;
double alpha_opt, cr_norm, sigma, sigma_z;
if (head->alpha0 == 0) {
head->alpha = 0.0;
return;
}
kz = K0->a;
mz = Mz->a;
cr = malloc(sizeof(double)*m);
cr_n = malloc(sizeof(double)*m);
aI = malloc(sizeof(double)*m*m);
H = malloc(sizeof(double)*n*n);
/* 初期のfからcrを求める cr=-(Kf-m)/alpha */
dgemv_("N", &m, &n, &one, kz, &m, f, &incr, &zero, cr, &incr);
daxpy_(&m, &one_, mz, &incr, cr, &incr);
alpha_opt = -1.0/head->alpha0;
dscal_(&m, &alpha_opt, cr, &incr);
head->alpha = head->alpha0;
/* alphaI (diagonal) とH (diagonal)の初期化 */
for (i=0; i<(n*n); i++) H[i] = 0.0;
for (i=0; i<m*m; i++) aI[i] = 0.0;
/* for (i=0; i<m; i++) cr[i] = 0.0; */
/* ここからalphaのloop */
for (head->alpha_loop=0;; head->alpha_loop++){
/* alphaI (diagonal)の初期化*/
for (i=0; i<m; i++) aI[i*(m+1)] = head->alpha;
/* BRDでcrの最適化 */
cr_norm = BRDnewton_modify(kz, mz, aI, cr, H, head, &m, &n);
/* crからfの計算f f= kz'*cr, fi>0 だけが解 */
dgemv_("T", &m, &n, &one, kz, &m, cr, &incr, &zero, f, &incr);
for (i=0; i<n; i++) (f[i] < 0) ? (f[i] = 0.0) : (f[i] = f[i]);
/* 圧縮前のカーネルを使って圧縮ノイズの標準偏差を求める */
sigma = sqrt(CalcSigma(k1, k2, f, head, d));
printf("uncompressed sigma = %g\n", sigma);
/* 圧縮のカーネルを使ってcrを求める */
dgemv_("N", &m, &n, &one, kz, &m, f, &incr, &zero, cr_n, &incr);
daxpy_(&m, &one_, mz, &incr, cr_n, &incr); /* kz*f - mz */
sigma_z = dnrm2_(&m, cr_n, &incr)/sqrt(m);
printf("compressed sigma = %g\n", sigma_z);
if (head->sigma0 != 0.0) sigma = head->sigma0;
printf("c_norm = %g\n", cr_norm);
switch(head->Atype){
case 0:
alpha_opt = sigma/sigma_z;
break;
case 1:
alpha_opt = sigma_z/dnrm2_(&n, f, &incr)/(sqrt(1-sqrt(2*m)/m));
break;
case 2:
alpha_opt = sigma_z/dnrm2_(&n, f, &incr);
break;
case 3:
alpha_opt = sigma/dnrm2_(&n, f, &incr)/(sqrt(1-sqrt(2*m)/m));
break;
}
/* alphaの収束チェック */
if (fabs(alpha_opt - head->alpha)/head->alpha < head->alpha_tol)
break;
/* alphaをmixingしてupdate */
if (head->alpha_loop > 1)
head->alpha = alpha_opt;
else
head->alpha_loop++;
if (head->alpha_loop == head->alpha_loop_max) {
printf("Iteration reached maximum alpha loop.\n");
break;
}
}
free(cr_n);
free(cr);
free(aI);
free(H);
}