18 #include <shogun/lib/external/libqp.h>
20 using namespace Eigen;
26 static double* H_diag_matrix;
27 static int H_diag_matrix_ld;
29 static const double* get_col(uint32_t j)
31 return H_diag_matrix + j*H_diag_matrix_ld;
34 malsar_result_t malsar_clustered(
35 CDotFeatures* features,
39 const malsar_options& options)
42 int n_feats = features->get_dim_feature_space();
44 int n_vecs = features->get_num_vectors();
46 int n_tasks = options.n_tasks;
49 H_diag_matrix = SG_CALLOC(
double, n_tasks*n_tasks);
50 for (
int i=0; i<n_tasks; i++)
51 H_diag_matrix[i*n_tasks+i] = 2.0;
52 H_diag_matrix_ld = n_tasks;
58 VectorXd Cs = VectorXd::Zero(n_tasks);
59 MatrixXd Ms =
MatrixXd::Identity(n_tasks, n_tasks)*options.n_clusters/n_tasks;
64 MatrixXd Wz=Ws, Wzp=Ws, Wz_old=Ws, delta_Wzp=Ws, gWs=Ws;
65 VectorXd Cz=Cs, Czp=Cs, Cz_old=Cs, delta_Czp=Cs, gCs=Cs;
66 MatrixXd Mz=Ms, Mzp=Ms, Mz_old=Ms, delta_Mzp=Ms, gMs=Ms;
69 double eta = rho2/rho1;
70 double c = rho1*eta*(1+eta);
73 double gamma=1, gamma_inc=2;
74 double obj=0.0, obj_old=0.0;
76 double* diag_H = SG_MALLOC(
double, n_tasks);
77 double* f = SG_MALLOC(
double, n_tasks);
78 double* a = SG_MALLOC(
double, n_tasks);
79 double* lb = SG_MALLOC(
double, n_tasks);
80 double* ub = SG_MALLOC(
double, n_tasks);
81 double* x = SG_CALLOC(
double, n_tasks);
85 while (!done && iter <= options.max_iter)
87 double alpha = double(t_old - 1)/t;
91 Ws = (1+alpha)*Wz - alpha*Wz_old;
92 Cs = (1+alpha)*Cz - alpha*Cz_old;
93 Ms = (1+alpha)*Mz - alpha*Mz_old;
100 IM = (eta*
MatrixXd::Identity(n_tasks,n_tasks)+Ms);
101 IMsqinv = (IM*IM).inverse();
102 invEtaMWt = IM.inverse()*Ws.transpose();
103 gMs.noalias() = -c*(Ws.transpose()*Ws)*IMsqinv;
104 gWs.noalias() += 2*c*invEtaMWt.transpose();
109 for (task=0; task<n_tasks; task++)
111 SGVector<index_t> task_idx = options.tasks_indices[task];
112 int n_vecs_task = task_idx.vlen;
113 for (
int i=0; i<n_vecs_task; i++)
115 double aa = -y[task_idx[i]]*(features->dense_dot(task_idx[i], Ws.col(task).data(), n_feats)+Cs[task]);
119 Fs += (CMath::log(CMath::exp(-bb) + CMath::exp(aa-bb)) + bb)/n_vecs_task;
120 double b = -y[task_idx[i]]*(1 - 1/(1+CMath::exp(aa)))/n_vecs_task;
122 features->add_to_dense_vec(b, task_idx[i], gWs.col(task).data(), n_feats);
128 Fs += c*(Ws*invEtaMWt).trace();
135 while (inner_iter <= 1)
137 Wzp = Ws - gWs/gamma;
138 Czp = Cs - gCs/gamma;
141 EigenSolver<MatrixXd> eigensolver;
142 eigensolver.compute(Ms-gMs/gamma,
true);
143 if (eigensolver.info()!=Eigen::Success)
148 for (
int i=0; i<n_tasks; i++)
154 f[i] = -2*eigensolver.eigenvalues()[i].real();
158 SG_SDEBUG("%dth eigenvalue %f\n",i,eigensolver.eigenvalues()[i].real())
162 x[i] =
double(options.n_clusters)/n_tasks;
164 double b = options.n_clusters;
167 libqp_state_T problem_state = libqp_gsmo_solver(&get_col,diag_H,f,a,b,lb,ub,x,n_tasks,1000,1e-6,NULL);
168 SG_SDEBUG("Libqp objective = %f\n",problem_state.QP)
169 SG_SDEBUG("Exit code = %d\n",problem_state.exitflag)
170 SG_SDEBUG("%d iteration passed\n",problem_state.nIter)
172 for (
int i=0; i<n_tasks; i++)
175 Map<VectorXd> Mzp_DiagSigz(x,n_tasks);
176 Mzp_Pz = eigensolver.eigenvectors().real();
177 Mzp = Mzp_Pz*Mzp_DiagSigz.asDiagonal()*Mzp_Pz.transpose();
180 for (
int i=0; i<n_tasks; i++)
181 Mzp_DiagSigz[i] += eta;
184 (Mzp_DiagSigz.cwiseInverse().asDiagonal())*
190 for (task=0; task<n_tasks; task++)
192 SGVector<index_t> task_idx = options.tasks_indices[task];
193 int n_vecs_task = task_idx.vlen;
194 for (
int i=0; i<n_vecs_task; i++)
196 double aa = -y[task_idx[i]]*(features->dense_dot(task_idx[i], Wzp.col(task).data(), n_feats)+Cs[task]);
199 Fzp += (CMath::log(CMath::exp(-bb) + CMath::exp(aa-bb)) + bb)/n_vecs_task;
202 Fzp += c*(Wzp*invEtaMWt).trace();
205 delta_Wzp = Wzp - Ws;
206 delta_Czp = Czp - Cs;
207 delta_Mzp = Mzp - Ms;
210 double nrm_delta_Wzp = delta_Wzp.squaredNorm();
211 double nrm_delta_Czp = delta_Czp.squaredNorm();
212 double nrm_delta_Mzp = delta_Mzp.squaredNorm();
214 double r_sum = (nrm_delta_Wzp + nrm_delta_Czp + nrm_delta_Mzp)/3;
216 double Fzp_gamma = 0.0;
217 if (n_feats > n_tasks)
219 Fzp_gamma = Fs + (delta_Wzp.transpose()*gWs).trace() +
220 (delta_Czp.transpose()*gCs).trace() +
221 (delta_Mzp.transpose()*gMs).trace() +
222 (gamma/2)*nrm_delta_Wzp +
223 (gamma/2)*nrm_delta_Czp +
224 (gamma/2)*nrm_delta_Mzp;
228 Fzp_gamma = Fs + (gWs.transpose()*delta_Wzp).trace() +
229 (gCs.transpose()*delta_Czp).trace() +
230 (gMs.transpose()*delta_Mzp).trace() +
231 (gamma/2)*nrm_delta_Wzp +
232 (gamma/2)*nrm_delta_Czp +
233 (gamma/2)*nrm_delta_Mzp;
244 if (Fzp <= Fzp_gamma)
264 switch (options.termination)
269 if ( CMath::abs(obj-obj_old) <= options.tolerance )
276 if ( CMath::abs(obj-obj_old) <= options.tolerance*CMath::abs(obj_old))
281 if (CMath::abs(obj) <= options.tolerance)
285 if (iter>=options.max_iter)
292 t = 0.5 * (1 + CMath::sqrt(1.0 + 4*t*t));
295 SG_SDEBUG(
"%d iteration passed, objective = %f\n",iter,obj)
297 SG_FREE(H_diag_matrix);
305 SGMatrix<
float64_t> tasks_w(n_feats, n_tasks);
306 for (
int i=0; i<n_feats; i++)
308 for (task=0; task<n_tasks; task++)
309 tasks_w(i,task) = Wzp(i,task);
312 SGVector<float64_t> tasks_c(n_tasks);
313 for (
int i=0; i<n_tasks; i++) tasks_c[i] = Czp[i];
314 return malsar_result_t(tasks_w, tasks_c);
318 #endif //USE_GPL_SHOGUN
all of classes and functions are contained in the shogun namespace
Matrix::Scalar max(Matrix m)