コード例 #1
0
  void SetNonzeros<Add>::evalAdj(const std::vector<std::vector<MX> >& aseed,
                                 std::vector<std::vector<MX> >& asens) {
    // Get all the nonzeros
    vector<int> nz = all();

    // Number of derivative directions
    int nadj = aseed.size();

    // Output sparsity
    const Sparsity &osp = sparsity();
    const int* orow = osp.row();
    vector<int> ocol = osp.get_col();

    // Input sparsity (first input same as output)
    const Sparsity &isp = dep(1).sparsity();
    const int* irow = isp.row();
    vector<int> icol = isp.get_col();

    // We next need to resort the assignment vector by outputs instead of inputs
    // Start by counting the number of output nonzeros corresponding to each input nonzero
    vector<int> onz_count(osp.nnz()+2, 0);
    for (vector<int>::const_iterator it=nz.begin(); it!=nz.end(); ++it) {
      onz_count[*it+2]++;
    }

    // Cumsum to get index offset for output nonzero
    for (int i=0; i<onz_count.size()-1; ++i) {
      onz_count[i+1] += onz_count[i];
    }

    // Get the order of assignments
    vector<int> nz_order(nz.size());
    for (int k=0; k<nz.size(); ++k) {
      // Save the new index
      nz_order[onz_count[1+nz[k]]++] = k;
    }

    // Find out which elements are being set
    vector<int>& with_duplicates = onz_count; // Reuse memory
    onz_count.resize(nz.size());
    for (int k=0; k<nz.size(); ++k) {
      // Get output nonzero
      int onz_k = nz[nz_order[k]];

      // Get element (note: may contain duplicates)
      if (onz_k>=0) {
        with_duplicates[k] = ocol[onz_k]*osp.size1() + orow[onz_k];
      } else {
        with_duplicates[k] = -1;
      }
    }

    // Get all output elements (this time without duplicates)
    vector<int> el_output;
    osp.find(el_output);

    // Sparsity pattern being formed and corresponding nonzero mapping
    vector<int> r_colind, r_row, r_nz, r_ind;

    for (int d=0; d<nadj; ++d) {
      // Get the matching nonzeros
      r_ind.resize(el_output.size());
      copy(el_output.begin(), el_output.end(), r_ind.begin());
      aseed[d][0].sparsity().get_nz(r_ind);

      // Sparsity pattern for the result
      r_colind.resize(isp.size2()+1); // Col count
      fill(r_colind.begin(), r_colind.end(), 0);
      r_row.clear();

      // Perform the assignments
      r_nz.clear();
      for (int k=0; k<nz.size(); ++k) {

        // Get the corresponding nonzero for the input
        int el = nz[k];

        // Skip if zero assignment
        if (el==-1) continue;

        // Get the corresponding nonzero in the argument
        int el_arg = r_ind[el];

        // Skip if no argument
        if (el_arg==-1) continue;

        // Save the assignment
        r_nz.push_back(el_arg);

        // Get the corresponding element
        int i=icol[k], j=irow[k];

        // Add to sparsity pattern
        r_row.push_back(j);
        r_colind[1+i]++;
      }

      // col count -> col offset
      for (int i=1; i<r_colind.size(); ++i) r_colind[i] += r_colind[i-1];

      // If anything to set/add
      if (!r_nz.empty()) {
        // Create a sparsity pattern from vectors
        Sparsity f_sp(isp.size1(), isp.size2(), r_colind, r_row);
        asens[d][1] += aseed[d][0]->getGetNonzeros(f_sp, r_nz);
        if (!Add) {
          asens[d][0] += MX::zeros(f_sp)->getSetNonzeros(aseed[d][0], r_nz);
        } else {
          asens[d][0] += aseed[d][0];
        }
      } else {
        asens[d][0] += aseed[d][0];
      }
    }
  }
