Line data Source code
1 : /**
2 : * @file gensvm_zv.c
3 : * @author G.J.J. van den Burg
4 : * @date 2016-10-17
5 : * @brief Functions for computing the ZV matrix product
6 : *
7 : * @details
8 : * This file exists because the product Z*V of two matrices occurs both in the
9 : * computation of the loss function and for predicting class labels. Moreover,
10 : * a distinction has to be made between dense Z matrices and sparse Z
11 : * matrices, hence a seperate file is warranted.
12 : *
13 : * @copyright
14 : Copyright 2016, G.J.J. van den Burg.
15 :
16 : This file is part of GenSVM.
17 :
18 : GenSVM is free software: you can redistribute it and/or modify
19 : it under the terms of the GNU General Public License as published by
20 : the Free Software Foundation, either version 3 of the License, or
21 : (at your option) any later version.
22 :
23 : GenSVM is distributed in the hope that it will be useful,
24 : but WITHOUT ANY WARRANTY; without even the implied warranty of
25 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 : GNU General Public License for more details.
27 :
28 : You should have received a copy of the GNU General Public License
29 : along with GenSVM. If not, see <http://www.gnu.org/licenses/>.
30 :
31 : */
32 :
33 : #include "gensvm_zv.h"
34 :
35 : /**
36 : * @brief Wrapper around sparse/dense versions of this function
37 : *
38 : * @details
39 : * This function tests if the data is stored in dense format or sparse format
40 : * by testing if GenData::Z is NULL or not, and calls the corresponding
41 : * version of this function accordingly.
42 : *
43 : * @sa
44 : * gensvm_calculate_ZV_dense(), gensvm_calculate_ZV_sparse()
45 : *
46 : * @param[in] model a GenModel instance holding the model
47 : * @param[in] data a GenData instance with the data
48 : * @param[out] ZV a pre-allocated matrix of appropriate dimensions
49 : */
50 478 : void gensvm_calculate_ZV(struct GenModel *model, struct GenData *data,
51 : double *ZV)
52 : {
53 478 : if (data->Z == NULL)
54 4 : gensvm_calculate_ZV_sparse(model, data, ZV);
55 : else
56 474 : gensvm_calculate_ZV_dense(model, data, ZV);
57 478 : }
58 :
59 : /**
60 : * @brief Compute the product Z*V for when Z is a sparse matrix
61 : *
62 : * @details
63 : * This is a simple sparse-dense matrix multiplication, which uses
64 : * cblas_daxpy() for each nonzero element of Z, to compute Z*V.
65 : *
66 : * @param[in] model a GenModel instance holding the model
67 : * @param[in] data a GenData instance with the data
68 : * @param[out] ZV a pre-allocated matrix of appropriate dimensions
69 : */
70 4 : void gensvm_calculate_ZV_sparse(struct GenModel *model,
71 : struct GenData *data, double *ZV)
72 : {
73 : long i, j, jj, jj_start, jj_end, K,
74 4 : n_row = data->spZ->n_row;
75 : double z_ij;
76 :
77 4 : K = model->K;
78 :
79 4 : long *Zia = data->spZ->ia;
80 4 : long *Zja = data->spZ->ja;
81 4 : double *vals = data->spZ->values;
82 :
83 35 : for (i=0; i<n_row; i++) {
84 31 : jj_start = Zia[i];
85 31 : jj_end = Zia[i+1];
86 :
87 143 : for (jj=jj_start; jj<jj_end; jj++) {
88 112 : j = Zja[jj];
89 112 : z_ij = vals[jj];
90 :
91 112 : cblas_daxpy(K-1, z_ij, &model->V[j*(K-1)], 1,
92 112 : &ZV[i*(K-1)], 1);
93 : }
94 : }
95 4 : }
96 :
97 : /**
98 : * @brief Compute the product Z*V for when Z is a dense matrix
99 : *
100 : * @details
101 : * This function uses cblas_dgemm() to compute the matrix product between Z
102 : * and V.
103 : *
104 : * @param[in] model a GenModel instance holding the model
105 : * @param[in] data a GenData instance with the data
106 : * @param[out] ZV a pre-allocated matrix of appropriate dimensions
107 : */
108 474 : void gensvm_calculate_ZV_dense(struct GenModel *model,
109 : struct GenData *data, double *ZV)
110 : {
111 : // use n from data, assume m and K are the same between model and data
112 474 : long n = data->n;
113 474 : long m = model->m;
114 474 : long K = model->K;
115 :
116 1896 : cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, K-1, m+1,
117 1896 : 1.0, data->Z, m+1, model->V, K-1, 0, ZV, K-1);
118 474 : }
|