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(); }
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; }
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()); }
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; }
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; }
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); } }
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--;} } } } } }
// 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(); }
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); }
//************************************************************************************************************* //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
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; }
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
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
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; }