17 #include <shogun/lib/external/libqp.h>
19 using namespace Eigen;
38 const malsar_options& options)
45 int n_tasks = options.n_tasks;
48 H_diag_matrix = SG_CALLOC(
double, n_tasks*n_tasks);
49 for (
int i=0; i<n_tasks; i++)
50 H_diag_matrix[i*n_tasks+i] = 2.0;
51 H_diag_matrix_ld = n_tasks;
56 MatrixXd Ws = MatrixXd::Zero(n_feats, n_tasks);
57 VectorXd Cs = VectorXd::Zero(n_tasks);
58 MatrixXd Ms = MatrixXd::Identity(n_tasks, n_tasks)*options.n_clusters/n_tasks;
63 MatrixXd Wz=Ws, Wzp=Ws, Wz_old=Ws, delta_Wzp=Ws, gWs=Ws;
64 VectorXd Cz=Cs, Czp=Cs, Cz_old=Cs, delta_Czp=Cs, gCs=Cs;
65 MatrixXd Mz=Ms, Mzp=Ms, Mz_old=Ms, delta_Mzp=Ms, gMs=Ms;
68 double eta = rho2/rho1;
69 double c = rho1*eta*(1+eta);
72 double gamma=1, gamma_inc=2;
73 double obj=0.0, obj_old=0.0;
75 double* diag_H = SG_MALLOC(
double, n_tasks);
76 double* f = SG_MALLOC(
double, n_tasks);
77 double* a = SG_MALLOC(
double, n_tasks);
78 double* lb = SG_MALLOC(
double, n_tasks);
79 double* ub = SG_MALLOC(
double, n_tasks);
80 double* x = SG_CALLOC(
double, n_tasks);
84 while (!done && iter <= options.max_iter)
86 double alpha = double(t_old - 1)/t;
90 Ws = (1+alpha)*Wz - alpha*Wz_old;
91 Cs = (1+alpha)*Cz - alpha*Cz_old;
92 Ms = (1+alpha)*Mz - alpha*Mz_old;
99 IM = (eta*MatrixXd::Identity(n_tasks,n_tasks)+Ms);
100 IMsqinv = (IM*IM).inverse();
101 invEtaMWt = IM.inverse()*Ws.transpose();
102 gMs.noalias() = -c*(Ws.transpose()*Ws)*IMsqinv;
103 gWs.noalias() += 2*c*invEtaMWt.transpose();
108 for (task=0; task<n_tasks; task++)
111 int n_vecs_task = task_idx.
vlen;
112 for (
int i=0; i<n_vecs_task; i++)
114 double aa = -y[task_idx[i]]*(features->
dense_dot(task_idx[i], Ws.col(task).data(), n_feats)+Cs[task]);
118 Fs += (CMath::log(CMath::exp(-bb) + CMath::exp(aa-bb)) + bb)/n_vecs_task;
119 double b = -y[task_idx[i]]*(1 - 1/(1+CMath::exp(aa)))/n_vecs_task;
127 Fs += c*(Ws*invEtaMWt).trace();
134 while (inner_iter <= 1)
136 Wzp = Ws - gWs/gamma;
137 Czp = Cs - gCs/gamma;
140 EigenSolver<MatrixXd> eigensolver;
141 eigensolver.compute(Ms-gMs/gamma,
true);
142 if (eigensolver.info()!=Eigen::Success)
147 for (
int i=0; i<n_tasks; i++)
153 f[i] = -2*eigensolver.eigenvalues()[i].real();
157 SG_SDEBUG(
"%dth eigenvalue %f\n",i,eigensolver.eigenvalues()[i].real())
161 x[i] = double(options.n_clusters)/n_tasks;
163 double b = options.n_clusters;
166 libqp_state_T problem_state = libqp_gsmo_solver(&
get_col,diag_H,f,a,b,lb,ub,x,n_tasks,1000,1e-6,NULL);
167 SG_SDEBUG(
"Libqp objective = %f\n",problem_state.QP)
168 SG_SDEBUG(
"Exit code = %d\n",problem_state.exitflag)
169 SG_SDEBUG(
"%d iteration passed\n",problem_state.nIter)
171 for (
int i=0; i<n_tasks; i++)
175 Mzp_Pz = eigensolver.eigenvectors().real();
176 Mzp = Mzp_Pz*Mzp_DiagSigz.asDiagonal()*Mzp_Pz.transpose();
179 for (
int i=0; i<n_tasks; i++)
180 Mzp_DiagSigz[i] += eta;
183 (Mzp_DiagSigz.cwiseInverse().asDiagonal())*
189 for (task=0; task<n_tasks; task++)
192 int n_vecs_task = task_idx.
vlen;
193 for (
int i=0; i<n_vecs_task; i++)
195 double aa = -y[task_idx[i]]*(features->
dense_dot(task_idx[i], Wzp.col(task).
data(), n_feats)+Cs[task]);
198 Fzp += (CMath::log(CMath::exp(-bb) + CMath::exp(aa-bb)) + bb)/n_vecs_task;
201 Fzp += c*(Wzp*invEtaMWt).trace();
204 delta_Wzp = Wzp - Ws;
205 delta_Czp = Czp - Cs;
206 delta_Mzp = Mzp - Ms;
209 double nrm_delta_Wzp = delta_Wzp.squaredNorm();
210 double nrm_delta_Czp = delta_Czp.squaredNorm();
211 double nrm_delta_Mzp = delta_Mzp.squaredNorm();
213 double r_sum = (nrm_delta_Wzp + nrm_delta_Czp + nrm_delta_Mzp)/3;
215 double Fzp_gamma = 0.0;
216 if (n_feats > n_tasks)
218 Fzp_gamma = Fs + (delta_Wzp.transpose()*gWs).trace() +
219 (delta_Czp.transpose()*gCs).trace() +
220 (delta_Mzp.transpose()*gMs).trace() +
221 (gamma/2)*nrm_delta_Wzp +
222 (gamma/2)*nrm_delta_Czp +
223 (gamma/2)*nrm_delta_Mzp;
227 Fzp_gamma = Fs + (gWs.transpose()*delta_Wzp).trace() +
228 (gCs.transpose()*delta_Czp).trace() +
229 (gMs.transpose()*delta_Mzp).trace() +
230 (gamma/2)*nrm_delta_Wzp +
231 (gamma/2)*nrm_delta_Czp +
232 (gamma/2)*nrm_delta_Mzp;
243 if (Fzp <= Fzp_gamma)
263 switch (options.termination)
268 if ( CMath::abs(obj-obj_old) <= options.tolerance )
275 if ( CMath::abs(obj-obj_old) <= options.tolerance*CMath::abs(obj_old))
280 if (CMath::abs(obj) <= options.tolerance)
284 if (iter>=options.max_iter)
291 t = 0.5 * (1 + CMath::sqrt(1.0 + 4*t*t));
294 SG_SDEBUG(
"%d iteration passed, objective = %f\n",iter,obj)
296 SG_FREE(H_diag_matrix);
305 for (
int i=0; i<n_feats; i++)
307 for (task=0; task<n_tasks; task++)
308 tasks_w(i,task) = Wzp(i,task);
312 for (
int i=0; i<n_tasks; i++) tasks_c[i] = Czp[i];
313 return malsar_result_t(tasks_w, tasks_c);
static const double * get_col(uint32_t j)
virtual float64_t dense_dot(int32_t vec_idx1, const float64_t *vec2, int32_t vec2_len)=0
virtual int32_t get_num_vectors() const =0
virtual void add_to_dense_vec(float64_t alpha, int32_t vec_idx1, float64_t *vec2, int32_t vec2_len, bool abs_val=false)=0
static double * H_diag_matrix
Features that support dot products among other operations.
virtual int32_t get_dim_feature_space() const =0
static int H_diag_matrix_ld
all of classes and functions are contained in the shogun namespace
malsar_result_t malsar_clustered(CDotFeatures *features, double *y, double rho1, double rho2, const malsar_options &options)
Matrix::Scalar max(Matrix m)