// separator is a string containing the symbol/character separating entries
	// and replace contains a separator-separated list of characters to replace
	// by the separator beforehand
	QList<double> DynamicsPlotterUtil::getDoublesFromString(const QString &list,
	const QString &separator, const QString &replace) {
		QString tmp(list);
		if(!replace.isEmpty()) {
			QStringList replist = replace.split(separator, QString::SkipEmptyParts);
			for(int i = 0; i < replist.size(); ++i) {
				tmp.replace(replist.at(i), separator);
			}
		}
		QStringList doublelist = tmp.split(separator, QString::SkipEmptyParts);
		QList<double> output;
		bool ok;

		for(int i = 0; i < doublelist.size(); ++i) {
			double d = doublelist.at(i).toDouble(&ok);

			if(!ok) {
				reportProblem("DynamicsPlotterUtil::getDoublesFromString : "
							  "Unable to convert ["+doublelist.at(i)+"] to double");
				return QList<double>();
			}

			output.append(d);
		}
		return output;
	}
Exemple #2
0
static int
loadCoreLibrary (JNIEnv *env) {
  if (coreHandle) return 1;

  if ((coreHandle = dlopen("libbrltty_core.so", RTLD_NOW | RTLD_GLOBAL))) {
    int allFound = 1;
    const SymbolEntry *symbol = symbolTable;

    while (symbol->name) {
      const void **pointer = symbol->pointer;

      if ((*pointer = dlsym(coreHandle, symbol->name))) {
        LOG("core symbol: %s -> %p", symbol->name, *pointer);
      } else {
        LOG("core symbol not found: %s", symbol->name);
        allFound = 0;
      }

      symbol += 1;
    }

    if (allFound) return 1;
  }

  reportProblem(env, "java/lang/UnsatisfiedLinkError", "%s", dlerror());
  return 0;
}
	/**
	 *
	 * The neuronsWithActivationChange parameter can be used to collect all DoubelValues that correspond
	 * to activation values of neurons. These neurons have to be collected in each DymnamcisPlotter in
	 * variable DynamcisPlotter::mNeuronsWithActivationsToTransfer to be handled correctly, if the
	 * activation of a neuron should be varied during an analyzer run. Otherwise the varied activations
	 * are immediately overwritten by the newly calculated activations at the first network update.
	 *
	 * If this method is used to collect elements that will NOT be changed during analyzer runs,
	 * then the last parameter MUST be empty. Othewise activations of neurons collected in this way
	 * will be treated differently compared to the other neurons in the network. This may lead to
	 * unexpected and erroneous behavior.
	 *
	 * @param specifier the specification of the desired DoubleValue object.
	 * @param networkElements the list of objects that are considered to find the specified DoubleValue object.
	 * @param neuronsWithActivationChange (optional) list to collect all activation values that are going to be changed during a run.
	 */
	DoubleValue* DynamicsPlotterUtil::getElementValue(QString const &specifier,
													  QList<NeuralNetworkElement*> const &networkElements,
													  QList<Neuron*> *neuronsWithActivationChange)
	{
		if(specifier.isEmpty()) {
			reportProblem("DynamicsPlotterUtil::getElementValue(2) : "
						  "Empty specifier!");
			return 0;
		}

		QStringList specifierParts = specifier.split(":");
		if(specifierParts.size() < 2 || specifierParts.size() > 3) {
			reportProblem("DynamicsPlotterUtil::getElementValue(2) : "
						  "Invalid specifier ["+specifier+"]!");
			return 0;
		}

		bool idValid;
		QString idString = specifierParts.first();
		QString parameter = specifier;
		parameter = parameter.remove(0, idString.size()+1);
		qulonglong id = idString.toULongLong(&idValid);
		if(!idValid) {
			reportProblem("DynamicsPlotterUtil::getElementValue(2) : "
						  "Invalid ID ["+idString+"]!");
			return 0;
		}

		NeuralNetworkElement* networkElement;
		networkElement = NeuralNetwork::selectNetworkElementById(id, networkElements);
		if(networkElement == 0) {
			reportProblem("DynamicsPlotterUtil::getElementValue(2) : "
						  "No element with ID ["+idString+"] "
						  "found in given list!");
			return 0;
		}

		DoubleValue* elementValue;
		elementValue = getElementValue(parameter, networkElement, neuronsWithActivationChange);
		if(elementValue == 0) {
			reportProblem("DynamicsPlotterUtil::getElementValue(2) : "
						  "Could not find specified parameter value at element!");
			return 0;
		}

		return elementValue;
	}
	double DynamicsPlotterUtil::getDistance(const QList<double> &state1, const QList<double> &state2) {
		if(state1.size() != state2.size()) {
			reportProblem("DynamicsPlotterUtil::getDistance : State dimensions do not match.");
			return 0;
		}

		double sum = 0;
		for(int i = 0; i < state1.size(); ++i) {
			sum += pow(state1.at(i)-state2.at(i),2);
		}
		return sqrt(sum);
	}
	QList<double> DynamicsPlotterUtil::getNeuronActivations(NeuralNetwork* network) {
        if(network == 0) {
            reportProblem("DynamicsPlotterUtil::getNeuronActivations : No network");
            return QList<double>();
        }
        QList<double> activations;
        QList<Neuron*> neurons = network->getNeurons();
        for(int n = 0; n < neurons.size(); ++n) {
            activations.append(neurons.at(n)->getLastActivation());
        }
        return activations;
	}
	double DynamicsPlotterUtil::getMeanValue(const QList<DoubleValue*> &valuesList) {
		if(valuesList.isEmpty()) {
			reportProblem("DynamicsPlotterUtil::getMeanValue : Empty list. Nothing to do.");
			return 0;
		}

		int nrValues = valuesList.size();
		double meanValue = 0;

		for(int currVal = 0; currVal < nrValues; ++currVal) {
			DoubleValue* dVal = valuesList.at(currVal);

			if(dVal == 0) {
				reportProblem("DynamicsPlotterUtil::getMeanValue : Encountered NULL element.");
				return 0;
			}

			meanValue += dVal->get();
		}

		return meanValue / nrValues;
	}
	QList<double> DynamicsPlotterUtil::getMeanValues(const QList< QList<DoubleValue*> > &valuesListList) {
		QList<double> meanValues, emptyList;
		emptyList = QList<double>();

		if(valuesListList.isEmpty()) {
			reportProblem("DynamicsPlotterUtil::getMeanValues : Empty list. Nothing to do.");
			return emptyList;
		}

		for(int currList = 0; currList < valuesListList.size(); ++currList) {
			meanValues.append(getMeanValue(valuesListList.at(currList)));
		}

		return meanValues;
	}
	bool DynamicsPlotterUtil::compareNetworkStates(const QList<double>
	&state1, const QList<double> &state2, double accuracy) {
		if(state1.size() != state2.size()) {
			reportProblem("DynamicsPlotterUtil: Cannot compare network states, they "
						"appear to be from different networks");
			return false;
		}

		for(int i = 0; i < state1.size(); ++i) {
			if(!Math::compareDoubles(state1.at(i), state2.at(i), accuracy) ) {
				return false;
			}
		}

		return true;
	}