コード例 #2
0
ファイル: getnonzeros.cpp プロジェクト: tmmsartor/casadi
  void GetNonzeros::evaluateMX(const MXPtrV& input, MXPtrV& output, const MXPtrVV& fwdSeed,
                               MXPtrVV& fwdSens, const MXPtrVV& adjSeed, MXPtrVV& adjSens,
                               bool output_given) {
    // Get all the nonzeros
    vector<int> nz = getAll();

    // Number of derivative directions
    int nfwd = fwdSens.size();
    int nadj = adjSeed.size();

    // Output sparsity
    const Sparsity& osp = sparsity();
    const vector<int>& orow = osp.row();
    vector<int> ocol = osp.getCol();

    // Input sparsity
    const Sparsity& isp = dep().sparsity();
    //const vector<int>& irow = isp.row();
    vector<int> icol = isp.getCol();

    // Get all input elements
    vector<int> el_input;
    isp.getElements(el_input, false);

    // Sparsity pattern being formed and corresponding nonzero mapping
    vector<int> r_colind, r_row, r_nz, r_ind;

    // Nondifferentiated function and forward sensitivities
    int first_d = output_given ? 0 : -1;
    for (int d=first_d; d<nfwd; ++d) {

      // Get references to arguments and results
      const MX& arg = d<0 ? *input[0] : *fwdSeed[d][0];
      MX& res = d<0 ? *output[0] : *fwdSens[d][0];

      // Get the matching nonzeros
      r_ind.resize(el_input.size());
      copy(el_input.begin(), el_input.end(), r_ind.begin());
      arg.sparsity().getNZInplace(r_ind);

      // Sparsity pattern for the result
      r_colind.resize(osp.size2()+1); // Col count
      fill(r_colind.begin(), r_colind.end(), 0);
      r_row.clear();

      // Perform the assignments
      r_nz.clear();
      for (int k=0; k<nz.size(); ++k) {

        // Get the corresponding nonzero for the input
        int el = nz[k];

        // Skip if zero assignment
        if (el==-1) continue;

        // Get the corresponding nonzero in the argument
        int el_arg = r_ind[el];

        // Skip if no argument
        if (el_arg==-1) continue;

        // Save the assignment
        r_nz.push_back(el_arg);

        // Get the corresponding element
        int i=ocol[k], j=orow[k];

        // Add to sparsity pattern
        r_row.push_back(j);
        r_colind[1+i]++;
      }

      // col count -> col offset
      for (int i=1; i<r_colind.size(); ++i) r_colind[i] += r_colind[i-1];

      // Create a sparsity pattern from vectors
      if (r_nz.size()==0) {
        res = MX::sparse(osp.shape());
      } else {
        Sparsity f_sp(osp.size1(), osp.size2(), r_colind, r_row);
        res = arg->getGetNonzeros(f_sp, r_nz);
      }
    }

    // Adjoint sensitivities
    for (int d=0; d<nadj; ++d) {

      // Get an owning references to the seeds and sensitivities
      // and clear the seeds for the next run
      MX aseed = *adjSeed[d][0];
      *adjSeed[d][0] = MX();
      MX& asens = *adjSens[d][0]; // Sensitivity after addition
      MX asens0 = asens; // Sensitivity before addition

      // Get the corresponding nz locations in the output sparsity pattern
      aseed.sparsity().getElements(r_nz, false);
      osp.getNZInplace(r_nz);

      // Filter out ignored entries and check if there is anything to add at all
      bool elements_to_add = false;
      for (vector<int>::iterator k=r_nz.begin(); k!=r_nz.end(); ++k) {
        if (*k>=0) {
          if (nz[*k]>=0) {
            elements_to_add = true;
          } else {
            *k = -1;
          }
        }
      }

      // Quick continue of no elements to add
      if (!elements_to_add) continue;

      // Get the nz locations in the adjoint sensitivity corresponding to the inputs
      r_ind.resize(el_input.size());
      copy(el_input.begin(), el_input.end(), r_ind.begin());
      asens0.sparsity().getNZInplace(r_ind);

      // Enlarge the sparsity pattern of the sensitivity if not all additions fit
      for (vector<int>::iterator k=r_nz.begin(); k!=r_nz.end(); ++k) {
        if (*k>=0 && r_ind[nz[*k]]<0) {

          // Create a new pattern which includes both the the previous seed and the addition
          Sparsity sp = asens0.sparsity().patternUnion(dep().sparsity());
          asens0 = asens0->getSetSparse(sp);

          // Recalculate the nz locations in the adjoint sensitivity corresponding to the inputs
          copy(el_input.begin(), el_input.end(), r_ind.begin());
          asens0.sparsity().getNZInplace(r_ind);

          break;
        }
      }

      // Have r_nz point to locations in the sensitivity instead of the output
      for (vector<int>::iterator k=r_nz.begin(); k!=r_nz.end(); ++k) {
        if (*k>=0) {
          *k = r_ind[nz[*k]];
        }
      }

      // Add to the element to the sensitivity
      asens = aseed->getAddNonzeros(asens0, r_nz);
    }
  }