// currently only hacked for spheres, with radius and sd as two parameters
  bool HipGISAXS::fit_steepest_descent(real_t zcut,
          real_t radius_min, real_t radius_max, real_t radius_num,
          real_t sd_min, real_t sd_max, real_t sd_num,
          unsigned int dim, MPI::Intracomm& world_comm,
          int x_min, int x_max, int x_step) {
    int mpi_rank = world_comm.Get_rank();

    if(!init_steepest_fit(world_comm, zcut)) return false;

    int num_alphai = 0, num_phi = 0, num_tilt = 0;;

    real_t alphai_min, alphai_max, alphai_step;
    HiGInput::instance().scattering_alphai(alphai_min, alphai_max, alphai_step);
    if(alphai_max < alphai_min) alphai_max = alphai_min;
    if(alphai_min == alphai_max || alphai_step == 0) num_alphai = 1;
    else num_alphai = (alphai_max - alphai_min) / alphai_step + 1;

    real_t phi_min, phi_max, phi_step;
    HiGInput::instance().scattering_inplanerot(phi_min, phi_max, phi_step);
    if(phi_step == 0) num_phi = 1;
    else num_phi = (phi_max - phi_min) / phi_step + 1;

    real_t tilt_min, tilt_max, tilt_step;
    HiGInput::instance().scattering_tilt(tilt_min, tilt_max, tilt_step);
    if(tilt_step == 0) num_tilt = 1;
    else num_tilt = (tilt_max - tilt_min) / tilt_step + 1;

    std::cout << "**                    Num alphai: " << num_alphai << std::endl
          << "**                       Num phi: " << num_phi << std::endl
          << "**                      Num tilt: " << num_tilt << std::endl;

    // prepare parameters

    std::vector<std::vector<real_t> > params;
    int num_params = 2;
    std::vector<real_t> temp;
    real_t deltap = 0.0;
    if(radius_num <= 1)
      temp.push_back(radius_min);
    else {
      deltap = fabs(radius_max - radius_min) / (radius_num - 1);
      for(int i = 0; i < radius_num; ++ i) {
        temp.push_back(radius_min + i * deltap);
      } // for
    } // if-else
    params.push_back(temp);
    temp.clear();
    if(sd_num <= 1)
      temp.push_back(sd_min);
    else {
      deltap = fabs(sd_max - sd_min) / (sd_num - 1);
      for(int i = 0; i < sd_num; ++ i) {
        temp.push_back(sd_min + i * deltap);
      } // for
    } // if-else
    params.push_back(temp);
    temp.clear();

    // this will work only on one shape and one structure

    const real_t err_threshold = 1e-8;
    const unsigned int max_iter = 200;

    std::vector<real_t> param_vals;
    //param_vals.push_back(16.0);
    //param_vals.push_back(6.0);
    param_vals.push_back(23.0);
    param_vals.push_back(2.0);
    std::vector<real_t> param_deltas;
    param_deltas.push_back(0.05);
    param_deltas.push_back(0.05);
    real_t gamma_const = 0.05;

    real_t qdeltay = QGrid::instance().delta_y();

    real_t alpha_i = alphai_min;
    // high level of parallelism here (alphai, phi, tilt) for dynamicity ...
    for(int i = 0; i < num_alphai; i ++, alpha_i += alphai_step) {
      real_t alphai = alpha_i * PI_ / 180;
      real_t phi = phi_min;
      for(int j = 0; j < num_phi; j ++, phi += phi_step) {
        real_t tilt = tilt_min;
        for(int k = 0; k < num_tilt; k ++, tilt += tilt_step) {

          std::cout << "-- Computing reference GISAXS "
                << i * num_phi * num_tilt + j * num_tilt + k + 1 << " / "
                << num_alphai * num_phi * num_tilt
                << " [alphai = " << alpha_i << ", phi = " << phi
                << ", tilt = " << tilt << "] ..." << std::endl;

          /* run the reference gisaxs simulation using input params */
          real_t* ref_data = NULL;
          if(!run_gisaxs(alpha_i, alphai, phi, tilt, ref_data, world_comm)) {
            if(mpi_rank == 0) std::cerr << "error: could not finish successfully" << std::endl;
            return false;
          } // if

          if(dim != 1) {
            std::cerr << "uh-oh: only 1D is supported for now" << std::endl;
            return false;
          } // if

          real_t* ref_z_cut = new (std::nothrow) real_t[nqy_];
          for(unsigned int iy = 0; iy < nqy_; ++ iy) {
            // assuming nqz_ == 1 ...
            ref_z_cut[iy] = ref_data[nqx_ * iy + 0];
          } // for

          delete[] ref_data;

          // this will store z cut values for each iteration for plotting later
          real_t* z_cuts = new (std::nothrow) real_t[nqy_ * max_iter];
          real_t* temp_zcuts = new (std::nothrow) real_t[nqy_];

          // do some preprocessing
          // start the main loop, bound by max_iter and err_threshold
          //   compute gisaxs for current parameter values
          //   compute the neighbors parameter values
          //   for 12 combinations of current and neighbors, compute gisaxs and error
          //   compute the derivatives (gradient) and error stuff
          //   update parameter values
          // compute the error surface

          real_t err = 10.0;
          std::vector<real_t> param1_list;
          std::vector<real_t> param2_list;
          structure_iterator_t structure_iter = HiGInput::instance().structure_begin();
          Structure* structure = &((*structure_iter).second);
          Shape* shape = HiGInput::instance().shape(*structure);
          shape_param_iterator_t shape_param = (*shape).param_begin();
          real_t* data = NULL;
          std::vector<real_t> param_error_data;
          for(unsigned int iter = 0; iter < max_iter; ++ iter) {
            param1_list.clear();
            param1_list.push_back(param_vals[0] - 2 * param_deltas[0]);  // p1mm
            param1_list.push_back(param_vals[0] - param_deltas[0]);    // p1m
            param1_list.push_back(param_vals[0]);            // p1
            param1_list.push_back(param_vals[0] + param_deltas[0]);    // p1p
            param1_list.push_back(param_vals[0] + 2 * param_deltas[0]);  // p1pp
            param2_list.clear();
            param2_list.push_back(param_vals[1] - 2 * param_deltas[1]);  // p2mm
            param2_list.push_back(param_vals[1] - param_deltas[1]);    // p2m
            param2_list.push_back(param_vals[1]);            // p2
            param2_list.push_back(param_vals[1] + param_deltas[1]);    // p2p
            param2_list.push_back(param_vals[1] + 2 * param_deltas[1]);  // p2pp

            // current point
            (*shape_param).second.mean(param1_list[2]);
            (*shape_param).second.deviation(param2_list[2]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              z_cuts[iter * nqy_ + iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err22 = compute_cut_fit_error(z_cuts + iter * nqy_, ref_z_cut, qdeltay);

            // 12 neighbors

            (*shape_param).second.mean(param1_list[0]);
            (*shape_param).second.deviation(param2_list[2]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err02 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[1]);
            (*shape_param).second.deviation(param2_list[1]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err11 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[1]);
            (*shape_param).second.deviation(param2_list[2]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err12 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[1]);
            (*shape_param).second.deviation(param2_list[3]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err13 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[2]);
            (*shape_param).second.deviation(param2_list[0]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err20 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[2]);
            (*shape_param).second.deviation(param2_list[1]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err21 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[2]);
            (*shape_param).second.deviation(param2_list[3]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err23 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[2]);
            (*shape_param).second.deviation(param2_list[4]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err24 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[3]);
            (*shape_param).second.deviation(param2_list[1]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err31 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[3]);
            (*shape_param).second.deviation(param2_list[2]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err32 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[3]);
            (*shape_param).second.deviation(param2_list[3]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err33 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            (*shape_param).second.mean(param1_list[4]);
            (*shape_param).second.deviation(param2_list[2]);
            if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
              if(mpi_rank == 0)
                std::cerr << "error: could not finish successfully" << std::endl;
              return false;
            } // if
            for(unsigned int iy = 0; iy < nqy_; ++ iy) {
              // assuming nqz_ == 1 ...
              temp_zcuts[iy] = data[nqx_ * iy];
            } // for
            delete[] data; data = NULL;
            real_t err42 = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);

            // 22  0
            // 02  1mm
            // 11  1m2m
            // 12  1m
            // 13  1m2p
            // 20  2mm
            // 21  2m
            // 23  2p
            // 24  2pp
            // 31  1p2m
            // 32  1p
            // 33  1p2p
            // 42  1pp

            real_t derr1 = (err32 - err12) / (2 * param_deltas[0]);
            real_t derr2 = (err23 - err21) / (2 * param_deltas[1]);
            err = sqrt(derr1 * derr1 + derr2 * derr2);
            std::cout << "++ Iteration: " << iter << ", Error: " << err << std::endl;
            std::cout << "++ Parameter 1: " << param_vals[0]
                  << ", Parameter 2: " << param_vals[1] << std::endl;
            param_error_data.push_back(iter);
            param_error_data.push_back(param_vals[0]);
            param_error_data.push_back(param_vals[1]);
            param_error_data.push_back(err);
            if(err < err_threshold) break;

            real_t herr11 = (err42 + err02 - 2 * err22) /
                      (4 * param_deltas[0] * param_deltas[0]);
            real_t herr12 = (err33 - err13 - (err31 - err11)) /
                      (4 * param_deltas[0] * param_deltas[1]);
            real_t herr21 = (err33 - err13 - (err31 - err11)) /
                      (4 * param_deltas[0] * param_deltas[1]);
            real_t herr22 = (err24 + err20 - 2 * err22) /
                      (4 * param_deltas[1] * param_deltas[1]);
            real_t* herr = new (std::nothrow) real_t[2 * 2];
            herr[0] = herr11;
            herr[1] = herr12;
            herr[2] = herr21;
            herr[3] = herr22;
            real_t* herrinv;
            mldivide(2, herr, herrinv);

            param_vals[0] -= gamma_const * (herrinv[0] * derr1 + herrinv[1] * derr2);
            param_vals[1] -= gamma_const * (herrinv[2] * derr1 + herrinv[3] * derr2);

            delete[] herrinv;
            delete[] herr;
          } // for

          // compute the error surface
          std::vector<std::vector<real_t> >::iterator mean_iter = params.begin();
          std::vector<std::vector<real_t> >::iterator sd_iter = mean_iter + 1;
          std::vector<real_t> err_surface;
          for(std::vector<real_t>::iterator curr_mean = (*mean_iter).begin();
              curr_mean != (*mean_iter).end(); ++ curr_mean) {
            for(std::vector<real_t>::iterator curr_sd = (*sd_iter).begin();
                curr_sd != (*sd_iter).end(); ++ curr_sd) {
              (*shape_param).second.mean(*curr_mean);
              (*shape_param).second.deviation(*curr_sd);
              if(!run_gisaxs(alpha_i, alphai, phi, tilt, data, world_comm)) {
                if(mpi_rank == 0)
                  std::cerr << "error: could not finish successfully" << std::endl;
                return false;
              } // if
              for(unsigned int iy = 0; iy < nqy_; ++ iy) {
                // assuming nqz_ == 1 ...
                temp_zcuts[iy] = data[nqx_ * iy];
              } // for
              delete[] data; data = NULL;
              real_t curr_err = compute_cut_fit_error(temp_zcuts, ref_z_cut, qdeltay);
              err_surface.push_back(*curr_mean);
              err_surface.push_back(*curr_sd);
              err_surface.push_back(curr_err);
            } // for
          } // for

          // write data to files
          // define output filename
          std::stringstream alphai_b, phi_b, tilt_b;
          std::string alphai_s, phi_s, tilt_s;
          alphai_b << alpha_i; alphai_s = alphai_b.str();
          phi_b << phi; phi_s = phi_b.str();
          tilt_b << tilt; tilt_s = tilt_b.str();
          std::string param_error_file(HiGInput::instance().param_pathprefix() +
                        "/" + HiGInput::instance().runname() +
                        "/param_error_ai=" + alphai_s + "_rot=" + phi_s +
                        "_tilt=" + tilt_s + ".dat");
          std::string z_cut_file(HiGInput::instance().param_pathprefix() +
                        "/" + HiGInput::instance().runname() +
                        "/z_cut_ai=" + alphai_s + "_rot=" + phi_s +
                        "_tilt=" + tilt_s + ".dat");
          std::string err_surf_file(HiGInput::instance().param_pathprefix() +
                        "/" + HiGInput::instance().runname() +
                        "/err_surf_ai=" + alphai_s + "_rot=" + phi_s +
                        "_tilt=" + tilt_s + ".dat");
          // write param_error_data
          std::ofstream param_error_f(param_error_file.c_str());
          for(std::vector<real_t>::iterator pei = param_error_data.begin();
              pei != param_error_data.end(); pei += 4) {
            param_error_f << *pei << "\t" << *(pei + 1) << "\t" << *(pei + 2) << "\t"
                    << *(pei + 3) << std::endl;
          } // for
          param_error_f.close();
          // write ref_z_cut and z_cuts
          std::ofstream zcut_f(z_cut_file.c_str());
          for(unsigned int yy = 0; yy < nqy_; ++ yy) {
            zcut_f << ref_z_cut[yy] << "\t";
          } // for
          zcut_f << std::endl;
          for(unsigned int i = 0; i < max_iter; ++ i) {
            for(unsigned int yy = 0; yy < nqy_; ++ yy) {
              zcut_f << z_cuts[i * nqy_ + yy] << "\t";
            } // for
            zcut_f << std::endl;
          } // for
          zcut_f.close();
          // write error surface
          std::ofstream err_surf_f(err_surf_file.c_str());
          for(std::vector<real_t>::iterator surfi = err_surface.begin();
              surfi != err_surface.end(); surfi += 3) {
            err_surf_f << *surfi << "\t" << *(surfi + 1) << "\t" << *(surfi + 2) << std::endl;
          } // for
          err_surf_f.close();

          (*shape_param).second.mean(22.0);
          (*shape_param).second.deviation(7.0);

          param_error_data.clear();
          delete[] temp_zcuts;
          delete[] z_cuts;
          delete[] ref_z_cut;

          std::cout << "parameter values: " << param_vals[0] << ", " << param_vals[1]
                << " [error: " << err << "]" << std::endl;

          // synchronize all procs after each run
          world_comm.Barrier();
        } // for tilt
      } // for phi
    } // for alphai

    return true;
  } // HipGISAXS::fit_all_gisaxs()
// 
// % Erased all parts not wanted for codegeneration /Martin %% 
// Arguments    : emxArray_real_T *s 
//                emxArray_boolean_T *outliers 
//                emxArray_boolean_T *outliers2 
// Return Type  : void 
//
void locateOutliers(emxArray_real_T *s, emxArray_boolean_T *outliers, emxArray_boolean_T *outliers2)
{
    int ia;
    int ic;
    emxArray_real_T *b_y1;
    int orderForDim;
    int iyLead;
    double work_data_idx_0;
    int m;
    double tmp1;
    double tmp2;
    emxArray_real_T *SigmaMat;
    emxArray_int32_T *r0;
    emxArray_int32_T *r1;
    emxArray_real_T *a;
    unsigned int s_idx_0;
    emxArray_real_T *C;
    int br;
    double mu;
    emxArray_real_T *b_s;
    /* locateOutliers: locates artifacts/outliers from data series */
    /*  */
    /*   Inputs:  s = array containg data series */
    /*            method = artifact removal method to use. */
    /*   methods: 'percent' = percentage filter: locates data > x percent diff than previous data point.                */
    /*            'sd' = standard deviation filter: locates data > x stdev away from mean. */
    /*            'above' = Threshold filter: locates data > threshold value */
    /*            'below' = Threshold filter: locates data < threshold value */
    /*            'median' = median filter. Outliers are located. */
    /* Outputs:   outliers = logical array of whether s is artifact/outlier or not */
    /*                        eg. - [0 0 0 1 0], 1=artifact, 0=normal */
    /*                         */
    /* Examples: */
    /*    Locate outliers with 20% percentage filter: */
    /*        outliers = locateOutlers(s,'percent',0.2) */
    /*    Locate outliers that are above a threshold of 0.5: */
    /*        outliers = locateOutlers(s,'thresh','above',0.5) */
    /*    Locate outliers with median filter: */
    /*        outliers = locateOutlers(s,'median',4,5) */
    /*  */
    /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
    /*  Copyright (C) 2010, John T. Ramshur, [email protected] */
    /*   */
    /*  This file is part of HRVAS */
    /*  */
    /*  HRVAS is free software: you can redistribute it and/or modify */
    /*  it under the terms of the GNU General Public License as published by */
    /*  the Free Software Foundation, either version 3 of the License, or */
    /*  (at your option) any later version. */
    /*   */
    /*  HRVAS is distributed in the hope that it will be useful, */
    /*  but WITHOUT ANY WARRANTY; without even the implied warranty of */
    /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
    /*  GNU General Public License for more details. */
    /*   */
    /*  You should have received a copy of the GNU General Public License */
    /*  along with Foobar.  If not, see <http://www.gnu.org/licenses/>. */
    /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
    ia = outliers->size[0];
    outliers->size[0] = s->size[0];
    emxEnsureCapacity((emxArray__common *)outliers, ia, (int)sizeof(boolean_T));
    ic = s->size[0];
    for (ia = 0; ia < ic; ia++) {
        outliers->data[ia] = false;
    }
    /* preallocate         */
    if (1 > s->size[0] - 1) {
        ic = 0;
    } else {
        ic = s->size[0] - 1;
    }
    emxInit_real_T(&b_y1, 1);
    if (s->size[0] == 0) {
        ia = b_y1->size[0];
        b_y1->size[0] = 0;
        emxEnsureCapacity((emxArray__common *)b_y1, ia, (int)sizeof(double));
    } else {
        if (s->size[0] - 1 <= 1) {
            orderForDim = s->size[0] - 1;
        } else {
            orderForDim = 1;
        }
        if (orderForDim < 1) {
            ia = b_y1->size[0];
            b_y1->size[0] = 0;
            emxEnsureCapacity((emxArray__common *)b_y1, ia, (int)sizeof(double));
        } else {
            orderForDim = s->size[0] - 1;
            ia = b_y1->size[0];
            b_y1->size[0] = orderForDim;
            emxEnsureCapacity((emxArray__common *)b_y1, ia, (int)sizeof(double));
            if (!(b_y1->size[0] == 0)) {
                orderForDim = 1;
                iyLead = 0;
                work_data_idx_0 = s->data[0];
                for (m = 2; m <= s->size[0]; m++) {
                    tmp1 = s->data[orderForDim];
                    tmp2 = work_data_idx_0;
                    work_data_idx_0 = tmp1;
                    tmp1 -= tmp2;
                    orderForDim++;
                    b_y1->data[iyLead] = tmp1;
                    iyLead++;
                }
            }
        }
    }
    emxInit_real_T(&SigmaMat, 1);
    b_abs(b_y1, SigmaMat);
    /* percent chage from previous */
    /* find index of values where pChange > perLimit */
    orderForDim = s->size[0];
    if (2 > orderForDim) {
        ia = 0;
        orderForDim = 0;
    } else {
        ia = 1;
        orderForDim = s->size[0];
    }
    emxInit_int32_T(&r0, 2);
    iyLead = r0->size[0] * r0->size[1];
    r0->size[0] = 1;
    r0->size[1] = orderForDim - ia;
    emxEnsureCapacity((emxArray__common *)r0, iyLead, (int)sizeof(int));
    orderForDim -= ia;
    for (iyLead = 0; iyLead < orderForDim; iyLead++) {
        r0->data[r0->size[0] * iyLead] = ia + iyLead;
    }
    emxInit_int32_T1(&r1, 1);
    ia = r1->size[0];
    r1->size[0] = ic;
    emxEnsureCapacity((emxArray__common *)r1, ia, (int)sizeof(int));
    for (ia = 0; ia < ic; ia++) {
        r1->data[ia] = 1 + ia;
    }
    ic = r0->size[0] * r0->size[1];
    for (ia = 0; ia < ic; ia++) {
        outliers->data[r0->data[ia]] = (SigmaMat->data[ia] / s->data[r1->data[ia] - 1] > 0.2);
    }
    emxFree_int32_T(&r1);
    emxFree_int32_T(&r0);
    emxInit_real_T1(&a, 2);
    /*  Reference:  */
    /*  Clifford, G. (2002). "Characterizing Artefact in the Normal  */
    /*  Human 24-Hour RR Time Series to Aid Identification and Artificial  */
    /*  Replication of Circadian Variations in Human Beat to Beat Heart Rate  */
    /*  using a Simple Threshold." */
    /*  */
    /*  Aubert, A. E., D. Ramaekers, et al. (1999). "The analysis of heart  */
    /*  rate variability in unrestrained rats. Validation of method and  */
    /*  results." Comput Methods Programs Biomed 60(3): 197-213. */
    /* convert to logical array */
    /* preallocate   */
    iyLead = s->size[0];
    s_idx_0 = (unsigned int)s->size[0];
    ia = a->size[0] * a->size[1];
    a->size[0] = (int)s_idx_0;
    a->size[1] = 2;
    emxEnsureCapacity((emxArray__common *)a, ia, (int)sizeof(double));
    for (orderForDim = 1; orderForDim <= iyLead; orderForDim++) {
        a->data[orderForDim - 1] = (double)orderForDim / (double)iyLead;
        a->data[(orderForDim + a->size[0]) - 1] = 1.0;
    }
    mldivide(a, s, b_y1);
    emxInit_real_T(&C, 1);
    if (b_y1->size[0] == 1) {
        ia = C->size[0];
        C->size[0] = a->size[0];
        emxEnsureCapacity((emxArray__common *)C, ia, (int)sizeof(double));
        ic = a->size[0];
        for (ia = 0; ia < ic; ia++) {
            C->data[ia] = 0.0;
            for (iyLead = 0; iyLead < 2; iyLead++) {
                C->data[ia] += a->data[ia + a->size[0] * iyLead] * b_y1->data[iyLead];
            }
        }
    } else {
        s_idx_0 = (unsigned int)a->size[0];
        ia = C->size[0];
        C->size[0] = (int)s_idx_0;
        emxEnsureCapacity((emxArray__common *)C, ia, (int)sizeof(double));
        m = a->size[0];
        orderForDim = C->size[0];
        ia = C->size[0];
        C->size[0] = orderForDim;
        emxEnsureCapacity((emxArray__common *)C, ia, (int)sizeof(double));
        for (ia = 0; ia < orderForDim; ia++) {
            C->data[ia] = 0.0;
        }
        if (a->size[0] == 0) {
        } else {
            orderForDim = 0;
            while ((m > 0) && (orderForDim <= 0)) {
                for (ic = 1; ic <= m; ic++) {
                    C->data[ic - 1] = 0.0;
                }
                orderForDim = m;
            }
            br = 0;
            orderForDim = 0;
            while ((m > 0) && (orderForDim <= 0)) {
                orderForDim = 0;
                for (iyLead = br; iyLead + 1 <= br + 2; iyLead++) {
                    if (b_y1->data[iyLead] != 0.0) {
                        ia = orderForDim;
                        for (ic = 0; ic + 1 <= m; ic++) {
                            ia++;
                            C->data[ic] += b_y1->data[iyLead] * a->data[ia - 1];
                        }
                    }
                    orderForDim += m;
                }
                br += 2;
                orderForDim = m;
            }
        }
    }
    emxFree_real_T(&a);
    ia = s->size[0];
    emxEnsureCapacity((emxArray__common *)s, ia, (int)sizeof(double));
    ic = s->size[0];
    for (ia = 0; ia < ic; ia++) {
        s->data[ia] -= C->data[ia];
    }
    emxFree_real_T(&C);
    mu = mean(s);
    /* mean */
    orderForDim = s->size[0];
    if (s->size[0] > 1) {
        iyLead = s->size[0] - 1;
    } else {
        iyLead = s->size[0];
    }
    if (s->size[0] == 0) {
        tmp2 = 0.0;
    } else {
        ia = 0;
        work_data_idx_0 = s->data[0];
        for (ic = 2; ic <= orderForDim; ic++) {
            ia++;
            work_data_idx_0 += s->data[ia];
        }
        work_data_idx_0 /= (double)s->size[0];
        ia = 0;
        tmp1 = s->data[0] - work_data_idx_0;
        tmp2 = tmp1 * tmp1;
        for (ic = 2; ic <= orderForDim; ic++) {
            ia++;
            tmp1 = s->data[ia] - work_data_idx_0;
            tmp2 += tmp1 * tmp1;
        }
        tmp2 /= (double)iyLead;
    }
    emxInit_real_T(&b_s, 1);
    /* standard deviation */
    /*  Create a matrix of mean values by replicating the mu vector for n rows */
    repmat(mu, (double)s->size[0], b_y1);
    /*  Create a matrix of standard deviation values by replicating the sigma vector for n rows */
    repmat(std::sqrt(tmp2), (double)s->size[0], SigmaMat);
    /*  Create a matrix of zeros and ones, where ones indicate the location of outliers */
    ia = b_s->size[0];
    b_s->size[0] = s->size[0];
    emxEnsureCapacity((emxArray__common *)b_s, ia, (int)sizeof(double));
    ic = s->size[0];
    for (ia = 0; ia < ic; ia++) {
        b_s->data[ia] = s->data[ia] - b_y1->data[ia];
    }
    b_abs(b_s, b_y1);
    ia = outliers2->size[0];
    outliers2->size[0] = b_y1->size[0];
    emxEnsureCapacity((emxArray__common *)outliers2, ia, (int)sizeof(boolean_T));
    ic = b_y1->size[0];
    emxFree_real_T(&b_s);
    for (ia = 0; ia < ic; ia++) {
        outliers2->data[ia] = (b_y1->data[ia] > 3.0 * SigmaMat->data[ia]);
    }
    emxFree_real_T(&b_y1);
    emxFree_real_T(&SigmaMat);
    /*  Reference:  */
    /*  Aubert, A. E., D. Ramaekers, et al. (1999). "The analysis of heart  */
    /*  rate variability in unrestrained rats. Validation of method and  */
    /*  results." Comput Methods Programs Biomed 60(3): 197-213. */
    /* convert to logical array */
}
Exemple #3
0
Matrix& LASSO::train(Matrix& X, Matrix& Y, Options& options) {

	int p = size(X, 2);
	int ny = size(Y, 2);
	double epsilon = options.epsilon;
	int maxIter = options.maxIter;
	double lambda = options.lambda;
	bool calc_OV = options.calc_OV;
	bool verbose = options.verbose;

	/*XNX = [X, -X];
		H_G = XNX' * XNX;
		D = repmat(diag(H_G), [1, n_y]);
		XNXTY = XNX' * Y;
	    A = (X' * X + lambda  * eye(p)) \ (X' * Y);*/

	Matrix& XNX = horzcat(2, &X, &uminus(X));
	Matrix& H_G = XNX.transpose().mtimes(XNX);
	double* Q = new double[size(H_G, 1)];
	for (int i = 0; i < size(H_G, 1); i++) {
		Q[i] = H_G.getEntry(i, i);
	}
	Matrix& XNXTY = XNX.transpose().mtimes(Y);
	Matrix& A = mldivide(
			plus(X.transpose().mtimes(X), times(lambda, eye(p))),
			X.transpose().mtimes(Y)
	);

	/*AA = [subplus(A); subplus(-A)];
		C = -XNXTY + lambda;
		Grad = C + H_G * AA;
		tol = epsilon * norm(Grad);
		PGrad = zeros(size(Grad));*/

	Matrix& AA = vertcat(2, &subplus(A), &subplus(uminus(A)));
	Matrix& C = plus(uminus(XNXTY), lambda);
	Matrix& Grad = plus(C, mtimes(H_G, AA));
	double tol = epsilon * norm(Grad);
	Matrix& PGrad = zeros(size(Grad));

	std::list<double> J;
	double fval = 0;
	// J(1) = sum(sum((Y - X * A).^2)) / 2 + lambda * sum(sum(abs(A)));
	if (calc_OV) {
		fval = sum(sum(pow(minus(Y, mtimes(X, A)), 2))) / 2 +
				lambda * sum(sum(abs(A)));
		J.push_back(fval);
	}

	Matrix& I_k = Grad.copy();
	double d = 0;
	int k = 0;

	DenseVector& SFPlusCi = *new DenseVector(AA.getColumnDimension());
	Matrix& S = H_G;
	Vector** SRows = null;
	if (typeid(H_G) == typeid(DenseMatrix))
		SRows = denseMatrix2DenseRowVectors(S);
	else
		SRows = sparseMatrix2SparseRowVectors(S);

	Vector** CRows = null;
	if (typeid(C) == typeid(DenseMatrix))
		CRows = denseMatrix2DenseRowVectors(C);
	else
		CRows = sparseMatrix2SparseRowVectors(C);

	double** FData = ((DenseMatrix&) AA).getData();
	double* FRow = null;
	double* pr = null;
	int K = 2 * p;

	while (true) {

		/*I_k = Grad < 0 | AA > 0;
		    I_k_com = not(I_k);
		    PGrad(I_k) = Grad(I_k);
		    PGrad(I_k_com) = 0;*/

		_or(I_k, lt(Grad, 0), gt(AA, 0));
		Matrix& I_k_com = _not(I_k);
		assign(PGrad, Grad);
		logicalIndexingAssignment(PGrad, I_k_com, 0);

		d = norm(PGrad, inf);
		if (d < tol) {
			if (verbose)
				println("Converge successfully!");
			break;
		}

		/*for i = 1:2*p
		            AA(i, :) = max(AA(i, :) - (C(i, :) + H_G(i, :) * AA) ./ (D(i, :)), 0);
		    end
		    A = AA(1:p,:) - AA(p+1:end,:);*/

		for (int i = 0; i < K; i++) {
			// SFPlusCi = SRows[i].operate(AA);
			operate(SFPlusCi, *SRows[i], AA);
			plusAssign(SFPlusCi, *CRows[i]);
			timesAssign(SFPlusCi, 1 / Q[i]);
			pr = SFPlusCi.getPr();
			// F(i, :) = max(F(i, :) - (S(i, :) * F + C(i, :)) / D[i]), 0);
			// F(i, :) = max(F(i, :) - SFPlusCi, 0)
			FRow = FData[i];
			for (int j = 0; j < AA.getColumnDimension(); j++) {
				FRow[j] = max(FRow[j] - pr[j], 0);
			}
		}

		// Grad = plus(C, mtimes(H_G, AA));
		plus(Grad, C, mtimes(H_G, AA));

		k = k + 1;
		if (k > maxIter) {
			if (verbose)
				println("Maximal iterations");
			break;
		}

		if (calc_OV) {
			fval = sum(sum(pow(minus(Y, mtimes(XNX, AA)), 2))) / 2 +
					lambda * sum(sum(abs(AA)));
			J.push_back(fval);
		}

		if (k % 10 == 0 && verbose) {
			if (calc_OV)
				fprintf("Iter %d - ||PGrad||: %f, ofv: %f\n", k, d, J.back());
			else
				fprintf("Iter %d - ||PGrad||: %f\n", k, d);

		}

	}

	Matrix& res = minus(
			AA.getSubMatrix(0, p - 1, 0, ny - 1),
			AA.getSubMatrix(p, 2 * p - 1, 0, ny - 1)
	);

	return res;

}