void tst_QtConcurrentIterateKernel::multipleResults() { QFuture<int> f = startThreadEngine(new MultipleResultsFor(0, 10)).startAsynchronously(); QCOMPARE(f.results().count() , 10); QCOMPARE(f.resultAt(0), 0); QCOMPARE(f.resultAt(5), 5); QCOMPARE(f.resultAt(9), 9); f.waitForFinished(); }
QList<LocatorFilterEntry> BasicLocatorFilterTest::matchesFor(const QString &searchText) { doBeforeLocatorRun(); const QList<ILocatorFilter *> filters = QList<ILocatorFilter *>() << m_filter; QFuture<LocatorFilterEntry> locatorSearch = QtConcurrent::run(Core::Internal::runSearch, filters, searchText); locatorSearch.waitForFinished(); doAfterLocatorRun(); return locatorSearch.results(); }
void tst_QtConcurrentThreadEngine::multipleResults() { MultipleResultsUser *engine = new MultipleResultsUser(); QFuture<int> f = engine->startAsynchronously(); QCOMPARE(f.results().count() , 10); QCOMPARE(f.resultAt(0), 0); QCOMPARE(f.resultAt(5), 5); QCOMPARE(f.resultAt(9), 9); f.waitForFinished(); }
QList<LocatorFilterEntry> BasicLocatorFilterTest::matchesFor(const QString &searchText) { doBeforeLocatorRun(); const QList<ILocatorFilter *> filters = QList<ILocatorFilter *>() << m_filter; m_filter->prepareSearch(searchText); QFuture<LocatorFilterEntry> locatorSearch = Utils::runAsync(&Internal::runSearch, filters, searchText); locatorSearch.waitForFinished(); doAfterLocatorRun(); return locatorSearch.results(); }
bool ActivitySessionData::setCurrentActivity(const QString &activityId) { QFuture<bool> rv; QMetaObject::invokeMethod(m_activitiesProxy, "setCurrentActivity", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QFuture<bool>, rv), Q_ARG(QString, activityId)); rv.waitForFinished(); //TODO: this shows one of the weaknesses in the QFuture based APIs .... bool value = rv.results().isEmpty() ? false : rv.result(); return value; }
void tst_QFuture::resultsAsList() { IntResult a; a.reportStarted(); QFuture<int> f = a.future(); int result; result = 1; a.reportResult(&result); result = 2; a.reportResult(&result); a.reportFinished(); QList<int> results = f.results(); QCOMPARE(results, QList<int>() << 1 << 2); }
/* Tests that a QFuture can return multiple results. */ void tst_QFuture::multipleResults() { IntResult a; a.reportStarted(); QFuture<int> f = a.future(); QFuture<int> copy = f; int result; result = 1; a.reportResult(&result); QCOMPARE(f.resultAt(0), 1); result = 2; a.reportResult(&result); QCOMPARE(f.resultAt(1), 2); result = 3; a.reportResult(&result); result = 4; a.reportFinished(&result); QCOMPARE(f.results(), QList<int>() << 1 << 2 << 3 << 4); // test foreach QList<int> fasit = QList<int>() << 1 << 2 << 3 << 4; { QList<int> results; foreach(int result, f) results.append(result); QCOMPARE(results, fasit); } { QList<int> results; foreach(int result, copy) results.append(result); QCOMPARE(results, fasit); } }
void tst_QFuture::iterators() { { QFutureInterface<int> e; e.reportStarted(); QFuture<int> f = e.future(); int result; result = 1; e.reportResult(&result); result = 2; e.reportResult(&result); result = 3; e.reportResult(&result); e.reportFinished(); QList<int> results; QFutureIterator<int> i(f); while (i.hasNext()) { results.append(i.next()); } QCOMPARE(results, f.results()); QFuture<int>::const_iterator i1 = f.begin(), i2 = i1 + 1; QFuture<int>::const_iterator c1 = i1, c2 = c1 + 1; QCOMPARE(i1, i1); QCOMPARE(i1, c1); QCOMPARE(c1, i1); QCOMPARE(c1, c1); QCOMPARE(i2, i2); QCOMPARE(i2, c2); QCOMPARE(c2, i2); QCOMPARE(c2, c2); QVERIFY(i1 != i2); QVERIFY(i1 != c2); QVERIFY(c1 != i2); QVERIFY(c1 != c2); QVERIFY(i2 != i1); QVERIFY(i2 != c1); QVERIFY(c2 != i1); QVERIFY(c2 != c1); int x1 = *i1; Q_UNUSED(x1); int x2 = *i2; Q_UNUSED(x2); int y1 = *c1; Q_UNUSED(y1); int y2 = *c2; Q_UNUSED(y2); } { QFutureInterface<QString> e; e.reportStarted(); QFuture<QString> f = e.future(); e.reportResult(QString("one")); e.reportResult(QString("two")); e.reportResult(QString("three")); e.reportFinished(); QList<QString> results; QFutureIterator<QString> i(f); while (i.hasNext()) { results.append(i.next()); } QCOMPARE(results, f.results()); QFuture<QString>::const_iterator i1 = f.begin(), i2 = i1 + 1; QFuture<QString>::const_iterator c1 = i1, c2 = c1 + 1; QCOMPARE(i1, i1); QCOMPARE(i1, c1); QCOMPARE(c1, i1); QCOMPARE(c1, c1); QCOMPARE(i2, i2); QCOMPARE(i2, c2); QCOMPARE(c2, i2); QCOMPARE(c2, c2); QVERIFY(i1 != i2); QVERIFY(i1 != c2); QVERIFY(c1 != i2); QVERIFY(c1 != c2); QVERIFY(i2 != i1); QVERIFY(i2 != c1); QVERIFY(c2 != i1); QVERIFY(c2 != c1); QString x1 = *i1; QString x2 = *i2; QString y1 = *c1; QString y2 = *c2; QCOMPARE(x1, y1); QCOMPARE(x2, y2); int i1Size = i1->size(); int i2Size = i2->size(); int c1Size = c1->size(); int c2Size = c2->size(); QCOMPARE(i1Size, c1Size); QCOMPARE(i2Size, c2Size); } { const int resultCount = 20; QFutureInterface<int> e; e.reportStarted(); QFuture<int> f = e.future(); for (int i = 0; i < resultCount; ++i) { e.reportResult(i); } e.reportFinished(); { QFutureIterator<int> it(f); QFutureIterator<int> it2(it); } { QFutureIterator<int> it(f); for (int i = 0; i < resultCount - 1; ++i) { QVERIFY(it.hasNext()); QCOMPARE(it.peekNext(), i); QCOMPARE(it.next(), i); } QVERIFY(it.hasNext()); QCOMPARE(it.peekNext(), resultCount - 1); QCOMPARE(it.next(), resultCount - 1); QVERIFY(!it.hasNext()); } { QFutureIterator<int> it(f); QVERIFY(it.hasNext()); it.toBack(); QVERIFY(!it.hasNext()); it.toFront(); QVERIFY(it.hasNext()); } } }
/* Test out-of-order result reporting using indexes */ void tst_QFuture::indexedResults() { { QFutureInterface<QChar> Interface; QFuture<QChar> f; QVERIFY(f.isStarted()); Interface.reportStarted(); f = Interface.future(); QVERIFY(f.isStarted()); QChar result; result = 'B'; Interface.reportResult(&result, 1); QCOMPARE(f.resultAt(1), result); result = 'A'; Interface.reportResult(&result, 0); QCOMPARE(f.resultAt(0), result); result = 'C'; Interface.reportResult(&result); // no index QCOMPARE(f.resultAt(2), result); Interface.reportFinished(); QCOMPARE(f.results(), QList<QChar>() << 'A' << 'B' << 'C'); } { // Test result reporting with a missing result in the middle QFutureInterface<int> Interface; Interface.reportStarted(); QFuture<int> f = Interface.future(); int result; result = 0; Interface.reportResult(&result, 0); QVERIFY(f.isResultReadyAt(0)); QCOMPARE(f.resultAt(0), 0); result = 3; Interface.reportResult(&result, 3); QVERIFY(f.isResultReadyAt(3)); QCOMPARE(f.resultAt(3), 3); result = 2; Interface.reportResult(&result, 2); QVERIFY(f.isResultReadyAt(2)); QCOMPARE(f.resultAt(2), 2); result = 4; Interface.reportResult(&result); // no index QVERIFY(f.isResultReadyAt(4)); QCOMPARE(f.resultAt(4), 4); Interface.reportFinished(); QCOMPARE(f.results(), QList<int>() << 0 << 2 << 3 << 4); } }
void tst_QFuture::cancel() { { QFuture<void> f; QFutureInterface<void> result; result.reportStarted(); f = result.future(); QVERIFY(!f.isCanceled()); result.reportCanceled(); QVERIFY(f.isCanceled()); result.reportFinished(); QVERIFY(f.isCanceled()); f.waitForFinished(); QVERIFY(f.isCanceled()); } // Cancel from the QFuture side and test if the result // interface detects it. { QFutureInterface<void> result; QFuture<void> f; QVERIFY(f.isStarted()); result.reportStarted(); f = result.future(); QVERIFY(f.isStarted()); QVERIFY(!result.isCanceled()); f.cancel(); QVERIFY(result.isCanceled()); result.reportFinished(); } // Test that finished futures can be canceled. { QFutureInterface<void> result; QFuture<void> f; QVERIFY(f.isStarted()); result.reportStarted(); f = result.future(); QVERIFY(f.isStarted()); result.reportFinished(); f.cancel(); QVERIFY(result.isCanceled()); QVERIFY(f.isCanceled()); } // Results reported after canceled is called should not be propagated. { QFutureInterface<int> futureInterface; futureInterface.reportStarted(); QFuture<int> f = futureInterface.future(); int result = 0; futureInterface.reportResult(&result); result = 1; futureInterface.reportResult(&result); f.cancel(); result = 2; futureInterface.reportResult(&result); result = 3; futureInterface.reportResult(&result); futureInterface.reportFinished(); QCOMPARE(f.results(), QList<int>()); } }
void BCI::run() { while(m_bIsRunning) { // Wait for fiff Info if not yet received - this is needed because we have to wait until the buffers are firstly initiated in the update functions while(!m_pFiffInfo_Sensor) msleep(10); // Start filling buffers with data from the inputs m_bProcessData = true; // Sensor level: Fill matrices with data if(m_bFillSensorWindowFirstTime) // Sensor level: Fill m_matSlidingWindowSensor with data for the first time { if(m_iTBWIndexSensor < m_matSlidingWindowSensor.cols()) { //cout<<"About to pop matrix"<<endl; MatrixXd t_mat = m_pBCIBuffer_Sensor->pop(); //cout<<"poped matrix"<<endl; // Get only the rows from the matrix which correspond with the selected features, namely electrodes on sensor level and destrieux clustered regions on source level for(int i = 0; i < m_matSlidingWindowSensor.rows(); i++) m_matSlidingWindowSensor.block(i, m_iTBWIndexSensor, 1, t_mat.cols()) = t_mat.block(m_mapElectrodePinningScheme[m_slChosenFeatureSensor.at(i)], 0, 1, t_mat.cols()); m_matStimChannelSensor.block(0, m_iTBWIndexSensor, 1, t_mat.cols()) = t_mat.block(136, 0, 1, t_mat.cols()); m_iTBWIndexSensor = m_iTBWIndexSensor + t_mat.cols(); } else // m_matSlidingWindowSensor is full for the first time { m_iTBWIndexSensor = 0; m_bFillSensorWindowFirstTime = false; } } else // Sensor level: Fill m_matTimeBetweenWindowsSensor matrix until full -> Then -> recalculate m_matSlidingWindowSensor, calculate features and classify { if(m_iTBWIndexSensor < m_matTimeBetweenWindowsSensor.cols()) { //cout<<"About to pop matrix"<<endl; MatrixXd t_mat = m_pBCIBuffer_Sensor->pop(); //cout<<"poped matrix"<<endl; // Get only the rows from the matrix which correspond with the selected features, namely electrodes on sensor level and destrieux clustered regions on source level for(int i = 0; i < m_matTimeBetweenWindowsSensor.rows(); i++) m_matTimeBetweenWindowsSensor.block(i, m_iTBWIndexSensor, 1, t_mat.cols()) = t_mat.block(m_mapElectrodePinningScheme[m_slChosenFeatureSensor.at(i)], 0, 1, t_mat.cols()); m_matTimeBetweenWindowsStimSensor.block(0, m_iTBWIndexSensor, 1, t_mat.cols()) = t_mat.block(136, 0, 1, t_mat.cols()); m_iTBWIndexSensor = m_iTBWIndexSensor + t_mat.cols(); } else // Recalculate m_matSlidingWindowSensor -> Calculate features, classify and store results { // ----1---- Recalculate m_matSlidingWindowSensor //cout<<"----1----"<<endl; //Move block from the right to the left -> use eval() to resolve Eigens aliasing problem m_matSlidingWindowSensor.block(0, 0, m_matSlidingWindowSensor.rows(), m_matSlidingWindowSensor.cols()-m_matTimeBetweenWindowsSensor.cols()) = m_matSlidingWindowSensor.block(0, m_matTimeBetweenWindowsSensor.cols(), m_matSlidingWindowSensor.rows(), m_matSlidingWindowSensor.cols()-m_matTimeBetweenWindowsSensor.cols()).eval(); m_matStimChannelSensor.block(0, 0, m_matStimChannelSensor.rows(), m_matStimChannelSensor.cols()-m_matTimeBetweenWindowsStimSensor.cols()) = m_matStimChannelSensor.block(0, m_matTimeBetweenWindowsStimSensor.cols(), m_matStimChannelSensor.rows(), m_matStimChannelSensor.cols()-m_matTimeBetweenWindowsStimSensor.cols()).eval(); // push m_matTimeBetweenWindowsSensor from the right m_matSlidingWindowSensor.block(0, m_matSlidingWindowSensor.cols()-m_matTimeBetweenWindowsSensor.cols(), m_matTimeBetweenWindowsSensor.rows(), m_matTimeBetweenWindowsSensor.cols()) = m_matTimeBetweenWindowsSensor; m_matStimChannelSensor.block(0, m_matStimChannelSensor.cols()-m_matTimeBetweenWindowsStimSensor.cols(), m_matTimeBetweenWindowsStimSensor.rows(), m_matTimeBetweenWindowsStimSensor.cols()) = m_matTimeBetweenWindowsStimSensor; //cout<<m_matStimChannelSensor; // Test if data is correctly streamed to this plugin if(m_slChosenFeatureSensor.contains("TEST")) { cout<<"Recalculate matrix"<<endl; for(int i = 0; i<m_matSlidingWindowSensor.cols() ; i++) cout << m_matSlidingWindowSensor(m_matSlidingWindowSensor.rows()-1,i) <<endl; // for(int i = 1; i<m_matSlidingWindowSensor.cols() ; i++) // { // cout << m_matSlidingWindowSensor(m_matSlidingWindowSensor.rows()-1,i-1) <<endl; // if(m_matSlidingWindowSensor(m_matSlidingWindowSensor.rows()-1,i) - m_matSlidingWindowSensor(m_matSlidingWindowSensor.rows()-1,i-1) != 1) // cout<<"Sequence error while streaming from tmsi plugin at position: "<<i<<endl; // } } // ----2---- Transform matrix into QList structure, so that QTConcurrent can handle it properly //cout<<"----2----"<<endl; QList< QPair<int,RowVectorXd> > qlMatrixRows; for(int i = 0; i< m_matSlidingWindowSensor.rows(); i++) qlMatrixRows << QPair<int,RowVectorXd>(i, m_matSlidingWindowSensor.row(i)); int iNumberOfFeatures = qlMatrixRows.size(); // ----3---- Subtract mean in m_matSlidingWindowSensor concurrently using map() //cout<<"----3----"<<endl; if(m_bSubtractMean) { QFuture<void> futureMean = QtConcurrent::map(qlMatrixRows,[this](QPair<int,RowVectorXd>& rowdata) { applyMeanCorrectionConcurrently(rowdata); }); futureMean.waitForFinished(); } // ----4---- Do simple threshold artefact reduction //cout<<"----4----"<<endl; if(hasThresholdArtefact(qlMatrixRows) == false) { // Look for trigger flag if(lookForTrigger(m_matStimChannelSensor) && !m_bTriggerActivated) { // cout << "Trigger activated" << endl; //QFuture<void> future = QtConcurrent::run(Beep, 450, 700); m_bTriggerActivated = true; } // ----5---- Filter data in m_matSlidingWindowSensor concurrently using map() //cout<<"----5----"<<endl; // TODO: work only on qlMatrixRows -> filteredRows doesnt need to be created -> more efficient QList< QPair<int,RowVectorXd> > filteredRows = qlMatrixRows; if(m_bUseFilter) { QFuture<void> futureFilter = QtConcurrent::map(filteredRows,[this](QPair<int,RowVectorXd>& chdata) { applyFilterOperatorConcurrently(chdata); }); futureFilter.waitForFinished(); } // // Write data before and after filtering to debug file // for(int i=0; i<qlMatrixRows.size(); i++) // m_outStreamDebug << "qlMatrixRows at row " << i << ": " << qlMatrixRows.at(i).second << "\n"; // m_outStreamDebug<<endl; // for(int i=0; i<filteredRows.size(); i++) // m_outStreamDebug << "filteredRows at row " << i << ": " << filteredRows.at(i).second << "\n"; // m_outStreamDebug << endl << "---------------------------------------------------------" << endl << endl; // // Write filtered data continously to file // for(int i = 0; i<filteredRows.at(0).second.size() ;i++) // m_outStreamDebug << filteredRows.at(0).second(i)<<endl; // ----6---- Calculate features concurrently using mapped() //cout<<"----6----"<<endl; std::function< QPair<int,QList<double> > (QPair<int,RowVectorXd>&)> applyOpsFeatures = [this](QPair<int,RowVectorXd>& chdata) -> QPair< int,QList<double> > { return applyFeatureCalcConcurrentlyOnSensorLevel(chdata); }; QFuture< QPair< int,QList<double> > > futureCalculatedFeatures = QtConcurrent::mapped(filteredRows.begin(), filteredRows.end(), applyOpsFeatures); futureCalculatedFeatures.waitForFinished(); m_iNumberOfCalculatedFeatures++; // ----7---- Store features //cout<<"----7----"<<endl; m_lFeaturesSensor.append(futureCalculatedFeatures.results()); // ----8---- If enough features (windows) have been calculated (processed) -> classify all features and average results //cout<<"----8----"<<endl; if(m_iNumberOfCalculatedFeatures == m_iNumberFeatures) { // Transform m_lFeaturesSensor into an easier file structure -> create feature points QList< QList<double> > lFeaturesSensor_new; for(int i = 0; i<m_lFeaturesSensor.size()-iNumberOfFeatures+1; i = i + iNumberOfFeatures) // iterate over QPair feature List for(int z = 0; z<m_lFeaturesSensor.at(0).second.size(); z++) // iterate over number of sub signals { QList<double> temp; for(int t = 0; t<iNumberOfFeatures; t++) // iterate over chosen features (electrodes) temp.append(m_lFeaturesSensor.at(i+t).second.at(z)); lFeaturesSensor_new.append(temp); } // //Check sizes // cout<<"lFeaturesSensor_new.size()"<<lFeaturesSensor_new.size()<<endl; // cout<<"lFeaturesSensor_new.at(0).size()"<<lFeaturesSensor_new.at(0).size()<<endl; // cout<<"m_lFeaturesSensor.size()"<<m_lFeaturesSensor.size()<<endl; // Display features if(m_bDisplayFeatures) emit paintFeatures((MyQList)lFeaturesSensor_new, m_bTriggerActivated); // Reset trigger m_bTriggerActivated = false; // ----9---- Classify features concurrently using mapped() ---------- //cout<<"----9----"<<endl; std::function<double (QList<double>&)> applyOpsClassification = [this](QList<double>& featData){ return applyClassificationCalcConcurrentlyOnSensorLevel(featData); }; QFuture<double> futureClassificationResults = QtConcurrent::mapped(lFeaturesSensor_new.begin(), lFeaturesSensor_new.end(), applyOpsClassification); futureClassificationResults.waitForFinished(); // ----10---- Generate final classification result -> average all classification results //cout<<"----10----"<<endl; double dfinalResult = 0; for(int i = 0; i<futureClassificationResults.resultCount() ;i++) dfinalResult += futureClassificationResults.resultAt(i); dfinalResult = dfinalResult/futureClassificationResults.resultCount(); //cout << "dfinalResult" << dfinalResult << endl << endl; // ----11---- Store final result //cout<<"----11----"<<endl; m_lClassResultsSensor.append(dfinalResult); // ----12---- Send result to the output stream, i.e. which is connected to the triggerbox //cout<<"----12----"<<endl; VectorXd variances(iNumberOfFeatures); variances.setZero(); for(int i = 0; i<lFeaturesSensor_new.size(); i++) for(int t = 0; t<iNumberOfFeatures; t++) variances(t) = variances(t) + lFeaturesSensor_new.at(i).at(t); variances = variances/lFeaturesSensor_new.size(); m_pBCIOutputOne->data()->setValue(dfinalResult); m_pBCIOutputTwo->data()->setValue(variances(0)); m_pBCIOutputThree->data()->setValue(variances(1)); for(int i = 0; i<filteredRows.at(0).second.cols() ; i++) { m_pBCIOutputFour->data()->setValue(filteredRows.at(0).second(0,i)); m_pBCIOutputFive->data()->setValue(filteredRows.at(1).second(0,i)); } // Clear classifications clearFeatures(); // Reset counter m_iNumberOfCalculatedFeatures = 0; } // End if enough features (windows) have been calculated (processed) } // End if artefact reduction else { // If trial has been rejected -> plot zeros as result and the filtered electrode channel m_pBCIOutputOne->data()->setValue(0); m_pBCIOutputTwo->data()->setValue(0); m_pBCIOutputThree->data()->setValue(0); QList< QPair<int,RowVectorXd> > filteredRows = qlMatrixRows; if(m_bUseFilter) { QFuture<void> futureFilter = QtConcurrent::map(filteredRows,[this](QPair<int,RowVectorXd>& chdata) { applyFilterOperatorConcurrently(chdata); }); futureFilter.waitForFinished(); } for(int i = 0; i<filteredRows.at(0).second.cols() ; i++) { m_pBCIOutputFour->data()->setValue(filteredRows.at(0).second(0,i)); m_pBCIOutputFive->data()->setValue(filteredRows.at(1).second(0,i)); } } m_iTBWIndexSensor = 0; } } } }