예제 #1
0
파일: main.cpp 프로젝트: mlefebvre87/libigl
int main(int argc, char *argv[])
{
  using namespace Eigen;
  using namespace std;
  MatrixXd V;
  MatrixXi F;
  igl::readOFF("../shared/decimated-knight.off",V,F);

  // 100 random indicies into rows of F
  VectorXi I;
  igl::floor((0.5*(VectorXd::Random(100,1).array()+1.)*F.rows()).eval(),I);
  
  // 50 random indicies into rows of I
  VectorXi J;
  igl::floor((0.5*(VectorXd::Random(50,1).array()+1.)*I.rows()).eval(),J);
  
  // K = I(J);
  VectorXi K;
  igl::slice(I,J,K);

  // default green for all faces
  MatrixXd C = RowVector3d(0.4,0.8,0.3).replicate(F.rows(),1);
  // Red for each in K
  MatrixXd R = RowVector3d(1.0,0.3,0.3).replicate(K.rows(),1);
  // C(K,:) = R
  igl::slice_into(R,K,1,C);

  // Plot the mesh with pseudocolors
  igl::viewer::Viewer viewer;
  viewer.data.set_mesh(V, F);
  viewer.data.set_colors(C);
  viewer.launch();
}
예제 #2
0
MatrixXi get_cross_table(const VectorXi &values, const VectorXi &classes) {
  if(classes.rows() != values.rows()) {
    throw ValueError("The vector of classes and values do not have same size"); 
  }
  IntsSet vals(values.data(), values.data() + values.size());
  IntsSet cls(classes.data(), classes.data() + classes.size());
  MatrixXi cross_table = MatrixXi::Zero(vals.size(), cls.size());
  IntsSet::const_iterator cls_begin = cls.begin();
  IntsSet::const_iterator val_begin = vals.begin();
  IntsSet::iterator class_it;
  IntsSet::iterator value_it;
  for (int i = 0; i < classes.size(); ++i) {
    class_it  = cls.find( classes(i));
    value_it = vals.find(values(i));
    unsigned int j = std::distance(val_begin, value_it); 
    unsigned int k = std::distance(cls_begin, class_it); 
    cross_table(j, k) += 1;
  }
  return cross_table;
}
예제 #3
0
void Mesh::sort()
{
  using namespace igl;
  using namespace igl::opengl2;
  using namespace std;
  using namespace Eigen;
  MatrixXi FF;
  VectorXi I;
  sort_triangles(getV(),getF(),FF,I);
  dgetF() = FF;
  if(getTCF().rows() == I.rows())
  {
    slice(MatrixXi(getTCF()),I,1,dgetTCF());
  }
  if(getNF().rows() == I.rows())
  {
    slice(MatrixXi(getNF()),I,1,dgetNF());
  }
  per_face_normals(getV(),getF(),dgetFN());
  per_vertex_normals(getV(),getF(),dgetVN());
  per_corner_normals(getV(),getF(),getFN(),30.0,dgetCN());
}
예제 #4
0
double nominal_entropy_gain(const VectorXi &values, const VectorXi &classes) {
  MatrixXi T = get_cross_table(values, classes);
  MatrixXi total_per_value = T.rowwise().sum(); 
  VectorXd probability_of_value = total_per_value.cast<double>() /values.rows();
  MatrixXd fractions_yx = divide_colwise( T.cast<double>(),
                                          total_per_value.cast<double>());
  double epsilon = std::numeric_limits<double>::epsilon();
  double invlog = 1 / std::log(2);
  MatrixXd H = (- invlog) * fractions_yx.array() * 
                             (fractions_yx.array() + epsilon).log().array();
  double total_entropy = probability_of_value.transpose() * H.rowwise().sum();
  VectorXi counts = T.colwise().sum();
  double gain = entropy(counts.cast<double>()) - total_entropy;
  return gain;
}
예제 #5
0
double nominal_gini_gain(const VectorXi &values, const VectorXi &classes) {
  MatrixXi T = get_cross_table(values, classes);
  // total_per_value(k) is the number of times that value k appears
  MatrixXi total_per_value = T.rowwise().sum(); 
  VectorXd probability_of_value = total_per_value.cast<double>() /values.rows();
  // Fraction of each class  per value
  MatrixXd fractions_yx = divide_colwise( T.cast<double>(),
                                          total_per_value.cast<double>());
  // Gini impurity for each value: sum fractions^2 over the rows
  VectorXd G = fractions_yx.array().square().rowwise().sum();
  double total_gini =  1 - probability_of_value.transpose() * G;
  VectorXi counts = T.colwise().sum();
  double gain = gini(counts.cast<double>()) - total_gini;
  return gain;
}
예제 #6
0
void igl::is_boundary_edge(
  const Eigen::PlainObjectBase<DerivedE> & E,
  const Eigen::PlainObjectBase<DerivedF> & F,
  Eigen::PlainObjectBase<DerivedB> & B)
{
  using namespace Eigen;
  using namespace std;
  // Should be triangles
  assert(F.cols() == 3);
  // Should be edges
  assert(E.cols() == 2);
  // number of faces
  const int m = F.rows();
  // Collect all directed edges after E
  MatrixXi EallE(E.rows()+3*m,2);
  EallE.block(0,0,E.rows(),E.cols()) = E;
  for(int e = 0;e<3;e++)
  {
    for(int f = 0;f<m;f++)
    {
      for(int c = 0;c<2;c++)
      {
        // 12 20 01
        EallE(E.rows()+m*e+f,c) = F(f,(c+1+e)%3);
      }
    }
  }
  // sort directed edges into undirected edges
  MatrixXi sorted_EallE,_;
  sort(EallE,2,true,sorted_EallE,_);
  // Determine unique undirected edges E and map to directed edges EMAP
  MatrixXi uE;
  VectorXi EMAP;
  unique_rows(sorted_EallE,uE,_,EMAP);
  // Counts of occurances
  VectorXi N = VectorXi::Zero(uE.rows());
  for(int e = 0;e<EMAP.rows();e++)
  {
    N(EMAP(e))++;
  }
  B.resize(E.rows());
  // Look of occurances of 2: one for original and another for boundary
  for(int e = 0;e<E.rows();e++)
  {
    B(e) = (N(EMAP(e)) == 2);
  }
}
예제 #7
0
void parameters::Compte_nbparam(datafile dat,model mod){
	const MatrixXi & omega=mod.Get_model();
	int g=omega.rows();
	m_nbparam=g-1;
	for (int k=0;k<g;k++){
		for (int b=0;b<(omega.rowwise().maxCoeff()(k)+1) ;b++){
			if ((omega.row(k).array()==b).any()){
				const VectorXi & who=mod.Get_var_block(k,b);
				const VectorXi modalite=dat.Get_modalite(who);
				if (who.rows()==1){
					m_nbparam+=modalite(0)-1;
				}else{
					for (int h=0;h<modalite.rows();h++){
						m_nbparam+=modalite(h)-1;
					}
					m_nbparam+=modalite(0);
					if ((modalite(1)==2)&&(who.rows()==2)){m_nbparam--;}
				}
			}
		}
	}
}
예제 #8
0
// processing
void drwnPRCurveNode::evaluateForwards()
{
    _curves.clear();
    drwnDataTable *tblActual = _inputPorts[0]->getTable();
    drwnDataTable *tblPredicted = _inputPorts[1]->getTable();
    if ((tblActual == NULL) || (tblPredicted == NULL)) {
        DRWN_LOG_WARNING("node \"" << _name << "\" requires two inputs");
        return;
    }

    // interate over records
    vector<string> keys = tblActual->getKeys();
    DRWN_START_PROGRESS(getName().c_str(), keys.size());
    for (vector<string>::const_iterator it = keys.begin(); it != keys.end(); it++) {
        DRWN_INC_PROGRESS;
        if (!getOwner()->getDatabase()->matchColour(*it, _colour)) continue;

        const drwnDataRecord *recActual = tblActual->lockRecord(*it);
        DRWN_ASSERT(recActual != NULL);

        const drwnDataRecord *recPredicted = tblPredicted->lockRecord(*it);
        if (recPredicted == NULL) {
            DRWN_LOG_WARNING("missing predictions for record \"" << *it << "\"");
        } else {

            // check dimensions
            if (recPredicted->numObservations() == 0) {
                DRWN_LOG_WARNING("missing predictions for \"" << *it << "\"");

            } else if (recActual->numObservations() != recPredicted->numObservations()) {
                DRWN_LOG_ERROR("size mismatch between actual (" << recActual->numObservations()
                    << ") and predicted observations (" << recPredicted->numObservations() << ")");

            } else {
                VectorXi actualClass;
                if (recActual->numFeatures() == 1) {
                    actualClass = recActual->data().col(0).cast<int>();
                } else {
                    actualClass = VectorXi::Zero(recActual->numObservations());
                    for (int i = 0; i < recActual->numObservations(); i++) {
                        recActual->data().row(i).maxCoeff(&actualClass[i]);
                    }
                }

                VectorXd predictedClass = recPredicted->data().col(0);
                if (_curves.empty()) {
                    _curves.resize(recPredicted->numFeatures());
                }
                DRWN_ASSERT((int)_curves.size() == recPredicted->numFeatures());

                for (int i = 0; i < actualClass.rows(); i++) {
                    if (actualClass[i] == -1) continue;
                    if (actualClass[i] >= (int)_curves.size()) {
                        DRWN_LOG_ERROR("mismatch between actual and predicted labels in \""
                            << getName() << "\" for record \"" << *it << "\"");
                        break;
                    }
                    for (int j = 0; j < (int)_curves.size(); j++) {
                        if (actualClass[i] == j) {
                            _curves[j].accumulatePositives(recPredicted->data()(i, j));
                        } else {
                            _curves[j].accumulateNegatives(recPredicted->data()(i, j));
                        }
                    }
                }
            }
        }

        // release records
        tblActual->unlockRecord(*it);
        tblPredicted->unlockRecord(*it);
    }

    // show results (average precision)
    for (int i = 0; i < (int)_curves.size(); i++) {
        DRWN_LOG_VERBOSE("11-pt average precision for \"" << getName()
            << "\" class " << i << " is " << toString(_curves[i].averagePrecision()));
    }

    DRWN_END_PROGRESS;
    updateWindow();
}
예제 #9
0
bool MNEForwardSolution::cluster_forward_solution(MNEForwardSolution &p_fwdOut, const Annotation &p_LHAnnotation, const Annotation &p_RHAnnotation, qint32 p_iClusterSize)
{
    p_fwdOut = MNEForwardSolution(*this);

    QList<Annotation> t_listAnnotation;
    t_listAnnotation.append(p_LHAnnotation);
    t_listAnnotation.append(p_RHAnnotation);

    //
    // Check consisty
    //
//    for(qint32 h = 0; h < this->src.hemispheres.size(); ++h )//obj.sizeForwardSolution)
//    {
//        if(this->src.hemispheres[h]->vertno.rows() !=  t_listAnnotation[h]->getLabel()->rows())
//        {
//            printf("Error: Annotation doesn't fit to Forward Solution: Vertice number is different!");
//            return false;
//        }
//    }


//    //DEBUG
//    MatrixXd test(20,3);
//    test << 0.537667139546100, 1.83388501459509, -2.25884686100365,
//            0.862173320368121, 0.318765239858981, -1.30768829630527,
//            -0.433592022305684, 0.342624466538650, 3.57839693972576,
//            2.76943702988488, -1.34988694015652, 3.03492346633185,
//            0.725404224946106, -0.0630548731896562, 0.714742903826096,
//            -0.204966058299775, -0.124144348216312, 1.48969760778547,
//            1.40903448980048, 1.41719241342961, 0.671497133608081,
//            -1.20748692268504, 0.717238651328839, 1.63023528916473,
//            0.488893770311789, 1.03469300991786, 0.726885133383238,
//            -0.303440924786016, 0.293871467096658, -0.787282803758638,
//            0.888395631757642, -1.14707010696915, -1.06887045816803,
//            -0.809498694424876, -2.94428416199490, 1.43838029281510,
//            0.325190539456198, -0.754928319169703, 1.37029854009523,
//            -1.71151641885370, -0.102242446085491, -0.241447041607358,
//            0.319206739165502, 0.312858596637428, -0.864879917324457,
//            -0.0300512961962686, -0.164879019209038, 0.627707287528727,
//            1.09326566903948, 1.10927329761440, -0.863652821988714,
//            0.0773590911304249, -1.21411704361541, -1.11350074148676,
//            -0.00684932810334806, 1.53263030828475, -0.769665913753682,
//            0.371378812760058, -0.225584402271252, 1.11735613881447;

//    std::cout << test << std::endl;

//    VectorXi idx;
//    MatrixXd ctrs;
//    VectorXd sumd;
//    MatrixXd D;

//    KMeans testK(QString("cityblock"), QString("sample"), 5);//QString("sqeuclidean")//QString("sample")

//    testK.calculate(test, 2, idx, ctrs, sumd, D);

//    std::cout << "idx" << std::endl << idx << std::endl;
//    std::cout << "ctrs" << std::endl << ctrs << std::endl;
//    std::cout << "sumd" << std::endl << sumd << std::endl;
//    std::cout << "D" << std::endl << D << std::endl;


    //DEBUG END


    KMeans t_kMeans(QString("sqeuclidean"), QString("sample"), 5);//QString("sqeuclidean")//QString("sample")//cityblock
    MatrixXd t_LF_new;

    qint32 count;
    qint32 offset;

    for(qint32 h = 0; h < this->src.hemispheres.size(); ++h )//obj.sizeForwardSolution)
    {
        count = 0;
        offset = 0;

        // Offset for continuous indexing;
        if(h > 0)
            for(qint32 j = 0; j < h; ++j)
                offset += this->src.hemispheres[j].nuse;


        if(h == 0)
            printf("Cluster Left Hemisphere\n");
        else
            printf("Cluster Right Hemisphere\n");

        Colortable t_CurrentColorTable = t_listAnnotation[h].getColortable();
        VectorXi label = t_CurrentColorTable.getAvailableROIs();

        // Get label for every vertice
        VectorXi vertno_labeled = VectorXi::Zero(this->src.hemispheres[h].vertno.rows());

        for(qint32 i = 0; i < vertno_labeled.rows(); ++i)
            vertno_labeled[i] = t_listAnnotation[h].getLabel()[this->src.hemispheres[h].vertno[i]];

        MatrixXd t_LF_partial;
        for (qint32 i = 0; i < label.rows(); ++i)
        {

            if (label[i] != 0)
            {
                QString curr_name = t_CurrentColorTable.struct_names[i];//obj.label2AtlasName(label(i));
                printf("\tCluster %d / %d %s...", i+1, label.rows(), curr_name.toUtf8().constData());

                //
                // Get source space indeces
                //
                VectorXi idcs = VectorXi::Zero(vertno_labeled.rows());
                qint32 c = 0;

                //Select ROIs
                for(qint32 j = 0; j < vertno_labeled.rows(); ++j)
                {
                    if(vertno_labeled[j] == label[i])
                    {
                        idcs[c] = j;
                        ++c;
                    }
                }
                idcs.conservativeResize(c);

//                VectorXi idcs_triplet = tripletSelection(idcs);//ToDo obsolete: use block instead

                //get selected LF
                MatrixXd t_LF(this->sol->data.rows(), idcs.rows()*3);

                for(qint32 j = 0; j < idcs.rows(); ++j)
                    t_LF.block(0, j*3, t_LF.rows(), 3) = this->sol->data.block(0, (idcs[j]+offset)*3, t_LF.rows(), 3);

                qint32 nSens = t_LF.rows();
                qint32 nSources = t_LF.cols()/3;
                qint32 nClusters = 0;

                if (nSources > 0)
                {
                    nClusters = ceil((double)nSources/(double)p_iClusterSize);

                    printf("%d Cluster(s)... ", nClusters);

                    t_LF_partial = MatrixXd::Zero(nSens,nClusters*3);

                    // Reshape Input data -> sources rows; sensors columns
                    MatrixXd t_sensLF(t_LF.cols()/3, 3*nSens);
                    for(qint32 j = 0; j < nSens; ++j)
                    {
                        for(qint32 k = 0; k < t_sensLF.rows(); ++k)
                            t_sensLF.block(k,j*3,1,3) = t_LF.block(j,k*3,1,3);
                    }

                    // Kmeans Reduction
                    VectorXi roiIdx;
                    MatrixXd ctrs;
                    VectorXd sumd;
                    MatrixXd D;

                    t_kMeans.calculate(t_sensLF, nClusters, roiIdx, ctrs, sumd, D);

                    //
                    // Assign the centroid for each cluster to the partial LF
                    //
                    for(qint32 j = 0; j < nSens; ++j)
                        for(qint32 k = 0; k < nClusters; ++k)
                            t_LF_partial.block(j, k*3, 1, 3) = ctrs.block(k,j*3,1,3);

                    //
                    // Get cluster indizes and its distances to the centroid
                    //
                    for(qint32 j = 0; j < nClusters; ++j)
                    {
                        VectorXi clusterIdcs = VectorXi::Zero(roiIdx.rows());
                        VectorXd clusterDistance = VectorXd::Zero(roiIdx.rows());
                        qint32 nClusterIdcs = 0;
                        for(qint32 k = 0; k < roiIdx.rows(); ++k)
                        {
                            if(roiIdx[k] == j)
                            {
                                clusterIdcs[nClusterIdcs] = idcs[k];
                                clusterDistance[nClusterIdcs] = D(k,j);
                                ++nClusterIdcs;
                            }
                        }
                        clusterIdcs.conservativeResize(nClusterIdcs);
                        p_fwdOut.src.hemispheres[h].cluster_vertnos.append(clusterIdcs);
                        p_fwdOut.src.hemispheres[h].cluster_distances.append(clusterDistance);
                    }

                    //
                    // Assign partial LF to new LeadField
                    //
                    if(t_LF_partial.rows() > 0 && t_LF_partial.cols() > 0)
                    {
                        t_LF_new.conservativeResize(t_LF_partial.rows(), t_LF_new.cols() + t_LF_partial.cols());
                        t_LF_new.block(0, t_LF_new.cols() - t_LF_partial.cols(), t_LF_new.rows(), t_LF_partial.cols()) = t_LF_partial;

                        // Map the centroids to the closest rr
                        for(qint32 k = 0; k < nClusters; ++k)
                        {
                            qint32 j = 0;

                            double sqec = sqrt((t_LF.block(0, j*3, t_LF.rows(), 3) - t_LF_partial.block(0, k*3, t_LF_partial.rows(), 3)).array().pow(2).sum());
                            double sqec_min = sqec;
                            double j_min = j;
                            for(qint32 j = 1; j < idcs.rows(); ++j)
                            {
                                sqec = sqrt((t_LF.block(0, j*3, t_LF.rows(), 3) - t_LF_partial.block(0, k*3, t_LF_partial.rows(), 3)).array().pow(2).sum());
                                if(sqec < sqec_min)
                                {
                                    sqec_min = sqec;
                                    j_min = j;
                                }
                            }

                            // Take the closest coordinates
                            qint32 sel_idx = idcs[j_min];
                            p_fwdOut.src.hemispheres[h].rr.row(count) = this->src.hemispheres[h].rr.row(sel_idx);
                            p_fwdOut.src.hemispheres[h].nn.row(count) = MatrixXd::Zero(1,3);

                            p_fwdOut.src.hemispheres[h].vertno[count] = this->src.hemispheres[h].vertno[sel_idx];
                            ++count;
                        }
                    }
                    printf("[done]\n");
                }
                else
                {
                    printf("failed! Label contains no sources.\n");
                }
            }
        }

        p_fwdOut.src.hemispheres[h].rr.conservativeResize(count, 3);
        p_fwdOut.src.hemispheres[h].nn.conservativeResize(count, 3);
        p_fwdOut.src.hemispheres[h].vertno.conservativeResize(count);

        p_fwdOut.src.hemispheres[h].nuse_tri = 0;
        p_fwdOut.src.hemispheres[h].use_tris = MatrixX3i(0,3);


        if(p_fwdOut.src.hemispheres[h].rr.rows() > 0 && p_fwdOut.src.hemispheres[h].rr.cols() > 0)
        {
            if(h == 0)
            {
                p_fwdOut.source_rr = MatrixX3d(0,3);
                p_fwdOut.source_nn = MatrixX3d(0,3);
            }

            p_fwdOut.source_rr.conservativeResize(p_fwdOut.source_rr.rows() + p_fwdOut.src.hemispheres[h].rr.rows(),3);
            p_fwdOut.source_rr.block(p_fwdOut.source_rr.rows() -  p_fwdOut.src.hemispheres[h].rr.rows(), 0,  p_fwdOut.src.hemispheres[h].rr.rows(), 3) = p_fwdOut.src.hemispheres[h].rr;

            p_fwdOut.source_nn.conservativeResize(p_fwdOut.source_nn.rows() + p_fwdOut.src.hemispheres[h].nn.rows(),3);
            p_fwdOut.source_nn.block(p_fwdOut.source_nn.rows() -  p_fwdOut.src.hemispheres[h].nn.rows(), 0,  p_fwdOut.src.hemispheres[h].nn.rows(), 3) = p_fwdOut.src.hemispheres[h].nn;
        }

        printf("[done]\n");
    }

    // set new fwd solution;
    p_fwdOut.sol->data = t_LF_new;
    p_fwdOut.sol->ncol = t_LF_new.cols();

    p_fwdOut.nsource = p_fwdOut.sol->ncol/3;

    p_fwdOut.isClustered = true;

    return true;
}
void mexFunction(int nlhs, mxArray *plhs[], 
    int nrhs, const mxArray *prhs[])
{
  // This is useful for debugging whether Matlab is caching the mex binary
  //mexPrintf("%s %s\n",__TIME__,__DATE__);
  igl::matlab::MexStream mout;
  std::streambuf *outbuf = std::cout.rdbuf(&mout);

  using namespace std;
  using namespace Eigen;
  using namespace igl;
  using namespace igl::matlab;

  MatrixXd P,V,C;
  VectorXi I;
  VectorXd sqrD;
  MatrixXi F;
  if(nrhs < 3)
  {
    mexErrMsgTxt("nrhs < 3");
  }
  parse_rhs_double(prhs,P);
  parse_rhs_double(prhs+1,V);
  parse_rhs_index(prhs+2,F);
  mexErrMsgTxt(P.cols()==3 || P.cols()==2,"P must be #P by (3|2)");
  mexErrMsgTxt(V.cols()==3 || V.cols()==2,"V must be #V by (3|2)");
  mexErrMsgTxt(V.cols()==P.cols(),"dim(V) must be dim(P)");
  mexErrMsgTxt(F.cols()==3 || F.cols()==2 || F.cols()==1,"F must be #F by (3|2|1)");

  point_mesh_squared_distance(P,V,F,sqrD,I,C);
  // Prepare left-hand side
  switch(nlhs)
  {
    case 3:
    {
      // Treat indices as reals
      plhs[2] = mxCreateDoubleMatrix(C.rows(),C.cols(), mxREAL);
      double * Cp = mxGetPr(plhs[2]);
      copy(&C.data()[0],&C.data()[0]+C.size(),Cp);
      // Fallthrough
    }
    case 2:
    {
      // Treat indices as reals
      plhs[1] = mxCreateDoubleMatrix(I.rows(),I.cols(), mxREAL);
      double * Ip = mxGetPr(plhs[1]);
      VectorXd Id = (I.cast<double>().array()+1).matrix();
      copy(&Id.data()[0],&Id.data()[0]+Id.size(),Ip);
      // Fallthrough
    }
    case 1:
    {
      plhs[0] = mxCreateDoubleMatrix(sqrD.rows(),sqrD.cols(), mxREAL);
      double * sqrDp = mxGetPr(plhs[0]);
      copy(&sqrD.data()[0],&sqrD.data()[0]+sqrD.size(),sqrDp);
      break;
    }
    default:break;
  }

  // Restore the std stream buffer Important!
  std::cout.rdbuf(outbuf);
}
예제 #11
0
파일: kmeans.cpp 프로젝트: cpieloth/mne-cpp
//*************************************************************************************************************
//GCENTROIDS Centroids and counts stratified by group.
void KMeans::gcentroids(MatrixXd& X, VectorXi& index, VectorXi& clusts,
                                          MatrixXd& centroids, VectorXi& counts)
{
    qint32 num = clusts.rows();
    centroids = MatrixXd::Zero(num,p);
    centroids.fill(std::numeric_limits<double>::quiet_NaN());
    counts = VectorXi::Zero(num);

    VectorXi members;

    qint32 c;

    for(qint32 i = 0; i < num; ++i)
    {
        c = 0;
        members = VectorXi::Zero(index.rows());
        for(qint32 j = 0; j < index.rows(); ++j)
        {
            if(index[j] == clusts[i])
            {
                members[c] = j;
                ++c;
            }
        }
        members.conservativeResize(c);
        if (c > 0)
        {
            counts[i] = c;
            if(m_sDistance.compare("sqeuclidean") == 0)
            {
                //Initialize
                if(members.rows() > 0)
                    centroids.row(i) = RowVectorXd::Zero(centroids.cols());

                for(qint32 j = 0; j < members.rows(); ++j)
                    centroids.row(i).array() += X.row(members[j]).array() / counts[i];
            }
            else if(m_sDistance.compare("cityblock") == 0)
            {
                // Separate out sorted coords for points in i'th cluster,
                // and use to compute a fast median, component-wise
                MatrixXd Xsorted(counts[i],p);
                c = 0;

                for(qint32 j = 0; j < index.rows(); ++j)
                {
                    if(index[j] == clusts[i])
                    {
                        Xsorted.row(c) = X.row(j);
                        ++c;
                    }
                }

                for(qint32 j = 0; j < Xsorted.cols(); ++j)
                    std::sort(Xsorted.col(j).data(),Xsorted.col(j).data()+Xsorted.rows());

                qint32 nn = floor(0.5*(counts(i)))-1;
                if (counts[i] % 2 == 0)
                    centroids.row(i) = .5 * (Xsorted.row(nn) + Xsorted.row(nn+1));
                else
                    centroids.row(i) = Xsorted.row(nn+1);
            }
            else if(m_sDistance.compare("cosine") == 0 || m_sDistance.compare("correlation") == 0)
            {
                for(qint32 j = 0; j < members.rows(); ++j)
                    centroids.row(i).array() += X.row(members[j]).array() / counts[i]; // unnormalized
            }
//            else if(m_sDistance.compare("hamming") == 0)
//            {
//                % Compute a fast median for binary data, component-wise
//                centroids(i,:) = .5*sign(2*sum(X(members,:), 1) - counts(i)) + .5;
//            }
        }
    }
}// function
예제 #12
0
파일: kmeans.cpp 프로젝트: cpieloth/mne-cpp
bool KMeans::calculate(    MatrixXd X, qint32 kClusters,
                            VectorXi& idx, MatrixXd& C, VectorXd& sumD, MatrixXd& D)
{
    if (kClusters < 1)
        return false;

    //Init random generator
    srand ( time(NULL) );

// n points in p dimensional space
    k = kClusters;
    n = X.rows();
    p = X.cols();

    if(m_sDistance.compare("cosine") == 0)
    {
//        Xnorm = sqrt(sum(X.^2, 2));
//        if any(min(Xnorm) <= eps(max(Xnorm)))
//            error(['Some points have small relative magnitudes, making them ', ...
//                   'effectively zero.\nEither remove those points, or choose a ', ...
//                   'distance other than ''cosine''.']);
//        end
//        X = X ./ Xnorm(:,ones(1,p));
    }
    else if(m_sDistance.compare("correlation")==0)
    {
        X.array() -= (X.rowwise().sum().array() / (double)p).replicate(1,p); //X - X.rowwise().sum();//.repmat(mean(X,2),1,p);
        MatrixXd Xnorm = (X.array().pow(2).rowwise().sum()).sqrt();//sqrt(sum(X.^2, 2));
//        if any(min(Xnorm) <= eps(max(Xnorm)))
//            error(['Some points have small relative standard deviations, making them ', ...
//                   'effectively constant.\nEither remove those points, or choose a ', ...
//                   'distance other than ''correlation''.']);
//        end
        X.array() /= Xnorm.replicate(1,p).array();
    }
//    else if(m_sDistance.compare('hamming')==0)
//    {
//        if ~all(ismember(X(:),[0 1]))
//            error(message('NonbinaryDataForHamm'));
//        end
//    }

    // Start
    RowVectorXd Xmins;
    RowVectorXd Xmaxs;
    if (m_sStart.compare("uniform") == 0)
    {
        if (m_sDistance.compare("hamming") == 0)
        {
            printf("Error: Uniform Start For Hamming\n");
            return false;
        }
        Xmins = X.colwise().minCoeff();
        Xmaxs = X.colwise().maxCoeff();
    }

    //
    // Done with input argument processing, begin clustering
    //
    if (m_bOnline)
    {
        Del = MatrixXd(n,k);
        Del.fill(std::numeric_limits<double>::quiet_NaN());// reassignment criterion
    }

    double totsumDBest = std::numeric_limits<double>::max();
    emptyErrCnt = 0;

    VectorXi idxBest;
    MatrixXd Cbest;
    VectorXd sumDBest;
    MatrixXd Dbest;

    for(qint32 rep = 0; rep < m_iReps; ++rep)
    {
        if (m_sStart.compare("uniform") == 0)
        {
            C = MatrixXd::Zero(k,p);
            for(qint32 i = 0; i < k; ++i)
                for(qint32 j = 0; j < p; ++j)
                    C(i,j) = unifrnd(Xmins[j], Xmaxs[j]);
            // For 'cosine' and 'correlation', these are uniform inside a subset
            // of the unit hypersphere.  Still need to center them for
            // 'correlation'.  (Re)normalization for 'cosine'/'correlation' is
            // done at each iteration.
            if (m_sDistance.compare("correlation") == 0)
                C.array() -= (C.array().rowwise().sum()/p).replicate(1, p).array();
        }
        else if (m_sStart.compare("sample") == 0)
        {
            C = MatrixXd::Zero(k,p);
            for(qint32 i = 0; i < k; ++i)
                C.block(i,0,1,p) = X.block(rand() % n, 0, 1, p);
            // DEBUG
//            C.block(0,0,1,p) = X.block(2, 0, 1, p);
//            C.block(1,0,1,p) = X.block(7, 0, 1, p);
//            C.block(2,0,1,p) = X.block(17, 0, 1, p);
        }
    //    else if (start.compare("cluster") == 0)
    //    {
    //        Xsubset = X(randsample(n,floor(.1*n)),:);
    //        [dum, C] = kmeans(Xsubset, k, varargin{:}, 'start','sample', 'replicates',1);
    //    }
    //    else if (start.compare("numeric") == 0)
    //    {
    //        C = CC(:,:,rep);
    //    }

        // Compute the distance from every point to each cluster centroid and the
        // initial assignment of points to clusters
        D = distfun(X, C, 0);
        idx = VectorXi::Zero(D.rows());
        d = VectorXd::Zero(D.rows());

        for(qint32 i = 0; i < D.rows(); ++i)
            d[i] = D.row(i).minCoeff(&idx[i]);

        m = VectorXi::Zero(k);
        for(qint32 i = 0; i < k; ++i)
            for (qint32 j = 0; j < idx.rows(); ++j)
                if(idx[j] == i)
                    ++ m[i];

        try // catch empty cluster errors and move on to next rep
        {
            // Begin phase one:  batch reassignments
            bool converged = batchUpdate(X, C, idx);

            // Begin phase two:  single reassignments
            if (m_bOnline)
                converged = onlineUpdate(X, C, idx);

            if (!converged)
                printf("Failed To Converge during replicate %d\n", rep);

            // Calculate cluster-wise sums of distances
            VectorXi nonempties = VectorXi::Zero(m.rows());
            quint32 count = 0;
            for(qint32 i = 0; i < m.rows(); ++i)
            {
                if(m[i] > 0)
                {
                    nonempties[i] = 1;
                    ++count;
                }
            }
            MatrixXd C_tmp(count,C.cols());
            count = 0;
            for(qint32 i = 0; i < nonempties.rows(); ++i)
            {
                if(nonempties[i])
                {
                    C_tmp.row(count) = C.row(i);
                    ++count;
                }
            }

            MatrixXd D_tmp = distfun(X, C_tmp, iter);
            count = 0;
            for(qint32 i = 0; i < nonempties.rows(); ++i)
            {
                if(nonempties[i])
                {
                    D.col(i) = D_tmp.col(count);
                    C.row(i) = C_tmp.row(count);
                    ++count;
                }
            }

            d = VectorXd::Zero(n);
            for(qint32 i = 0; i < n; ++i)
                d[i] += D.array()(idx[i]*n+i);//Colum Major

            sumD = VectorXd::Zero(k);
            for(qint32 i = 0; i < k; ++i)
                for (qint32 j = 0; j < idx.rows(); ++j)
                    if(idx[j] == i)
                        sumD[i] += d[j];

            totsumD = sumD.array().sum();

//            printf("%d iterations, total sum of distances = %f\n", iter, totsumD);

            // Save the best solution so far
            if (totsumD < totsumDBest)
            {
                totsumDBest = totsumD;
                idxBest = idx;
                Cbest = C;
                sumDBest = sumD;
                Dbest = D;
            }
        }
        catch (int e)
        {
            if(e == 0)
            {
                // If an empty cluster error occurred in one of multiple replicates, catch
                // it, warn, and move on to next replicate.  Error only when all replicates
                // fail.  Rethrow an other kind of error.
                if (m_iReps == 1)
                    return false;
                else
                {
                    emptyErrCnt = emptyErrCnt + 1;
//                    printf("Replicate %d terminated: empty cluster created at iteration %d.\n", rep, iter);
                    if (emptyErrCnt == m_iReps)
                    {
//                        error(message('EmptyClusterAllReps'));
                        return false;
                    }

                }
            }
        } // catch

    } // replicates

    // Return the best solution
    idx = idxBest;
    C = Cbest;
    sumD = sumDBest;
    D = Dbest;

//if hadNaNs
//    idx = statinsertnan(wasnan, idx);
//end
    return true;
}
예제 #13
0
파일: kmeans.cpp 프로젝트: cpieloth/mne-cpp
bool KMeans::onlineUpdate(MatrixXd& X, MatrixXd& C, VectorXi& idx)
{
    // Initialize some cluster information prior to phase two
    MatrixXd Xmid1;
    MatrixXd Xmid2;
    if (m_sDistance.compare("cityblock") == 0)
    {
        Xmid1 = MatrixXd::Zero(k,p);
        Xmid2 = MatrixXd::Zero(k,p);
        for(qint32 i = 0; i < k; ++i)
        {
            if (m[i] > 0)
            {
                // Separate out sorted coords for points in i'th cluster,
                // and save values above and below median, component-wise
                MatrixXd Xsorted(m[i],p);
                qint32 c = 0;
                for(qint32 j = 0; j < idx.rows(); ++j)
                {
                    if(idx[j] == i)
                    {
                        Xsorted.row(c) = X.row(j);
                        ++c;
                    }
                }
                for(qint32 j = 0; j < Xsorted.cols(); ++j)
                    std::sort(Xsorted.col(j).data(),Xsorted.col(j).data()+Xsorted.rows());

                qint32 nn = floor(0.5*m[i])-1;
                if ((m[i] % 2) == 0)
                {
                    Xmid1.row(i) = Xsorted.row(nn);
                    Xmid2.row(i) = Xsorted.row(nn+1);
                }
                else if (m[i] > 1)
                {
                    Xmid1.row(i) = Xsorted.row(nn);
                    Xmid2.row(i) = Xsorted.row(nn+2);
                }
                else
                {
                    Xmid1.row(i) = Xsorted.row(0);
                    Xmid2.row(i) = Xsorted.row(0);
                }
            }
        }
    }
    else if (m_sDistance.compare("hamming") == 0)
    {
//    Xsum = zeros(k,p);
//    for i = 1:k
//        if m(i) > 0
//            % Sum coords for points in i'th cluster, component-wise
//            Xsum(i,:) = sum(X(idx==i,:), 1);
//        end
//    end
    }

    //
    // Begin phase two:  single reassignments
    //
    VectorXi changed = VectorXi(m.rows());
    qint32 count = 0;
    for(qint32 i = 0; i < m.rows(); ++i)
    {
        if(m[i] > 0)
        {
            changed[count] = i;
            ++count;
        }
    }
    changed.conservativeResize(count);

    qint32 lastmoved = 0;
    qint32 nummoved = 0;
    qint32 iter1 = iter;
    bool converged = false;
    while (iter < m_iMaxit)
    {
        // Calculate distances to each cluster from each point, and the
        // potential change in total sum of errors for adding or removing
        // each point from each cluster.  Clusters that have not changed
        // membership need not be updated.
        //
        // Singleton clusters are a special case for the sum of dists
        // calculation.  Removing their only point is never best, so the
        // reassignment criterion had better guarantee that a singleton
        // point will stay in its own cluster.  Happily, we get
        // Del(i,idx(i)) == 0 automatically for them.

        if (m_sDistance.compare("sqeuclidean") == 0)
        {
            for(qint32 j = 0; j < changed.rows(); ++j)
            {
                qint32 i = changed[j];
                VectorXi mbrs = VectorXi::Zero(idx.rows());
                for(qint32 l = 0; l < idx.rows(); ++l)
                    if(idx[l] == i)
                        mbrs[l] = 1;

                VectorXi sgn = 1 - 2 * mbrs.array(); // -1 for members, 1 for nonmembers

                if (m[i] == 1)
                    for(qint32 l = 0; l < mbrs.rows(); ++l)
                        if(mbrs[l])
                            sgn[l] = 0; // prevent divide-by-zero for singleton mbrs

                Del.col(i) = ((double)m[i] / ((double)m[i] + sgn.cast<double>().array()));

                Del.col(i).array() *= (X - C.row(i).replicate(n,1)).array().pow(2).rowwise().sum().array();
            }
        }
        else if (m_sDistance.compare("cityblock") == 0)
        {
            for(qint32 j = 0; j < changed.rows(); ++j)
            {
                qint32 i = changed[j];
                if (m(i) % 2 == 0) // this will never catch singleton clusters
                {
                    MatrixXd ldist = Xmid1.row(i).replicate(n,1) - X;
                    MatrixXd rdist = X - Xmid2.row(i).replicate(n,1);
                    VectorXd mbrs = VectorXd::Zero(idx.rows());

                    for(qint32 l = 0; l < idx.rows(); ++l)
                        if(idx[l] == i)
                            mbrs[l] = 1;
                    MatrixXd sgn = ((-2*mbrs).array() + 1).replicate(1, p); // -1 for members, 1 for nonmembers
                    rdist = sgn.array()*rdist.array(); ldist = sgn.array()*ldist.array();

                    for(qint32 l = 0; l < idx.rows(); ++l)
                    {
                        double sum = 0;
                        for(qint32 h = 0; h < rdist.cols(); ++h)
                            sum += rdist(l,h) > ldist(l,h) ? rdist(l,h) < 0 ? 0 : rdist(l,h) : ldist(l,h) < 0 ? 0 : ldist(l,h);
                        Del(l,i) = sum;
                    }
                }
                else
                    Del.col(i) = ((X - C.row(i).replicate(n,1)).array().abs()).rowwise().sum();
            }
        }
        else if (m_sDistance.compare("cosine") == 0 || m_sDistance.compare("correlation") == 0)
        {
            // The points are normalized, centroids are not, so normalize them
            MatrixXd normC = C.array().pow(2).rowwise().sum().sqrt();
//            if any(normC < eps(class(normC))) % small relative to unit-length data points
//                error('Zero cluster centroid created at iteration %d during replicate %d.',iter, rep);
//            end
            // This can be done without a loop, but the loop saves memory allocations
            MatrixXd XCi;
            qint32 i;
            for(qint32 j = 0; j < changed.rows(); ++j)
            {
                i = changed[j];
                XCi = X * C.row(i).transpose();

                VectorXi mbrs = VectorXi::Zero(idx.rows());
                for(qint32 l = 0; l < idx.rows(); ++l)
                    if(idx[l] == i)
                        mbrs[l] = 1;

                VectorXi sgn = 1 - 2 * mbrs.array(); // -1 for members, 1 for nonmembers


                double A = (double)m[i] * normC(i,0);
                double B = pow(((double)m[i] * normC(i,0)),2);

                Del.col(i) = 1 + sgn.cast<double>().array()*
                        (A - (B + 2 * sgn.cast<double>().array() * m[i] * XCi.array() + 1).sqrt());

                std::cout << "Del.col(i)\n" << Del.col(i) << std::endl;



//                Del(:,i) = 1 + sgn .*...
//                      (m(i).*normC(i) - sqrt((m(i).*normC(i)).^2 + 2.*sgn.*m(i).*XCi + 1));
            }
        }
        else if (m_sDistance.compare("hamming") == 0)
        {
//            for i = changed
//                if mod(m(i),2) == 0 % this will never catch singleton clusters
//                    % coords with an unequal number of 0s and 1s have a
//                    % different contribution than coords with an equal
//                    % number
//                    unequal01 = find(2*Xsum(i,:) ~= m(i));
//                    numequal01 = p - length(unequal01);
//                    mbrs = (idx == i);
//                    Di = abs(X(:,unequal01) - C(repmat(i,n,1),unequal01));
//                    Del(:,i) = (sum(Di, 2) + mbrs*numequal01) / p;
//                else
//                    Del(:,i) = sum(abs(X - C(repmat(i,n,1),:)), 2) / p;
//                end
//            end
        }

        // Determine best possible move, if any, for each point.  Next we
        // will pick one from those that actually did move.
        previdx = idx;
        prevtotsumD = totsumD;

        VectorXi nidx = VectorXi::Zero(Del.rows());
        VectorXd minDel = VectorXd::Zero(Del.rows());

        for(qint32 i = 0; i < Del.rows(); ++i)
            minDel[i] = Del.row(i).minCoeff(&nidx[i]);

        VectorXi moved = VectorXi::Zero(previdx.rows());
        qint32 count = 0;
        for(qint32 i = 0; i < moved.rows(); ++i)
        {
            if(previdx[i] != nidx[i])
            {
                moved[count] = i;
                ++count;
            }
        }
        moved.conservativeResize(count);

        if (moved.sum() > 0)
        {
            // Resolve ties in favor of not moving
            VectorXi moved_new = VectorXi::Zero(moved.rows());
            count = 0;
            for(qint32 i = 0; i < moved.rows(); ++i)
            {
                if ( Del.array()(previdx[moved(i)]*n + moved(i)) > minDel(moved(i)))
                {
                    moved_new[count] = moved[i];
                    ++count;
                }
            }
            moved_new.conservativeResize(count);
            moved = moved_new;
        }

        if (moved.rows() <= 0)
        {
            // Count an iteration if phase 2 did nothing at all, or if we're
            // in the middle of a pass through all the points
            if ((iter == iter1) || nummoved > 0)
            {
                ++iter;

//                printf("%6d\t%6d\t%8d\t%12g\n",iter,2,nummoved,totsumD);
            }
            converged = true;
            break;
        }

        // Pick the next move in cyclic order
        VectorXi moved_new(moved.rows());
        for(qint32 i = 0; i < moved.rows(); ++i)
            moved_new[i] = ((moved[i] - lastmoved) % n) + lastmoved;

        moved[0] = moved_new.minCoeff() % n;//+1
        moved.conservativeResize(1);

        // If we've gone once through all the points, that's an iteration
        if (moved[0] <= lastmoved)
        {
            ++iter;
//            printf("%6d\t%6d\t%8d\t%12g\n",iter,2,nummoved,totsumD);
            if(iter >= m_iMaxit)
                break;
            nummoved = 0;
        }
        ++nummoved;
        lastmoved = moved[0];

        qint32 oidx = idx(moved[0]);
        nidx[0] = nidx(moved[0]);
        nidx.conservativeResize(1);
        totsumD += Del(moved[0],nidx[0]) - Del(moved[0],oidx);

        // Update the cluster index vector, and the old and new cluster
        // counts and centroids
        idx[ moved[0] ] = nidx[0];
        m( nidx[0] ) = m( nidx[0] ) + 1;
        m( oidx ) = m( oidx ) - 1;


        if (m_sDistance.compare("sqeuclidean") == 0)
        {
            C.row(nidx[0]) = C.row(nidx[0]).array() + (X.row(moved[0]) - C.row(nidx[0])).array() / m[nidx[0]];
            C.row(oidx) = C.row(oidx).array() - (X.row(moved[0]) - C.row(oidx)).array() / m[oidx];
        }
        else if (m_sDistance.compare("cityblock") == 0)
        {
            VectorXi onidx(2);
            onidx << oidx, nidx[0];//ToDo always right?

            qint32 i;
            for(qint32 h = 0; h < 2; ++h)
            {
                i = onidx[h];
                // Separate out sorted coords for points in each cluster.
                // New centroid is the coord median, save values above and
                // below median.  All done component-wise.
                MatrixXd Xsorted(m[i],p);
                qint32 c = 0;
                for(qint32 j = 0; j < idx.rows(); ++j)
                {
                    if(idx[j] == i)
                    {
                        Xsorted.row(c) = X.row(j);
                        ++c;
                    }
                }
                for(qint32 j = 0; j < Xsorted.cols(); ++j)
                    std::sort(Xsorted.col(j).data(),Xsorted.col(j).data()+Xsorted.rows());


                qint32 nn = floor(0.5*m[i])-1;
                if ((m[i] % 2) == 0)
                {
                    C.row(i) = 0.5 * (Xsorted.row(nn) + Xsorted.row(nn+1));
                    Xmid1.row(i) = Xsorted.row(nn);
                    Xmid2.row(i) = Xsorted.row(nn+1);
                }
                else
                {
                    C.row(i) = Xsorted.row(nn+1);
                    if (m(i) > 1)
                    {
                        Xmid1.row(i) = Xsorted.row(nn);
                        Xmid2.row(i) = Xsorted.row(nn+2);
                    }
                    else
                    {
                        Xmid1.row(i) = Xsorted.row(0);
                        Xmid2.row(i) = Xsorted.row(0);
                    }
                }
            }
        }
        else if (m_sDistance.compare("cosine") == 0 || m_sDistance.compare("correlation") == 0)
        {
            C.row(nidx[0]).array() += (X.row(moved[0]) - C.row(nidx[0])).array() / m[nidx[0]];
            C.row(oidx).array() += (X.row(moved[0]) - C.row(oidx)).array() / m[oidx];
        }
        else if (m_sDistance.compare("hamming") == 0)
        {
//                % Update summed coords for points in each cluster.  New
//                % centroid is the coord median.  All done component-wise.
//                Xsum(nidx,:) = Xsum(nidx,:) + X(moved,:);
//                Xsum(oidx,:) = Xsum(oidx,:) - X(moved,:);
//                C(nidx,:) = .5*sign(2*Xsum(nidx,:) - m(nidx)) + .5;
//                C(oidx,:) = .5*sign(2*Xsum(oidx,:) - m(oidx)) + .5;
        }

        VectorXi sorted_onidx(1+nidx.rows());
        sorted_onidx << oidx, nidx;
        std::sort(sorted_onidx.data(), sorted_onidx.data()+sorted_onidx.rows());
        changed = sorted_onidx;
    } // phase two

    return converged;

} // nested function
예제 #14
0
파일: kmeans.cpp 프로젝트: cpieloth/mne-cpp
bool KMeans::batchUpdate(MatrixXd& X, MatrixXd& C, VectorXi& idx)
{
    // Every point moved, every cluster will need an update
    qint32 i = 0;
    VectorXi moved(n);
    for(i = 0; i < n; ++i)
        moved[i] = i;

    VectorXi changed(k);
    for(i = 0; i < k; ++i)
        changed[i] = i;

    previdx = VectorXi::Zero(n);

    prevtotsumD = std::numeric_limits<double>::max();//max double


    MatrixXd D = MatrixXd::Zero(X.rows(), k);

    //
    // Begin phase one:  batch reassignments
    //
    iter = 0;
    bool converged = false;
    while(true)
    {
        ++iter;

        // Calculate the new cluster centroids and counts, and update the
        // distance from every point to those new cluster centroids
        MatrixXd C_new;
        VectorXi m_new;
        KMeans::gcentroids(X, idx, changed, C_new, m_new);
        MatrixXd D_new = distfun(X, C_new, iter);

        for(qint32 i = 0; i < changed.rows(); ++i)
        {
            C.row(changed[i]) = C_new.row(i);
            D.col(changed[i]) = D_new.col(i);
            m[changed[i]] = m_new[i];
        }

        // Deal with clusters that have just lost all their members
        VectorXi empties = VectorXi::Zero(changed.rows());
        for(qint32 i = 0; i < changed.rows(); ++i)
            if(m(i) == 0)
                empties[i] = 1;

        if (empties.sum() > 0)
        {
            if (m_sEmptyact.compare("error") == 0)
            {
                throw 0;
            }
            else if (m_sEmptyact.compare("drop") == 0)
            {
    //            // Remove the empty cluster from any further processing
    //            D(:,empties) = NaN;
    //            changed = changed(m(changed) > 0);
    //            warning('Empty cluster created at iteration %d during replicate %d.',iter, rep,);
            }
            else if (m_sEmptyact.compare("singleton") == 0)
            {
    //            warning('Empty cluster created at iteration %d during replicate %d.', iter, rep);

    //            for i = empties
    //                d = D((idx-1)*n + (1:n)'); // use newly updated distances

    //                % Find the point furthest away from its current cluster.
    //                % Take that point out of its cluster and use it to create
    //                % a new singleton cluster to replace the empty one.
    //                [dlarge, lonely] = max(d);
    //                from = idx(lonely); % taking from this cluster
    //                if m(from) < 2
    //                    % In the very unusual event that the cluster had only
    //                    % one member, pick any other non-singleton point.
    //                    from = find(m>1,1,'first');
    //                    lonely = find(idx==from,1,'first');
    //                end
    //                C(i,:) = X(lonely,:);
    //                m(i) = 1;
    //                idx(lonely) = i;
    //                D(:,i) = distfun(X, C(i,:), distance, iter);

    //                % Update clusters from which points are taken
    //                [C(from,:), m(from)] = gcentroids(X, idx, from, distance);
    //                D(:,from) = distfun(X, C(from,:), distance, iter);
    //                changed = unique([changed from]);
    //            end
            }
        }

        // Compute the total sum of distances for the current configuration.
        totsumD = 0;
        for(qint32 i = 0; i < n; ++i)
            totsumD += D.array()(idx[i]*n+i);//Colum Major
        // Test for a cycle: if objective is not decreased, back out
        // the last step and move on to the single update phase
        if(prevtotsumD <= totsumD)
        {
            idx = previdx;
            MatrixXd C_new;
            VectorXi m_new;
            gcentroids(X, idx, changed, C_new, m_new);
            C.block(0,0,k,C.cols()) = C_new;
            m.block(0,0,k,1) = m_new;
            --iter;
            break;
        }

//        printf("%6d\t%6d\t%8d\t%12g\n",iter,1,moved.rows(),totsumD);
        if (iter >= m_iMaxit)
            break;

        // Determine closest cluster for each point and reassign points to clusters
        previdx = idx;
        prevtotsumD = totsumD;

        VectorXi nidx(D.rows());
        for(qint32 i = 0; i < D.rows(); ++i)
            d[i] = D.row(i).minCoeff(&nidx[i]);

        // Determine which points moved
        VectorXi moved = VectorXi::Zero(nidx.rows());
        qint32 count = 0;
        for(qint32 i = 0; i < nidx.rows(); ++i)
        {
            if(nidx[i] != previdx[i])
            {
                moved[count] = i;
                ++count;
            }
        }
        moved.conservativeResize(count);

        if (moved.rows() > 0)
        {
            // Resolve ties in favor of not moving
            VectorXi moved_new = VectorXi::Zero(moved.rows());
            count = 0;
            for(qint32 i = 0; i < moved.rows(); ++i)
            {
                if(D.array()(previdx[moved[i]] * n + moved[i]) > d[moved[i]])
                {
                    moved_new[count] = moved[i];
                    ++count;
                }
            }
            moved_new.conservativeResize(count);
            moved = moved_new;
        }

        if (moved.rows() == 0)
        {
            converged = true;
            break;
        }

        for(qint32 i = 0; i < moved.rows(); ++i)
            if(moved[i] >= 0)
                idx[ moved[i] ] = nidx[ moved[i] ];

        // Find clusters that gained or lost members
        std::vector<int> tmp;
        for(qint32 i = 0; i < moved.rows(); ++i)
            tmp.push_back(idx[moved[i]]);
        for(qint32 i = 0; i < moved.rows(); ++i)
            tmp.push_back(previdx[moved[i]]);

        std::sort(tmp.begin(),tmp.end());

        std::vector<int>::iterator it;
        it = std::unique(tmp.begin(),tmp.end());
        tmp.resize( it - tmp.begin() );

        changed.conservativeResize(tmp.size());

        for(quint32 i = 0; i < tmp.size(); ++i)
            changed[i] = tmp[i];
    } // phase one
    return converged;
} // nested function
예제 #15
0
MatrixXd MNEInverseOperator::cluster_kernel(const AnnotationSet &p_AnnotationSet, qint32 p_iClusterSize, MatrixXd& p_D) const
{
    MatrixXd p_outMT = this->m_K.transpose();

    QList<MNEClusterInfo> t_qListMNEClusterInfo;
    MNEClusterInfo t_MNEClusterInfo;
    t_qListMNEClusterInfo.append(t_MNEClusterInfo);
    t_qListMNEClusterInfo.append(t_MNEClusterInfo);

    //
    // Check consisty
    //
    if(this->isFixedOrient())
    {
        printf("Error: Fixed orientation not implemented jet!\n");
        return p_outMT;
    }

//    qDebug() << "p_outMT" << p_outMT.rows() << "x" << p_outMT.cols();

//    MatrixXd t_G_Whitened(0,0);
//    bool t_bUseWhitened = false;
//    //
//    //Whiten gain matrix before clustering -> cause diffenerent units Magnetometer, Gradiometer and EEG
//    //
//    if(!p_pNoise_cov.isEmpty() && !p_pInfo.isEmpty())
//    {
//        FiffInfo p_outFwdInfo;
//        FiffCov p_outNoiseCov;
//        MatrixXd p_outWhitener;
//        qint32 p_outNumNonZero;
//        //do whitening with noise cov
//        this->prepare_forward(p_pInfo, p_pNoise_cov, false, p_outFwdInfo, t_G_Whitened, p_outNoiseCov, p_outWhitener, p_outNumNonZero);
//        printf("\tWhitening the forward solution.\n");

//        t_G_Whitened = p_outWhitener*t_G_Whitened;
//        t_bUseWhitened = true;
//    }



    //
    // Assemble input data
    //
    qint32 count;
    qint32 offset;

    MatrixXd t_MT_new;

    for(qint32 h = 0; h < this->src.size(); ++h )
    {

        count = 0;
        offset = 0;

        // Offset for continuous indexing;
        if(h > 0)
            for(qint32 j = 0; j < h; ++j)
                offset += this->src[j].nuse;

        if(h == 0)
            printf("Cluster Left Hemisphere\n");
        else
            printf("Cluster Right Hemisphere\n");

        Colortable t_CurrentColorTable = p_AnnotationSet[h].getColortable();
        VectorXi label_ids = t_CurrentColorTable.getLabelIds();

        // Get label ids for every vertex
        VectorXi vertno_labeled = VectorXi::Zero(this->src[h].vertno.rows());

        //ToDo make this more universal -> using Label instead of annotations - obsolete when using Labels
        for(qint32 i = 0; i < vertno_labeled.rows(); ++i)
            vertno_labeled[i] = p_AnnotationSet[h].getLabelIds()[this->src[h].vertno[i]];

        //Qt Concurrent List
        QList<RegionMT> m_qListRegionMTIn;

        //
        // Generate cluster input data
        //
        for (qint32 i = 0; i < label_ids.rows(); ++i)
        {
            if (label_ids[i] != 0)
            {
                QString curr_name = t_CurrentColorTable.struct_names[i];//obj.label2AtlasName(label(i));
                printf("\tCluster %d / %li %s...", i+1, label_ids.rows(), curr_name.toUtf8().constData());

                //
                // Get source space indeces
                //
                VectorXi idcs = VectorXi::Zero(vertno_labeled.rows());
                qint32 c = 0;

                //Select ROIs //change this use label info with a hash tabel
                for(qint32 j = 0; j < vertno_labeled.rows(); ++j)
                {
                    if(vertno_labeled[j] == label_ids[i])
                    {
                        idcs[c] = j;
                        ++c;
                    }
                }
                idcs.conservativeResize(c);

                //get selected MT
                MatrixXd t_MT(p_outMT.rows(), idcs.rows()*3);

                for(qint32 j = 0; j < idcs.rows(); ++j)
                    t_MT.block(0, j*3, t_MT.rows(), 3) = p_outMT.block(0, (idcs[j]+offset)*3, t_MT.rows(), 3);

                qint32 nSens = t_MT.rows();
                qint32 nSources = t_MT.cols()/3;

                if (nSources > 0)
                {
                    RegionMT t_sensMT;

                    t_sensMT.idcs = idcs;
                    t_sensMT.iLabelIdxIn = i;
                    t_sensMT.nClusters = ceil((double)nSources/(double)p_iClusterSize);

                    t_sensMT.matRoiMTOrig = t_MT;

                    printf("%d Cluster(s)... ", t_sensMT.nClusters);

                    // Reshape Input data -> sources rows; sensors columns
                    t_sensMT.matRoiMT = MatrixXd(t_MT.cols()/3, 3*nSens);

                    for(qint32 j = 0; j < nSens; ++j)
                        for(qint32 k = 0; k < t_sensMT.matRoiMT.rows(); ++k)
                            t_sensMT.matRoiMT.block(k,j*3,1,3) = t_MT.block(j,k*3,1,3);

                    m_qListRegionMTIn.append(t_sensMT);

                    printf("[added]\n");
                }
                else
                {
                    printf("failed! Label contains no sources.\n");
                }
            }
        }


        //
        // Calculate clusters
        //
        printf("Clustering... ");
        QFuture< RegionMTOut > res;
        res = QtConcurrent::mapped(m_qListRegionMTIn, &RegionMT::cluster);
        res.waitForFinished();

        //
        // Assign results
        //
        MatrixXd t_MT_partial;

        qint32 nClusters;
        qint32 nSens;
        QList<RegionMT>::const_iterator itIn;
        itIn = m_qListRegionMTIn.begin();
        QFuture<RegionMTOut>::const_iterator itOut;
        for (itOut = res.constBegin(); itOut != res.constEnd(); ++itOut)
        {
            nClusters = itOut->ctrs.rows();
            nSens = itOut->ctrs.cols()/3;
            t_MT_partial = MatrixXd::Zero(nSens, nClusters*3);

//            std::cout << "Number of Clusters: " << nClusters << " x " << nSens << std::endl;//itOut->iLabelIdcsOut << std::endl;

            //
            // Assign the centroid for each cluster to the partial G
            //
            //ToDo change this use indeces found with whitened data
            for(qint32 j = 0; j < nSens; ++j)
                for(qint32 k = 0; k < nClusters; ++k)
                    t_MT_partial.block(j, k*3, 1, 3) = itOut->ctrs.block(k,j*3,1,3);

            //
            // Get cluster indizes and its distances to the centroid
            //
            for(qint32 j = 0; j < nClusters; ++j)
            {
                VectorXi clusterIdcs = VectorXi::Zero(itOut->roiIdx.rows());
                VectorXd clusterDistance = VectorXd::Zero(itOut->roiIdx.rows());
                qint32 nClusterIdcs = 0;
                for(qint32 k = 0; k < itOut->roiIdx.rows(); ++k)
                {
                    if(itOut->roiIdx[k] == j)
                    {
                        clusterIdcs[nClusterIdcs] = itIn->idcs[k];
//                        qint32 offset = h == 0 ? 0 : this->src[0].nuse;
//                        Q_UNUSED(offset)
                        clusterDistance[nClusterIdcs] = itOut->D(k,j);
                        ++nClusterIdcs;
                    }
                }
                clusterIdcs.conservativeResize(nClusterIdcs);
                clusterDistance.conservativeResize(nClusterIdcs);

                VectorXi clusterVertnos = VectorXi::Zero(clusterIdcs.size());
                for(qint32 k = 0; k < clusterVertnos.size(); ++k)
                    clusterVertnos(k) = this->src[h].vertno[clusterIdcs(k)];

                t_qListMNEClusterInfo[h].clusterVertnos.append(clusterVertnos);

            }


            //
            // Assign partial G to new LeadField
            //
            if(t_MT_partial.rows() > 0 && t_MT_partial.cols() > 0)
            {
                t_MT_new.conservativeResize(t_MT_partial.rows(), t_MT_new.cols() + t_MT_partial.cols());
                t_MT_new.block(0, t_MT_new.cols() - t_MT_partial.cols(), t_MT_new.rows(), t_MT_partial.cols()) = t_MT_partial;

                // Map the centroids to the closest rr
                for(qint32 k = 0; k < nClusters; ++k)
                {
                    qint32 j = 0;

                    double sqec = sqrt((itIn->matRoiMTOrig.block(0, j*3, itIn->matRoiMTOrig.rows(), 3) - t_MT_partial.block(0, k*3, t_MT_partial.rows(), 3)).array().pow(2).sum());
                    double sqec_min = sqec;
                    qint32 j_min = 0;
//                    MatrixXd matGainDiff;
                    for(qint32 j = 1; j < itIn->idcs.rows(); ++j)
                    {
                        sqec = sqrt((itIn->matRoiMTOrig.block(0, j*3, itIn->matRoiMTOrig.rows(), 3) - t_MT_partial.block(0, k*3, t_MT_partial.rows(), 3)).array().pow(2).sum());

                        if(sqec < sqec_min)
                        {
                            sqec_min = sqec;
                            j_min = j;
//                            matGainDiff = itIn->matRoiGOrig.block(0, j*3, itIn->matRoiGOrig.rows(), 3) - t_G_partial.block(0, k*3, t_G_partial.rows(), 3);
                        }
                    }

//                    qListGainDist.append(matGainDiff);

                    // Take the closest coordinates
//                    qint32 sel_idx = itIn->idcs[j_min];
//                    Q_UNUSED(sel_idx)

//                    //vertices
//                    std::cout << this->src[h].vertno[sel_idx] << ", ";

                    ++count;
                }
            }

            ++itIn;
        }

        printf("[done]\n");
    }


    //
    // Cluster operator D (sources x clusters)
    //
    qint32 totalNumOfClust = 0;
    for (qint32 h = 0; h < 2; ++h)
        totalNumOfClust += t_qListMNEClusterInfo[h].clusterVertnos.size();

    if(this->isFixedOrient())
        p_D = MatrixXd::Zero(p_outMT.cols(), totalNumOfClust);
    else
        p_D = MatrixXd::Zero(p_outMT.cols(), totalNumOfClust*3);

    QList<VectorXi> t_vertnos = this->src.get_vertno();

//    qDebug() << "Size: " << t_vertnos[0].size()  << t_vertnos[1].size();
//    qDebug() << "this->sol->data.cols(): " << this->sol->data.cols();

    qint32 currentCluster = 0;
    for (qint32 h = 0; h < 2; ++h)
    {
        int hemiOffset = h == 0 ? 0 : t_vertnos[0].size();
        for(qint32 i = 0; i < t_qListMNEClusterInfo[h].clusterVertnos.size(); ++i)
        {
            VectorXi idx_sel;
            MNEMath::intersect(t_vertnos[h], t_qListMNEClusterInfo[h].clusterVertnos[i], idx_sel);

//            std::cout << "\nVertnos:\n" << t_vertnos[h] << std::endl;

//            std::cout << "clusterVertnos[i]:\n" << t_qListMNEClusterInfo[h].clusterVertnos[i] << std::endl;

            idx_sel.array() += hemiOffset;

//            std::cout << "idx_sel]:\n" << idx_sel << std::endl;



            double selectWeight = 1.0/idx_sel.size();
            if(this->isFixedOrient())
            {
                for(qint32 j = 0; j < idx_sel.size(); ++j)
                    p_D.col(currentCluster)[idx_sel(j)] = selectWeight;
            }
            else
            {
                qint32 clustOffset = currentCluster*3;
                for(qint32 j = 0; j < idx_sel.size(); ++j)
                {
                    qint32 idx_sel_Offset = idx_sel(j)*3;
                    //x
                    p_D(idx_sel_Offset,clustOffset) = selectWeight;
                    //y
                    p_D(idx_sel_Offset+1, clustOffset+1) = selectWeight;
                    //z
                    p_D(idx_sel_Offset+2, clustOffset+2) = selectWeight;
                }
            }
            ++currentCluster;
        }
    }

//    std::cout << "D:\n" << D.row(0) << std::endl << D.row(1) << std::endl << D.row(2) << std::endl << D.row(3) << std::endl << D.row(4) << std::endl << D.row(5) << std::endl;

    //
    // Put it all together
    //
    p_outMT = t_MT_new;

    return p_outMT;
}