void Densification::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd){ bvec_t *inputd = get_bvec_t(input[0]->data()); bvec_t *outputd = get_bvec_t(output[0]->data()); int d1 = input[0]->size1(); int d2 = input[0]->size2(); const vector<int>& rowind = input[0]->rowind(); const vector<int>& col = input[0]->col(); int k=0; // index of the result for(int i=0; i<d1; ++i){ // loop over rows for(int el=rowind[i]; el<rowind[i+1]; ++el){ // loop over the non-zero elements int j=col[el]; // column for(; k<i*d2+j; ++k){ if(fwd) outputd[k] = 0; // add zeros before the non-zero element } // add the non-zero element if(fwd){ outputd[k] = inputd[el]; } else { inputd[el] |= outputd[k]; } k++; } } // add sparse zeros at the end of the matrix for(; k<d1*d2; ++k) if(fwd) outputd[k] = 0; }
void UnaryMX::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd){ bvec_t *inputd = get_bvec_t(input[0]->data()); bvec_t *outputd = get_bvec_t(output[0]->data()); if(fwd){ copy(inputd,inputd+size(),outputd); } else { int nz = input[0]->data().size(); for(int el=0; el<nz; ++el){ inputd[el] |= outputd[el]; } } }
void Reshape::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd) { // Quick return if inplace if (input[0]==output[0]) return; bvec_t *res_ptr = get_bvec_t(output[0]->data()); vector<double>& arg = input[0]->data(); bvec_t *arg_ptr = get_bvec_t(arg); if (fwd) { copy(arg_ptr, arg_ptr+arg.size(), res_ptr); } else { for (int k=0; k<arg.size(); ++k) { *arg_ptr++ |= *res_ptr; *res_ptr++ = 0; } } }
void Concat::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd) { bvec_t *res_ptr = get_bvec_t(output[0]->data()); for (int i=0; i<input.size(); ++i) { vector<double>& arg_i = input[i]->data(); bvec_t *arg_i_ptr = get_bvec_t(arg_i); if (fwd) { copy(arg_i_ptr, arg_i_ptr+arg_i.size(), res_ptr); res_ptr += arg_i.size(); } else { for (int k=0; k<arg_i.size(); ++k) { *arg_i_ptr++ |= *res_ptr; *res_ptr++ = 0; } } } }
void UnaryMX::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd) { // Quick return if inplace if (input[0]==output[0]) return; bvec_t *inputd = get_bvec_t(input[0]->data()); bvec_t *outputd = get_bvec_t(output[0]->data()); if (fwd) { copy(inputd, inputd+size(), outputd); } else { int nz = input[0]->data().size(); for (int el=0; el<nz; ++el) { bvec_t s = outputd[el]; outputd[el] = bvec_t(0); inputd[el] |= s; } } }
void GetNonzerosSlice::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd) { // Get references to the assignment operations and data bvec_t *outputd = get_bvec_t(output[0]->data()); bvec_t *inputd = get_bvec_t(input[0]->data()); // Propagate sparsity if (fwd) { for (int k=s_.start_; k!=s_.stop_; k+=s_.step_) { *outputd++ = inputd[k]; } } else { for (int k=s_.start_; k!=s_.stop_; k+=s_.step_) { inputd[k] |= *outputd; *outputd++ = 0; } } }
void GetNonzerosVector::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd) { // Get references to the assignment operations and data bvec_t *outputd = get_bvec_t(output[0]->data()); bvec_t *inputd = get_bvec_t(input[0]->data()); // Propagate sparsity if (fwd) { for (vector<int>::const_iterator k=nz_.begin(); k!=nz_.end(); ++k) { *outputd++ = *k>=0 ? inputd[*k] : 0; } } else { for (vector<int>::const_iterator k=nz_.begin(); k!=nz_.end(); ++k) { if (*k>=0) inputd[*k] |= *outputd; *outputd++ = 0; } } }
void Multiplication<TrX,TrY>::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd){ bvec_t *zd = get_bvec_t(input[0]->data()); bvec_t *rd = get_bvec_t(output[0]->data()); const size_t n = this->size(); if(fwd){ if(zd!=rd) copy(zd,zd+n,rd); DMatrix::mul_sparsity<true>(*input[1],*input[2],*input[0]); } else { DMatrix::mul_sparsity<false>(*input[1],*input[2],*output[0]); if(zd!=rd){ for(int i=0; i<n; ++i){ zd[i] |= rd[i]; rd[i] = bvec_t(0); } } } }
void InnerProd::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd){ bvec_t& res = *get_bvec_t(output[0]->data()); bvec_t* arg0 = get_bvec_t(input[0]->data()); bvec_t* arg1 = get_bvec_t(input[1]->data()); const int n = input[0]->size(); if(fwd){ res = 0; for(int i=0; i<n; ++i){ res |= *arg0++ | *arg1++; } } else { for(int i=0; i<n; ++i){ *arg0++ |= res; *arg1++ |= res; } res = 0; } }
void ParallelizerInternal::spEvaluateTask(bool use_fwd, int task){ // Get a reference to the function FX& fcn = funcs_[task]; if(use_fwd){ // Set input influence for(int j=inind_[task]; j<inind_[task+1]; ++j){ int nv = input(j).size(); const bvec_t* p_v = get_bvec_t(input(j).data()); bvec_t* f_v = get_bvec_t(fcn.input(j-inind_[task]).data()); copy(p_v,p_v+nv,f_v); } // Propagate fcn.spEvaluate(use_fwd); // Get output dependence for(int j=outind_[task]; j<outind_[task+1]; ++j){ int nv = output(j).size(); bvec_t* p_v = get_bvec_t(output(j).data()); const bvec_t* f_v = get_bvec_t(fcn.output(j-outind_[task]).data()); copy(f_v,f_v+nv, p_v); } } else { // Set output influence for(int j=outind_[task]; j<outind_[task+1]; ++j){ int nv = output(j).size(); const bvec_t* p_v = get_bvec_t(output(j).data()); bvec_t* f_v = get_bvec_t(fcn.output(j-outind_[task]).data()); copy(p_v,p_v+nv,f_v); } // Propagate fcn.spEvaluate(use_fwd); // Get input dependence for(int j=inind_[task]; j<inind_[task+1]; ++j){ int nv = input(j).size(); bvec_t* p_v = get_bvec_t(input(j).data()); const bvec_t* f_v = get_bvec_t(fcn.input(j-inind_[task]).data()); copy(f_v,f_v+nv,p_v); } } }
void SXFunctionInternal::spInit(bool fwd) { // Quick return if just-in-time compilation for // sparsity pattern propagation, no work vector needed #ifdef WITH_OPENCL if (just_in_time_sparsity_) { return; // Quick return } #endif // WITH_OPENCL // We need a work array containing unsigned long rather than doubles. // Since the two datatypes have the same size (64 bits) // we can save overhead by reusing the double array alloc(); bvec_t *iwork = get_bvec_t(w_tmp_); if (!fwd) fill_n(iwork, sz_w(), bvec_t(0)); }
void EvaluationMX::propagateSparsity(DMatrixPtrV& arg, DMatrixPtrV& res,bool use_fwd) { if (fcn_.spCanEvaluate(use_fwd)) { // Propagating sparsity pattern supported // Pass/clear forward seeds/adjoint sensitivities for (int iind = 0; iind < fcn_.getNumInputs(); ++iind) { // Input vector vector<double> &v = fcn_.input(iind).data(); if (v.empty()) continue; // FIXME: remove? if (arg[iind] == 0) { // Set to zero if not used fill_n(get_bvec_t(v), v.size(), bvec_t(0)); } else { // Copy output fcn_.input(iind).sparsity().set( get_bvec_t(fcn_.input(iind).data()), get_bvec_t(arg[iind]->data()), arg[iind]->sparsity()); } } // Pass/clear adjoint seeds/forward sensitivities for (int oind = 0; oind < fcn_.getNumOutputs(); ++oind) { // Output vector vector<double> &v = fcn_.output(oind).data(); if (v.empty()) continue; // FIXME: remove? if (res[oind] == 0) { // Set to zero if not used fill_n(get_bvec_t(v), v.size(), bvec_t(0)); } else { // Copy output fcn_.output(oind).sparsity().set( get_bvec_t(fcn_.output(oind).data()), get_bvec_t(res[oind]->data()), res[oind]->sparsity()); } } // Propagate seedsfcn_. fcn_.spInit(use_fwd); // NOTE: should only be done once fcn_.spEvaluate(use_fwd); // Get the sensitivities if (use_fwd) { for (int oind = 0; oind < res.size(); ++oind) { if (res[oind] != 0) { res[oind]->sparsity().set( get_bvec_t(res[oind]->data()), get_bvec_t(fcn_.output(oind).data()), fcn_.output(oind).sparsity()); } } } else { for (int iind = 0; iind < arg.size(); ++iind) { if (arg[iind] != 0) { arg[iind]->sparsity().bor( get_bvec_t(arg[iind]->data()), get_bvec_t(fcn_.input(iind).data()), fcn_.input(iind).sparsity()); } } } // Clear seeds and sensitivities for (int iind = 0; iind < arg.size(); ++iind) { vector<double> &v = fcn_.input(iind).data(); fill(v.begin(), v.end(), 0); } for (int oind = 0; oind < res.size(); ++oind) { vector<double> &v = fcn_.output(oind).data(); fill(v.begin(), v.end(), 0); } } else { // Propagating sparsity pattern not supported if (use_fwd) { // Clear the outputs for (int oind = 0; oind < res.size(); ++oind) { // Skip of not used if (res[oind] == 0) continue; // Get data array for output and clear it bvec_t *outputd = get_bvec_t(res[oind]->data()); fill_n(outputd, res[oind]->size(), 0); } } // Loop over inputs for (int iind = 0; iind < arg.size(); ++iind) { // Skip of not used if (arg[iind] == 0) continue; // Skip if no seeds if (use_fwd && arg[iind]->empty()) continue; // Get data array for input bvec_t *inputd = get_bvec_t(arg[iind]->data()); // Loop over outputs for (int oind = 0; oind < res.size(); ++oind) { // Skip of not used if (res[oind] == 0) continue; // Skip if no seeds if (!use_fwd && res[oind]->empty()) continue; // Get the sparsity of the Jacobian block CRSSparsity& sp = fcn_.jacSparsity(iind, oind, true); if (sp.isNull() || sp.size() == 0) continue; // Skip if zero const int d1 = sp.size1(); //const int d2 = sp.size2(); const vector<int>& rowind = sp.rowind(); const vector<int>& col = sp.col(); // Get data array for output bvec_t *outputd = get_bvec_t(res[oind]->data()); // Carry out the sparse matrix-vector multiplication for (int i = 0; i < d1; ++i) { for (int el = rowind[i]; el < rowind[i + 1]; ++el) { // Get column int j = col[el]; // Propagate dependencies if (use_fwd) { outputd[i] |= inputd[j]; } else { inputd[j] |= outputd[i]; } } } } } } }
void SymbolicMX::propagateSparsity(DMatrixPtrV& input, DMatrixPtrV& output, bool fwd){ bvec_t *outputd = get_bvec_t(output[0]->data()); fill_n(outputd,output[0]->size(),0); }