/** * The update rule for the basis matrix W. * The function takes in all the matrices and only changes the * value of the W matrix. * * @param V Input matrix to be factorized. * @param W Basis matrix to be updated. * @param H Encoding matrix. */ inline void WUpdate(const arma::sp_mat& V, arma::mat& W, const arma::mat& H) { if(!isStart) (*it)++; else isStart = false; if(*it == V.end()) { delete it; it = new arma::sp_mat::const_iterator(V.begin()); } size_t currentUserIndex = it->col(); size_t currentItemIndex = it->row(); arma::mat deltaW(1, W.n_cols); deltaW.zeros(); deltaW += (**it - arma::dot(W.row(currentItemIndex), H.col(currentUserIndex))) * arma::trans(H.col(currentUserIndex)); if(kw != 0) deltaW -= kw * W.row(currentItemIndex); W.row(currentItemIndex) += u*deltaW; }
// [[Rcpp::export]] arma::sp_mat sparseIterators(arma::sp_mat SM, double val) { arma::sp_mat::iterator begin = SM.begin(); arma::sp_mat::iterator end = SM.end(); for (arma::sp_mat::iterator it = begin; it != end; ++it) (*it) += val; return SM; }
/** * Solve the following KKT system (2.10) of [AHO98]: * * [ 0 A^T I ] [ dsx ] = [ rd ] * [ A 0 0 ] [ dy ] = [ rp ] * [ E 0 F ] [ dsz ] = [ rc ] * \---- M ----/ * * where * * A = [ Asparse ] * [ Adense ] * dy = [ dysparse dydense ] * E = Z sym I * F = X sym I * */ static inline void SolveKKTSystem(const arma::sp_mat& Asparse, const arma::mat& Adense, const arma::mat& Z, const arma::mat& M, const arma::mat& F, const arma::vec& rp, const arma::vec& rd, const arma::vec& rc, arma::vec& dsx, arma::vec& dysparse, arma::vec& dydense, arma::vec& dsz) { arma::mat Frd_rc_Mat, Einv_Frd_rc_Mat, Einv_Frd_ATdy_rc_Mat, Frd_ATdy_rc_Mat; arma::vec Einv_Frd_rc, Einv_Frd_ATdy_rc, dy; // Note: Whenever a formula calls for E^(-1) v for some v, we solve Lyapunov // equations instead of forming an explicit inverse. // Compute the RHS of (2.12) math::Smat(F * rd - rc, Frd_rc_Mat); SolveLyapunov(Einv_Frd_rc_Mat, Z, 2. * Frd_rc_Mat); math::Svec(Einv_Frd_rc_Mat, Einv_Frd_rc); arma::vec rhs = rp; const size_t numConstraints = Asparse.n_rows + Adense.n_rows; if (Asparse.n_rows) rhs(arma::span(0, Asparse.n_rows - 1)) += Asparse * Einv_Frd_rc; if (Adense.n_rows) rhs(arma::span(Asparse.n_rows, numConstraints - 1)) += Adense * Einv_Frd_rc; // TODO(stephentu): use a more efficient method (e.g. LU decomposition) if (!arma::solve(dy, M, rhs)) Log::Fatal << "PrimalDualSolver::SolveKKTSystem(): Could not solve KKT " << "system." << std::endl; if (Asparse.n_rows) dysparse = dy(arma::span(0, Asparse.n_rows - 1)); if (Adense.n_rows) dydense = dy(arma::span(Asparse.n_rows, numConstraints - 1)); // Compute dx from (2.13) math::Smat(F * (rd - Asparse.t() * dysparse - Adense.t() * dydense) - rc, Frd_ATdy_rc_Mat); SolveLyapunov(Einv_Frd_ATdy_rc_Mat, Z, 2. * Frd_ATdy_rc_Mat); math::Svec(Einv_Frd_ATdy_rc_Mat, Einv_Frd_ATdy_rc); dsx = -Einv_Frd_ATdy_rc; // Compute dz from (2.14) dsz = rd - Asparse.t() * dysparse - Adense.t() * dydense; }
void CalculateEdgeLengths(vtkPolyData* mesh, arma::sp_mat& edge_lengths) { vtkSmartPointer<vtkIdList> cellIdList = vtkSmartPointer<vtkIdList>::New(); vtkSmartPointer<vtkIdList> pointIdList = vtkSmartPointer<vtkIdList>::New(); const int npts = mesh->GetNumberOfPoints(); edge_lengths.set_size(npts, npts); for (vtkIdType i = 0; i < npts; i++) { cellIdList->Reset(); mesh->GetPointCells(i, cellIdList); double *pt1 = mesh->GetPoint(i); for (vtkIdType j = 0; j < cellIdList->GetNumberOfIds(); j++) { pointIdList->Reset(); mesh->GetCellPoints(cellIdList->GetId(i), pointIdList); for (vtkIdType k = 0; k < pointIdList->GetNumberOfIds(); k++) { vtkIdType pt2_id = pointIdList->GetId(k); if (pt2_id != i) { //not the same point if (edge_lengths(i, pt2_id) != 0) { //is not calculated yet double *pt2 = mesh->GetPoint(pt2_id); const double dx = pt1[0] - pt2[0]; const double dy = pt1[1] - pt2[1]; const double dz = pt1[2] - pt2[2]; const double d = sqrt(dx * dx + dy * dy + dz * dz); edge_lengths(i, pt2_id) = d; edge_lengths(pt2_id, i) = d; } } } } } }
void Initialize(const arma::sp_mat& dataset, const size_t rank) { (void)rank; n = dataset.n_rows; m = dataset.n_cols; it = new arma::sp_mat::const_iterator(dataset.begin()); isStart = true; }
inline void SVDIncompleteIncrementalLearning:: WUpdate<arma::sp_mat>(const arma::sp_mat& V, arma::mat& W, const arma::mat& H) { arma::mat deltaW(n, W.n_cols); deltaW.zeros(); for(arma::sp_mat::const_iterator it = V.begin_col(currentUserIndex); it != V.end_col(currentUserIndex);it++) { double val = *it; size_t i = it.row(); deltaW.row(i) += (val - arma::dot(W.row(i), H.col(currentUserIndex))) * arma::trans(H.col(currentUserIndex)); if(kw != 0) deltaW.row(i) -= kw * W.row(i); } W += u*deltaW; }
/** * Create an unweighted graph laplacian from the edges. */ void CreateSparseGraphLaplacian(const arma::mat& edges, arma::sp_mat& laplacian) { // Get the number of vertices in the problem. const size_t vertices = max(max(edges)) + 1; laplacian.zeros(vertices, vertices); for (size_t i = 0; i < edges.n_cols; ++i) { laplacian(edges(0, i), edges(1, i)) = -1.0; laplacian(edges(1, i), edges(0, i)) = -1.0; } for (size_t i = 0; i < vertices; ++i) { laplacian(i, i) = -arma::accu(laplacian.row(i)); } }
void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, const size_t i, arma::sp_mat& gradient) const { gradient.set_size(n); const size_t p = visitationOrder[i]; gradient[p] = 400 * (std::pow(coordinates[p], 3) - coordinates[p] * coordinates[p + 1]) + 2 * (coordinates[p] - 1); gradient[p + 1] = 200 * (coordinates[p + 1] - std::pow(coordinates[p], 2)); }
inline void SVDIncompleteIncrementalLearning:: HUpdate<arma::sp_mat>(const arma::sp_mat& V, const arma::mat& W, arma::mat& H) { arma::mat deltaH(H.n_rows, 1); deltaH.zeros(); for(arma::sp_mat::const_iterator it = V.begin_col(currentUserIndex); it != V.end_col(currentUserIndex);it++) { double val = *it; size_t i = it.row(); if((val = V(i, currentUserIndex)) != 0) deltaH += (val - arma::dot(W.row(i), H.col(currentUserIndex))) * arma::trans(W.row(i)); } if(kh != 0) deltaH -= kh * H.col(currentUserIndex); H.col(currentUserIndex++) += u * deltaH; currentUserIndex = currentUserIndex % m; }
void CalculateInversiveDistanceE2(const arma::sp_mat& l, const arma::vec& gamma, arma::sp_mat& I) { const int npts = gamma.n_elem; I.set_size(npts, npts); //the measure is symmetric, process only upper triangle for (int i = 0; i < npts; i++) { for (int j = i + 1; j < npts; j++) { if (l(i, j) > 0) { //only for existing edges const double I_ij = (l(i, j) * l(i, j) - gamma(i) * gamma(i) - gamma(j) * gamma(j)) / (2 * gamma(i) * gamma(j)); I(i, j) = I_ij; I(j, i) = I_ij; } } } }
void CalculateGeneralizedEdgeLengthsE2(const arma::vec& gamma, const arma::sp_mat& I, arma::sp_mat& gen_edge_lengths) { const int npts = gamma.n_elem; gen_edge_lengths.set_size(npts, npts); //the measure is symmetric, process only upper triangle for (int i = 0; i < npts; i++) { for (int j = i + 1; j < npts; j++) { if (I(i, j) > 0) { //only for existing edges const double l_ij = sqrt(gamma(i) * gamma(i) + gamma(j) * gamma(j) + 2 * gamma(i) * gamma(j) * I(i, j)); gen_edge_lengths(i, j) = l_ij; gen_edge_lengths(j, i) = l_ij; } } } }
void LogisticRegressionFunction<MatType>::PartialGradient( const arma::mat& parameters, const size_t j, arma::sp_mat& gradient) const { const arma::rowvec diffs = responses - (1 / (1 + arma::exp(-parameters(0, 0) - parameters.tail_cols(parameters.n_elem - 1) * predictors))); gradient.set_size(arma::size(parameters)); if (j == 0) { gradient[j] = -arma::accu(diffs); } else { gradient[j] = arma::dot(-predictors.row(j - 1), diffs) + lambda * parameters(0, j); } }
//' Compute ego/alter edge coordinates considering alter's size and aspect ratio //' //' Given a graph, vertices' positions and sizes, calculates the absolute positions //' of the endpoints of the edges considering the plot's aspect ratio. //' //' @param graph A square matrix of size \eqn{n}. Adjacency matrix. //' @param toa Integer vector of size \eqn{n}. Times of adoption. //' @param x Numeric vector of size \eqn{n}. x-coordinta of vertices. //' @param y Numeric vector of size \eqn{n}. y-coordinta of vertices. //' @param vertex_cex Numeric vector of size \eqn{n}. Vertices' sizes in terms //' of the x-axis (see \code{\link{symbols}}). //' @param undirected Logical scalar. Whether the graph is undirected or not. //' @param no_contemporary Logical scalar. Whether to return (compute) edges' //' coordiantes for vertices with the same time of adoption (see details). //' @param dev Numeric vector of size 2. Height and width of the device (see details). //' @param ran Numeric vector of size 2. Range of the x and y axis (see details). //' @param curved Logical vector. //' @return A numeric matrix of size \eqn{m\times 5}{m * 5} with the following //' columns: //' \item{x0, y0}{Edge origin} //' \item{x1, y1}{Edge target} //' \item{alpha}{Relative angle between \code{(x0,y0)} and \code{(x1,y1)} in terms //' of radians} //' With \eqn{m} as the number of resulting edges. //' @details //' //' In order to make the plot's visualization more appealing, this function provides //' a straight forward way of computing the tips of the edges considering the //' aspect ratio of the axes range. In particular, the following corrections are //' made at the moment of calculating the egdes coords: //' //' \itemize{ //' \item{Instead of using the actual distance between ego and alter, a relative //' one is calculated as follows //' \deqn{d'=\left[(x_0-x_1)^2 + (y_0' - y_1')^2\right]^\frac{1}{2}}{d'=sqrt[(x0-x1)^2 + (y0'-y1')^2]} //' where \eqn{% //' y_i'=y_i\times\frac{\max x - \min x}{\max y - \min y} }{% //' yi' = yi * [max(x) - min(x)]/[max(y) - min(y)]} //' } //' \item{Then, for the relative elevation angle, \code{alpha}, the relative distance \eqn{d'} //' is used, \eqn{\alpha'=\arccos\left( (x_0 - x_1)/d' \right)}{\alpha' = acos[ (x0 - x1)/d' ]}} //' \item{Finally, the edge's endpoint's (alter) coordinates are computed as follows: % //' \deqn{% //' x_1' = x_1 + \cos(\alpha')\times v_1}{% //' x1' = x1 + cos(\alpha') * v1 //' } //' \deqn{% //' y_1' = y_1 -+ \sin(\alpha')\times v_1 \times\frac{\max y - \min y}{\max x - \min x} }{% //' y1' = y1 -+ sin(\alpha')*[max(y) - min(y)]/[max(x) - min(x)] //' } //' Where \eqn{v_1}{v1} is alter's size in terms of the x-axis, and the sign of //' the second term in \eqn{y_1'}{y1'} is negative iff \eqn{y_0 < y_1}{y0<y1}. //' } //' } //' //' The same process (with sign inverted) is applied to the edge starting piont. //' The resulting values, \eqn{x_1',y_1'}{x1',y1'} can be used with the function //' \code{\link{arrows}}. This is the workhorse function used in \code{\link{plot_threshold}}. //' //' The \code{dev} argument provides a reference to rescale the plot accordingly //' to the device, and former, considering the size of the margins as well (this //' can be easily fetched via \code{par("pin")}, plot area in inches). //' //' On the other hand, \code{ran} provides a reference for the adjustment //' according to the range of the data, this is \code{range(x)[2] - range(x)[1]} //' and \code{range(y)[2] - range(y)[1]} respectively. //' //' @keywords misc dplot //' @examples //' # -------------------------------------------------------------------------- //' data(medInnovationsDiffNet) //' library(sna) //' //' # Computing coordinates //' set.seed(79) //' coords <- sna::gplot(as.matrix(medInnovationsDiffNet$graph[[1]])) //' //' # Getting edge coordinates //' vcex <- rep(1.5, nnodes(medInnovationsDiffNet)) //' ecoords <- edges_coords( //' medInnovationsDiffNet$graph[[1]], //' diffnet.toa(medInnovationsDiffNet), //' x = coords[,1], y = coords[,2], //' vertex_cex = vcex, //' dev = par("pin") //' ) //' //' ecoords <- as.data.frame(ecoords) //' //' # Plotting //' symbols(coords[,1], coords[,2], circles=vcex, //' inches=FALSE, xaxs="i", yaxs="i") //' //' with(ecoords, arrows(x0,y0,x1,y1, length=.1)) //' @export // [[Rcpp::export]] NumericMatrix edges_coords( const arma::sp_mat & graph, const arma::colvec & toa, const arma::colvec & x, const arma::colvec & y, const arma::colvec & vertex_cex, bool undirected=true, bool no_contemporary=true, NumericVector dev = NumericVector::create(), NumericVector ran = NumericVector::create(), LogicalVector curved = LogicalVector::create() ) { // The output matrix has the following // - x0 and y0 // - x1 and y1 // - alpha std::vector< double > x0; std::vector< double > y0; std::vector< double > x1; std::vector< double > y1; std::vector< double > alpha; // Rescaling the vertex sizes arma::colvec vertex_size(vertex_cex); // If yexpand is too small, just throw an error if (ran.length() == 0) { ran = NumericVector::create(2); ran[0] = x.max() - x.min(); ran[1] = y.max() - y.min(); } // Expansion factor for y double yexpand = 1.0; if ( ran[1] > 1e-5 ) yexpand = ran[1]/ran[0]; // Adjusting for device size if (dev.length() == 0) dev = NumericVector::create(2,1.0); // Curved? if (curved.length() == 0) curved = LogicalVector::create(graph.n_nonzero, true); yexpand = yexpand * (dev[0]/dev[1]); for(arma::sp_mat::const_iterator it = graph.begin(); it != graph.end(); ++it) { int i = it.row(); int j = it.col(); // Checking conditions if (undirected && (i < j)) continue; if (no_contemporary && (toa(i)==toa(j)) ) continue; // Computing angle double a = atan2((y(j) - y(i))/yexpand, x(j) - x(i)); alpha.push_back(a); // Adding the xs and the ys x0.push_back(x.at(i) + cos(a)*vertex_size.at(i)); x1.push_back(x.at(j) - cos(a)*vertex_size.at(j)); // The formula needs an extra help to figure out the ys y0.push_back(y.at(i) + sin(a)*vertex_size.at(i)*yexpand); y1.push_back(y.at(j) - sin(a)*vertex_size.at(j)*yexpand); } // Building up the output int e = x0.size(); NumericMatrix out(e,5); for(int i=0; i<e; ++i) { out(i,0) = x0[i]; out(i,1) = y0[i]; out(i,2) = x1[i]; out(i,3) = y1[i]; out(i,4) = alpha[i]; } colnames(out) = CharacterVector::create("x0", "y0", "x1", "y1", "alpha"); return out; }
// [[Rcpp::export]] arma::sp_mat sparseTranspose(arma::sp_mat SM) { return SM.t(); }
// compute the log likelihood and its gradient w.r.t. theta int dtq::compGrad(void) { // remember, everything here is for equispaced data // we'll save the non-equispaced case for our scala + spark code :) if ((! haveData) || (! haveMyh)) return 1; if (spi<1) return 1; loglikmat = arma::zeros(ltvec-1,numts); if (spi==1) // special case { } else { // strategy: precompute and store common elements in Mats and Cubs // compute gradf and gradg at all spatial grid points arma::mat gradfy = arma::zeros(ylen,curtheta.n_elem); arma::mat gradgy = arma::zeros(ylen,curtheta.n_elem); this->gradFGyvec(gradfy, gradgy); // ompute gradf and gradg at all the data points arma::cube gradfdata = arma::zeros(curtheta.n_elem, (ltvec-1), numts); arma::cube gradgdata = arma::zeros(curtheta.n_elem, (ltvec-1), numts); this->gradFGdata(gradfdata, gradgdata); // initialize cubes to store all states and adjoints, // at all internal time points (spi-1), // for each pair of time series points (ltvec-1), // and at all spatial grid points (ylen) arma::cube dtqcube = arma::zeros(ylen,(ltvec-1),(spi-1)); arma::cube adjcube = arma::zeros(ylen,(ltvec-1),(spi-1)); // temporary matrix to store the initial state, phatinit arma::mat phatinit = arma::zeros(ylen,(ltvec-1)); // cube to store the gradient of the initial state w.r.t. theta arma::cube phatgrad = arma::zeros(ylen,(ltvec-1),curtheta.n_elem); // build the big matrix of initial conditions // and the gradients of those initial conditions! this->phatinitgrad(phatinit, phatgrad, gradfdata, gradgdata); dtqcube.slice(0) = phatinit; // propagate states forward in time by (spi-2) steps if (spi >= 3) for (int i=1; i<=(spi-2); i++) dtqcube.slice(i) = myk * prop * dtqcube.slice(i-1); // now multiply on the left by the Gamma vectors const arma::vec muvec = yvec + fy*myh; const arma::vec sigvec = gy*sqrt(myh); arma::cube allgamma = arma::zeros(ylen,numts,(ltvec-1)); for (int j=0; j<(ltvec-1); j++) { for (int l=0; l<numts; l++) { allgamma.slice(j).col(l) = myk*gausspdf((*odata)(j+1,l),muvec,sigvec); loglikmat(j,l) = log(arma::dot(allgamma.slice(j).col(l),dtqcube.slice(spi-2).col(j))); } } // std::cout << loglikmat << '\n'; // initialize the adjoint calculation for (int j=0; j<(ltvec-1); j++) for (int l=0; l<numts; l++) adjcube.slice(spi-2).col(j) += allgamma.slice(j).col(l) / exp(loglikmat(j,l)); // propagate adjoints backward in time by (spi-2) steps arma::sp_mat transprop = prop.t(); if (spi >= 3) for (int i=(spi-2); i>=1; i--) adjcube.slice(i-1) = myk * transprop * adjcube.slice(i); // stuff that we need for a bunch of gradients gradloglik = arma::zeros(curtheta.n_elem); arma::vec gvecm1 = arma::pow(gy,-1); arma::vec gvecm2 = arma::pow(gy,-2); arma::vec gvecm3 = arma::pow(gy,-3); // actual gradient calculation // proceed element-wise through theta_i for (int i=0; i<curtheta.n_elem; i++) { arma::vec temp1 = gvecm2 % gradfy.col(i); arma::vec temp2 = gvecm1 % gradgy.col(i); arma::vec temp3 = (1.0/myh)*gvecm3 % gradgy.col(i); arma::sp_mat::const_iterator start = prop.begin(); arma::sp_mat::const_iterator end = prop.end(); arma::umat dkdtloc(2, prop.n_nonzero); arma::vec dkdtval(prop.n_nonzero); unsigned int dkdtc = 0; for (arma::sp_mat::const_iterator it = start; it != end; ++it) { dkdtloc(0,dkdtc) = it.row(); dkdtloc(1,dkdtc) = it.col(); dkdtc++; } #pragma omp parallel for for (unsigned int dkdtcount=0; dkdtcount < prop.n_nonzero; dkdtcount++) { unsigned int orow = dkdtloc(0,dkdtcount); unsigned int ocol = dkdtloc(1,dkdtcount); double comval = yvec(orow) - muvec(ocol); dkdtval(dkdtcount) = myk*(prop.values[dkdtcount])*( comval*temp1(ocol) - temp2(ocol) + temp3(ocol)*comval*comval ); } arma::sp_mat dkdtheta(dkdtloc, dkdtval, ylen, ylen, false, true); // implement formula (22) from the DSAA paper // need gradient of Gamma{F-1} double tally = 0.0; #pragma omp parallel for reduction(+:tally) for (int j=0; j<(ltvec-1); j++) { tally += arma::dot(phatgrad.slice(i).col(j),adjcube.slice(0).col(j)); } #pragma omp parallel for collapse(2) reduction(+:tally) for (int j=0; j<(ltvec-1); j++) for (int l=0; l<numts; l++) { double xi = (*odata)((j+1),l); arma::vec gammagrad = (xi-muvec) % temp1; gammagrad += arma::pow(xi-muvec,2) % temp3; gammagrad -= temp2; gammagrad = gammagrad % allgamma.slice(j).col(l); tally += arma::dot(gammagrad,dtqcube.slice(spi-2).col(j)) / exp(loglikmat(j,l)); } // we have tested and found that the dot product is better than the // triple matrix product here, i.e., it is worth taking the transpose // arma::mat dkdtheta = dkdthetatrans.t(); #pragma omp parallel for collapse(2) reduction(+:tally) for (int j=0; j<(ltvec-1); j++) for (int l=0; l<(spi-2); l++) { tally += arma::dot((dkdtheta*dtqcube.slice(l).col(j)),adjcube.slice(l+1).col(j)); } gradloglik(i) = tally; } } haveLoglik = true; haveGradloglik = true; return 0; }