Exemple #9
0
static int
loadCoreLibrary (JNIEnv *env) {
  if (coreHandle) return 1;

  if ((coreHandle = dlopen("libbrltty_core.so", RTLD_NOW | RTLD_GLOBAL))) {
    const SymbolEntry *symbol = symbolTable;

    while (symbol->name) {
      const void **pointer = symbol->pointer;

      if (!(*pointer = dlsym(coreHandle, symbol->name))) goto error;
      symbol += 1;
    }

    return 1;
  }

error:
  reportProblem(env, "java/lang/UnsatisfiedLinkError", "%s", dlerror());
  return 0;
}
Exemple #10
0
void BasinPlotter::calculateData() {
	
	// get program core
	Core *core = Core::getInstance();
	
	// get network
	ModularNeuralNetwork *network = getCurrentNetwork();
	if(network == 0) {
		Core::log("BasinPlotter: Could not find a neural network to work with! Aborting.", true);
		return;
	}
	
	QList<NeuralNetworkElement*> networkElements;
	network->getNetworkElements(networkElements);
	QList<DoubleValue*> networkValues =
						DynamicsPlotterUtil::getNetworkValues(networkElements);

	// Get parameters for varied elements
	QString variedX = mVariedX->get();
	QString variedY = mVariedY->get();
	if(variedX.isEmpty() || variedY.isEmpty()) {
		reportProblem("BasinPlotter: No elements to vary.");
		return;
	}
	

	DoubleValue *variedValX = DynamicsPlotterUtil::getElementValue(
		variedX, networkElements, &mNeuronsWithActivationsToTransfer);
	DoubleValue *variedValY = DynamicsPlotterUtil::getElementValue(
		variedY, networkElements, &mNeuronsWithActivationsToTransfer);
	
	if(variedValX == 0 || variedValY == 0) {
		reportProblem("BasinPlotter: NULL pointer for varied element. Aborting.");
		return;
	}
	
	QList<double> variedRangeX = 
				DynamicsPlotterUtil::getDoublesFromString(mVariedRangeX->get());
	QList<double> variedRangeY = 
				DynamicsPlotterUtil::getDoublesFromString(mVariedRangeY->get());
				
	if(variedRangeX.size() != 2 || variedRangeY.size() != 2) {
		reportProblem("BasinPlotter: Not a valid range given.");
		return;
	}
		

	int resolutionX = mResolutionX->get();
	int resolutionY = mResolutionY->get();
	
	//avoid division by zero!
	if(resolutionX < 2 || resolutionY < 2) {
		reportProblem("BasinPlotter: Invalid resolution given.");
		return;
	}


	// projected elements
	int nrProjections = 0;
	QString projectionsX = mProjectionsX->get();
	QString projectionsY = mProjectionsY->get();
	QList< QList<DoubleValue*> > projectionValuesX;
	QList< QList<DoubleValue*> > projectionValuesY;
	QList<double> projectionRangesX;
	QList<double> projectionRangesY;

	if(projectionsX != "0" && projectionsY != "0") {

		QList<QStringList> projectionListX = 
				DynamicsPlotterUtil::parseElementString(projectionsX);
		QList<QStringList> projectionListY =
				DynamicsPlotterUtil::parseElementString(projectionsY);

		projectionValuesX =
				DynamicsPlotterUtil::getElementValues(projectionListX, networkElements);
		projectionValuesY =
				DynamicsPlotterUtil::getElementValues(projectionListY, networkElements);

		if(projectionValuesX.isEmpty() || projectionValuesY.isEmpty()) {
			reportProblem("BasinPlotter: Could not find specified elements to project onto.");
			return;
		}

		if(projectionValuesX.size() != projectionValuesY.size()) {
			reportProblem("BasinPlotter: Mismatching number of projected elements for the two axes.");
			return;
		}

		projectionRangesX =
				DynamicsPlotterUtil::getDoublesFromString(mProjectionRangesX->get());
		projectionRangesY =
				DynamicsPlotterUtil::getDoublesFromString(mProjectionRangesY->get());

		if(projectionRangesX.size() != 2*projectionValuesX.size() ||
		   projectionRangesY.size() != 2*projectionValuesY.size()) {
			reportProblem("BasinPlotter: Given ranges for projection don't match number of elements.");
			return;
		}

		nrProjections = projectionValuesX.size();

	}
	

	// save original values for clean-up
	QList<double> variedValuesOrig;
	variedValuesOrig.append(QList<double>() << variedValX->get()
											<< variedValY->get());

	bool resetNetworkActivation = mResetNetworkActivation->get();
	storeCurrentNetworkActivities();
	
	/* store network configuration (bias terms, synapse weights,
			observable parameters of TFs, AFs, SFs. */
	bool restoreNetConfiguration = mRestoreNetworkConfiguration->get();
	storeNetworkConfiguration();
	
	//This is important when the physical simulator is activated!
	bool resetSimulation = mResetSimulator->get();
	triggerReset();
	

	// PREPARE data matrix
	double xStart = variedRangeX.first();
	double xEnd = variedRangeX.last();
	double xStepSize = (xEnd - xStart) / (double) (resolutionX - 1);
	int roundDigits = mRoundDigits->get();
	double xVal;
	QList<double> xValues;
		
	double yStart = variedRangeY.first();
	double yEnd = variedRangeY.last();
	double yStepSize = (yEnd - yStart) / (double) (resolutionY - 1);
	double yVal;
	QList<double> yValues;
	
	{
		//Thread safety of matrix.
		QMutexLocker guard(mDynamicsPlotManager->getMatrixLocker());
		
		mData->clear();
		mData->resize(resolutionX + 1, resolutionY + 1, 3 + nrProjections);
		mData->fill(0);

		// calculate values and draw axes
		for(int x = 1; x <= resolutionX; ++x) {
			xVal = xStart + (x - 1) * xStepSize;
			mData->set(Math::round(xVal, 5), x, 0, 0);
			mData->set(Math::round(xVal, 5), x, 0, 1);
			mData->set(Math::round(xVal, 5), x, 0, 2);
			
			if(roundDigits >= 0) {
				xVal = Math::round(xVal, roundDigits);
			}
			xValues.append(xVal);
		}
		
		for(int y = 1; y <= resolutionY; ++y) {
			yVal = yStart + (y - 1) * yStepSize;
			mData->set(Math::round(yVal, 5), 0, y, 0);
			mData->set(Math::round(yVal, 5), 0, y, 1);
			mData->set(Math::round(yVal, 5), 0, y, 2);
			
			if(roundDigits >= 0) {
				yVal = Math::round(yVal, roundDigits);
			}
			yValues.append(yVal);
		}

		// same for additional projections
		for(int currProj = 0; currProj < nrProjections; ++currProj) {
			double pStartX = projectionRangesX.at(currProj * 2);
			double pEndX = projectionRangesX.at(currProj * 2 + 1);
			double pStepX = (pEndX - pStartX) / (double) (resolutionX - 1);
			for(int x = 1; x <= resolutionX; ++x) {
				mData->set(Math::round((pStartX + (x - 1) * pStepX), 5), x, 0, 3 + currProj);
			}
			double pStartY = projectionRangesY.at(currProj * 2);
			double pEndY = projectionRangesY.at(currProj * 2 + 1);
			double pStepY = (pEndY - pStartY) / (double) (resolutionY - 1);
			for(int y = 1; y <= resolutionY; ++y) {
				mData->set(Math::round((pStartY + (y - 1) * pStepY), 5), 0, y, 3 + currProj);
			}
		}
	}

	// MAIN LOOP over x parameter points
		
	int stepsRun = mStepsToRun->get();
	int stepsCheck = mStepsToCheck->get();
	double accuracy = mAccuracy->get();
	
	QList< QList<double> > attractors;
		
	for(int x = 1; x <= resolutionX && mActiveValue->get(); ++x) {
			
		mProgressPercentage->set((double)(100 * x / resolutionX));

		// INNER LOOP over y parameter points
		for(int y = 1; y <= resolutionY && mActiveValue->get(); ++y) {
			
			if(resetSimulation) {
				triggerReset();
			}
			
			if(restoreNetConfiguration) {
				restoreNetworkConfiguration();
			}
			
			if(resetNetworkActivation) {
				restoreCurrentNetworkActivites();
			}
			
			// set x parameter
			variedValX->set(xValues.at(x - 1));
			// set y parameter
			variedValY->set(yValues.at(y - 1));
			
			if(!notifyNetworkParametersChanged(network)) {
				return;
			}

			for(int runStep = 0; runStep < stepsRun && mActiveValue->get(); ++runStep) {
				// let the network run for 1 timestep
				triggerNetworkStep();
			}
			
			QList< QList<double> > networkStates;
			QList<double> networkState;
			QList< QPair<double,double> > variedPositions;

			QList< QPair< QList<double>, QList<double> > > projectionPositions;

			bool foundMatch = false;
			int attrPeriod = 0;

			for(int checkStep = 0; checkStep <= stepsCheck && !foundMatch && mActiveValue->get(); ++checkStep) {
				triggerNetworkStep();
				
				// get current network state
				networkState = DynamicsPlotterUtil::getNetworkState(networkValues);
				
				// abort on empty state
				if(networkState.isEmpty()) {
					reportProblem("BasinPlotter: Encountered empty network state.");
					return;
				}
				
				// compare states to find attractors
				for(int period = 1; period <= checkStep && !foundMatch; ++period) {
					foundMatch = DynamicsPlotterUtil::compareNetworkStates(
							networkStates.at(checkStep-period),
							networkState,
							accuracy);
					attrPeriod = period;
				}
				
				// save current state as last one
				networkStates.append(networkState);

				variedPositions.append(QPair<double,double>(variedValX->get(), variedValY->get()));

				if(nrProjections > 0) {
					QPair< QList<double>, QList<double> > currentPositions;
					currentPositions.first = DynamicsPlotterUtil::getMeanValues(projectionValuesX);
					currentPositions.second = DynamicsPlotterUtil::getMeanValues(projectionValuesY);
					projectionPositions.append(currentPositions);
				}

			}
			
			// at this point, either an attractor has been found
			if(foundMatch && mActiveValue->get()) {
				
				// check for past attractors
				bool attrMatch = false;
				int attrNo = 1;
				while(attrNo <= attractors.size() && !attrMatch) {
					for(int state = 1; state <= attrPeriod && !attrMatch; ++state) {
						attrMatch = DynamicsPlotterUtil::compareNetworkStates(
								attractors.at(attrNo-1),
								networkStates.at(networkStates.size()-state),
									// was: size()-1-state
								accuracy);
					}
					attrNo++;
				}
				
				
				//Thread safety of matrix.
				QMutexLocker guard(mDynamicsPlotManager->getMatrixLocker());
				
				// write matrix
				mData->set(attrNo, x, y, 0);
				mData->set(attrPeriod, x, y, 1);

				// calculate and plot attractor position
				int nrPositions = variedPositions.size();
				for(int periodPos = 1; periodPos <= attrPeriod; ++periodPos) {
					int currPosition = nrPositions - periodPos;

					double currValX = variedPositions.at(currPosition).first;
					double currValY = variedPositions.at(currPosition).second;
				
					int attrPosX = ceil((currValX - xStart) / xStepSize + 1);
					int attrPosY = ceil((currValY - yStart) / yStepSize + 1);
				
					mData->set(attrNo, attrPosX, attrPosY, 2);

					for(int currProj = 0; currProj < nrProjections; ++currProj) {
						double xVal = projectionPositions.at(currPosition).first.at(currProj);
						double yVal = projectionPositions.at(currPosition).second.at(currProj);

						double pStartX = projectionRangesX.at(currProj * 2);
						double pEndX = projectionRangesX.at(currProj * 2 + 1);
						double pStepX = (pEndX - pStartX) / (double) (resolutionX - 1);
						double pStartY = projectionRangesY.at(currProj * 2);
						double pEndY = projectionRangesY.at(currProj * 2 + 1);
						double pStepY = (pEndY - pStartY) / (double) (resolutionY - 1);
						
						int xPos = floor((xVal - pStartX) / pStepX + 1);
						int yPos = floor((yVal - pStartY) / pStepY + 1);

						mData->set(attrNo, xPos, yPos, 3 + currProj);
					}
				}
				
				if(!attrMatch) {
					attractors.append(networkStates.last());
				}
			}
			
			// or not, but then there's nothing to do :D
			
			// runtime maintencance
			if(core->isShuttingDown()) {
				return;
			}
			core->executePendingTasks();
		}
	}
	
	// CLEAN UP
	variedValX->set(variedValuesOrig.at(0));
	variedValY->set(variedValuesOrig.at(1));
	notifyNetworkParametersChanged(network);

	triggerReset();
	restoreNetworkConfiguration();
	restoreCurrentNetworkActivites();

}
Exemple #11
0
static void
reportOutOfMemory (JNIEnv *env, const char *description) {
  reportProblem(env, "java/lang/OutOfMemoryError", "cannot allocate %s", description);
}
void LyapunovExponent::calculateData() {
	
	// get program core
	Core *core = Core::getInstance();
	
	// get network
	ModularNeuralNetwork *network = getCurrentNetwork();
	QList<NeuralNetworkElement*> networkElements;
	network->getNetworkElements(networkElements);
	QList<DoubleValue*> networkValues =
		DynamicsPlotterUtil::getNetworkValues(networkElements);

	// Get parameters for varied element
	QString variedElement = mVariedElement->get();
	if(variedElement.isEmpty()) {
		reportProblem("LyapunovExponent: No element to vary.");
		return;
	}

	DoubleValue *variedValue = 
			DynamicsPlotterUtil::getElementValue(variedElement, networkElements);
	
	if(variedValue == 0) {
		reportProblem("LyapunovExponent: Invalid value or specifier.");
		return;
	}
	
	QList<double> variedRange = 
				DynamicsPlotterUtil::getDoublesFromString(mVariedRange->get());
				
	if(variedRange.size() != 2) {
		reportProblem("LyapunovExponent: Invalid parameter range.");
		return;
	}

		
	int resolutionX = mResolutionX->get();
	int resolutionY = mResolutionY->get();
	
	//avoid division by zero!
	if(resolutionX < 2 || resolutionY < 2) {
		reportProblem("LyapunovExponent: Invalid resolution given.");
		return;
	}

	
	// Let costraint resolver run properly (order matters!)
	storeNetworkConfiguration();
	storeCurrentNetworkActivities();
	triggerReset();
	restoreCurrentNetworkActivites();
	restoreNetworkConfiguration();
	notifyNetworkParametersChanged(network);

	// save original value
	double originalValue = variedValue->get();

	
	double valStep = (variedRange.at(1) - variedRange.at(0)) / (double) (resolutionX - 1);
	QList<double> variedValues;
	
	// prepare data matrix
	{
		//Thread safety of matrix.
		QMutexLocker guard(mDynamicsPlotManager->getMatrixLocker());

		mData->clear();
		mData->resize(resolutionX + 1, resolutionY + 1, 1);
		mData->fill(0);

		

		for(int x = 1; x <= resolutionX; ++x) {
			double val = variedRange.at(0) + (x-1) * valStep;
			variedValues.append(val);
			
			mData->set(val, x, 0, 0);
		}
	}
	
	int stepsPrePlot = mStepsPrePlot->get();
	int stepsToPlot = mStepsToPlot->get();

	bool drawNL = mDrawNL->get();

	QList<double> ynum;
	double eps = pow(10,-9);
	for(int x = 0; x < variedValues.size(); ++x) {

		// set initial conditions of this run/trajectory
		variedValue->set(variedValues.at(x));
		notifyNetworkParametersChanged(network);
		
		// calculate activation after X PrePlot-Steps
		for(int s = 0; s < stepsPrePlot && mActiveValue->get(); ++s) {
			triggerNetworkStep();
		}
		
		// list for states			
		QList< QList<double> > networkStates;

		for(int s = 0; s < stepsToPlot && mActiveValue->get(); ++s) {

			triggerNetworkStep();
			
			// get current state of the network
			QList<double> networkState = 
					DynamicsPlotterUtil::getNetworkState(networkValues);
			
			// save to list
			networkStates.append(networkState);
		}

		double ljanum = 0;
		int c = 0;
		for(int i = 0; i < networkStates.size() - 1; ++i) {
			double dy = 10000000, df = 100000000;
			bool found = false;

			for(int j = 0; j < networkStates.size() - 1; ++j) {

				double d = DynamicsPlotterUtil::getDistance(
								networkStates.at(i), networkStates.at(j));

				if(d < dy && d > eps) {
					dy = d;
					df = DynamicsPlotterUtil::getDistance(
								networkStates.at(i + 1), networkStates.at(j + 1));
					found = true;
				}
				
			}
			
			if(found && dy != 0 && df != 0) {
				ljanum += log(df / dy);
				c++;
			}

		}

		// save current hightest exponent
		ynum.append(ljanum / c);

		// find smallest and biggest exponent
		double ymin = ynum.first(); double ymax = ynum.first();
		for(int i = 1; i < ynum.size(); ++i) {
			double y = ynum.at(i);
			if(y < ymin) {
				ymin = y;
			}
			if(y > ymax) {
				ymax = y;
			}
		}
		double ystep = (ymax - ymin) / (double)(resolutionY - 1);
		if(ystep == 0) {
			reportProblem("LyapunovExponent: No suitable data found.");
			ymin = 1;
			ymax = 1;
		}

		{
			//Thread safety of matrix.
			QMutexLocker guard(mDynamicsPlotManager->getMatrixLocker());
			
			// clear data matrix
			mData->fill(0);

			// rescale
			for(int y = 1; y <= resolutionY; ++y) {
				double v = ymin + (y-1) * ystep;
				mData->set(Math::round(v, 5), 0, y, 0);
			}
			
			// fill rescaled matrix again
			for(int x = 1; x <= ynum.size(); ++x) {
				double v = min(max(ymin, ynum.at(x - 1)), ymax);
				int y = ceil(((v - ymin) / ystep) + 1);
				mData->set(1, x, y, 0);
			}

			// find null position (if any)
			int ny = ceil(((-ymin)/ystep)+1);
			// and draw red line indicating y=0
			if(drawNL && ny < resolutionY && ny > 0) {
				for(int x = 0; x < resolutionX; ++x) {
					if(mData->get(x, ny, 0) == 0) {
						mData->set(2, x, ny, 0);
					}
				}
			}
		}

		// runtime maintencance
		if(core->isShuttingDown()) {
			return;
		}
		core->executePendingTasks();
	
	}
	
	// re-set original parameter value
	variedValue->set(originalValue);
	// CLEAN UP
	notifyNetworkParametersChanged(network);
	triggerReset();
	restoreNetworkConfiguration();
	restoreCurrentNetworkActivites();

}
	DoubleValue* DynamicsPlotterUtil::getElementValue(QString const &specifier,
													  NeuralNetworkElement* networkElement,
													  QList<Neuron*> *neuronsWithActivationChange)
	{
		QString parameter, variable;
		QStringList nParams, sParams;
		nParams << "o" << "a" << "b" << "tf" << "af";
		sParams << "w" << "sf";

		if(specifier.isEmpty()) {
			reportProblem("DynamicsPlotterUtil::getElementValue(1) : Empty parameter specification");
			return 0;
		}

		if(specifier.contains(":")) {
			QStringList paramParts = specifier.split(":");
			if(paramParts.size() > 2) {
				reportProblem("DynamicsPlotterUtil::getElementValue(1) : Invalid parameter specification");
				return 0;
			}
			parameter = paramParts.first();
			variable = paramParts.last();
		} else {
			parameter = specifier;
		}

		// requested parameter is neuron-specific
		if(nParams.contains(parameter)) {
			Neuron *neuron = dynamic_cast<Neuron*>(networkElement);

			if(neuron != 0) {
				if(parameter == specifier) { // no variable requested

					if(parameter == nParams.at(0)) { // output "o"
						return &(neuron->getOutputActivationValue());
					}

					if(parameter == nParams.at(1)) { // activation "a"
						if(neuronsWithActivationChange != 0) {
							neuronsWithActivationChange->append(neuron);
						}
						return &(neuron->getActivationValue());
					}

					if(parameter == nParams.at(2)) { // bias "b"
						return &(neuron->getBiasValue());
					}

				} else { // variable requested

					if(parameter == nParams.at(3)) { // TransferFunction "tf"
						TransferFunction *tf = neuron->getTransferFunction();
						if(tf != 0) {
							DoubleValue *tfo = dynamic_cast<DoubleValue*>(tf->getObservableOutput(variable));
							if(tfo != 0) {
								return tfo;
							}
							DoubleValue *tfp = dynamic_cast<DoubleValue*>(tf->getParameter(variable));
							if(tfp != 0) {
								return tfp;
							}
						}
					}

					if(parameter == nParams.at(4)) { // ActivationFunction "af"
						ActivationFunction *af = neuron->getActivationFunction();
						if(af != 0) {
							DoubleValue *afo = dynamic_cast<DoubleValue*>(af->getObservableOutput(variable));
							if(afo != 0) {
								return afo;
							}
							DoubleValue *afp = dynamic_cast<DoubleValue*>(af->getParameter(variable));
							if(afp != 0) {
								return afp;
							}
						}
					}
				}

				// requested parameter has not been found, report
				reportProblem("DynamicsPlotterUtil::getElementValue(1) : "
							  "Found neuron ["+QString::number(neuron->getId())+"] "
							  "but not the specified observable or function parameter "
							  "["+specifier+"]");
			}
		}

		// requested parameter is synapse-specific
		if(sParams.contains(parameter)) {
			Synapse *synapse = dynamic_cast<Synapse*>(networkElement);

			if(synapse != 0) {
				if(parameter == specifier) { // no variable requested

					if(parameter == sParams.at(0)) { // weight w
						return &(synapse->getStrengthValue());
					}

				} else { // variable requested

					if(parameter == sParams.at(1)) {
						SynapseFunction *sf = synapse->getSynapseFunction();
						if(sf != 0) {
							DoubleValue *sfo = dynamic_cast<DoubleValue*>(sf->getObservableOutput(variable));
							if(sfo != 0) {
								return sfo;
							}
							DoubleValue *sfp = dynamic_cast<DoubleValue*>(sf->getParameter(variable));
							if(sfp != 0) {
								return sfp;
							}
						}
					}
				}

				// requested parameter has not been found, report
				reportProblem("DynamicsPlotterUtil::getElementValue(1) : "
							  "Found synapse ["+QString::number(synapse->getId())+"] "
							  "but not the specified observable or function parameter "
							  "["+specifier+"]");
			}
		}

		// neuron/synapse or specified parameter not found
		// do not report here, since getElementValues
		// correctly calls this function with non-matching
		// specifier-element pairs
		return 0;
	}
	// returns a list of references to relevant network element values
	QList<DoubleValue*> DynamicsPlotterUtil::getNetworkValues(const
	QList<NeuralNetworkElement*> networkElements) {
		QList<DoubleValue*> list;
		for(int i = 0; i < networkElements.size(); ++i) {
			NeuralNetworkElement *e = networkElements.at(i);

			if(e == 0) {
				reportProblem("DynamicsPlotterUtil::getNetworkState : "
							"NeuralNetworkElement is NULL!");
				return QList<DoubleValue*>();
			}

			Neuron *n = dynamic_cast<Neuron*>(e);
			if(n != 0) {
				DoubleValue *d = &(n->getActivationValue());
				list.append(d);
				DoubleValue *b = &(n->getBiasValue());
				list.append(b);

				ObservableNetworkElement *tf =
				dynamic_cast<ObservableNetworkElement*>(n->getTransferFunction());
				if(tf != 0) {
					QList<Value*> tfVals = tf->getObservableOutputs();
					for(int j = 0; j < tfVals.size(); ++j) {
						DoubleValue *v = dynamic_cast<DoubleValue*>(tfVals.at(j));
						if(v != 0) {
							list.append(v);
						}
					}
				}

				ObservableNetworkElement *af =
				dynamic_cast<ObservableNetworkElement*>(n->getActivationFunction());
				if(af != 0) {
					QList<Value*> afVals = af->getObservableOutputs();
					for(int j = 0; j < afVals.size(); ++j) {
						DoubleValue *v = dynamic_cast<DoubleValue*>(afVals.at(j));
						if(v != 0) {
							list.append(v);
						}
					}
				}
			}

			Synapse *s = dynamic_cast<Synapse*>(e);
			if(s != 0) {
				DoubleValue *d = &(s->getStrengthValue());
				list.append(d);

				ObservableNetworkElement *sf =
				dynamic_cast<ObservableNetworkElement*>(s->getSynapseFunction());
				if(sf != 0) {
					QList<Value*> sfVals = sf->getObservableOutputs();
					for(int j = 0; j < sfVals.size(); ++j) {
						DoubleValue *v = dynamic_cast<DoubleValue*>(sfVals.at(j));
						if(v != 0) {
							list.append(v);
						}
					}
				}
			}
		}
		return list;
	}
	/**
	 *
	 * The neuronsWithActivationChange parameter can be used to collect all DoubelValues that correspond
	 * to activation values of neurons. These neurons have to be collected in each DymnamcisPlotter in
	 * variable DynamcisPlotter::mNeuronsWithActivationsToTransfer to be handled correctly, if the
	 * activation of a neuron should be varied during an analyzer run. Otherwise the varied activations
	 * are immediately overwritten by the newly calculated activations at the first network update.
	 *
	 * If this method is used to collect elements that will NOT be changed during analyzer runs,
	 * then the last parameter MUST be empty. Othewise activations of neurons collected in this way
	 * will be treated differently compared to the other neurons in the network. This may lead to
	 * unexpected and erroneous behavior.
	 *
	 * @param specifierLists a list of stringlists, containing the single specifications of DoubleValues.
	 * @param networkElements the list of objects that are considered to find the specified DoubleValue object.
	 * @param neuronsWithActivationChange (optional) list to collect all activation values that are going to be changed during a run.
	 */
	QList< QList<DoubleValue*> > DynamicsPlotterUtil::getElementValues(QList<QStringList> const &specifierLists,
																	   QList<NeuralNetworkElement*> const &networkElements,
																	   QList<Neuron*> *neuronsWithActivationChange)
	{
		QList< QList<DoubleValue*> > plotElements, emptyList;
		emptyList = QList< QList<DoubleValue*> >();

		for(int listNr = 0; listNr < specifierLists.size(); ++listNr) {
			QList<DoubleValue*> elementValues;

			QStringList specifierList = specifierLists.at(listNr);
			for(int specifierNr = 0; specifierNr < specifierList.size(); ++specifierNr) {

				QString specifier = specifierList.at(specifierNr);
				if(specifier.isEmpty()) {
					reportProblem("DynamicsPlotterUtil::getElementValues : Empty specifier!");
					return emptyList;
				}

				QStringList parameters = specifier.split(":");
				if(parameters.size() < 2 || parameters.size() > 3) {
					reportProblem("DynamicsPlotterUtil::getElementValues : Invalid specifier ["+specifier+"]!");
					return emptyList;
				}

				if(parameters.first() == "all") {
					QList<DoubleValue*> netValues;
					DoubleValue* elementValue;
					QString parameter = specifier.remove("all:");

					for(int elemNr = 0; elemNr < networkElements.size(); ++elemNr) {
						NeuralNetworkElement* networkElement = networkElements.at(elemNr);
						elementValue = getElementValue(parameter, networkElement, neuronsWithActivationChange);

						if(elementValue != 0) {
							netValues.append(elementValue);
						}
					}

					elementValues.append(netValues);

				} else {
					DoubleValue* elementValue;
					elementValue = getElementValue(specifier, networkElements, neuronsWithActivationChange);

					if(elementValue == 0) {
						reportProblem("DynamicsPlotterUtil::getElementValues : Could not find a value "
									  "for element specifier ["+specifier+"]!");
						return emptyList;
					}

					elementValues.append(elementValue);

				}
			}

			plotElements.append(elementValues);
		}

		return plotElements;
	}