Commit be5a4da7 authored by Rafael Laboissière's avatar Rafael Laboissière
Browse files

New upstream version 6.1.08

parent a6b7f00d
Loading
Loading
Loading
Loading
+45 −48
Original line number Diff line number Diff line
@@ -86,10 +86,9 @@ autoEEG EEG_create (double tmin, double tmax) {
}

integer EEG_getChannelNumber (EEG me, conststring32 channelName) {
	for (integer ichan = 1; ichan <= my numberOfChannels; ichan ++) {
	for (integer ichan = 1; ichan <= my numberOfChannels; ichan ++)
		if (Melder_equ (my channelNames [ichan].get(), channelName))
			return ichan;
	}
	return 0;
}

@@ -99,7 +98,7 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
		char buffer [81];
		fread (buffer, 1, 8, f);
		buffer [8] = '\0';
		bool is24bit = buffer [0] == (char) 255;
		const bool is24bit = ( buffer [0] == (char) 255 );
		fread (buffer, 1, 80, f);
		buffer [80] = '\0';
		trace (U"Local subject identification: \"", Melder_peek8to32 (buffer), U"\"");
@@ -114,27 +113,27 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
		trace (U"Start time of recording: \"", Melder_peek8to32 (buffer), U"\"");
		fread (buffer, 1, 8, f);
		buffer [8] = '\0';
		integer numberOfBytesInHeaderRecord = atol (buffer);
		const integer numberOfBytesInHeaderRecord = atol (buffer);
		trace (U"Number of bytes in header record: ", numberOfBytesInHeaderRecord);
		fread (buffer, 1, 44, f);
		buffer [44] = '\0';
		trace (U"Version of data format: \"", Melder_peek8to32 (buffer), U"\"");
		fread (buffer, 1, 8, f);
		buffer [8] = '\0';
		integer numberOfDataRecords = strtol (buffer, nullptr, 10);
		const integer numberOfDataRecords = strtol (buffer, nullptr, 10);
		trace (U"Number of data records: ", numberOfDataRecords);
		fread (buffer, 1, 8, f);
		buffer [8] = '\0';
		double durationOfDataRecord = atof (buffer);
		const double durationOfDataRecord = atof (buffer);
		trace (U"Duration of a data record: ", durationOfDataRecord);
		fread (buffer, 1, 4, f);
		buffer [4] = '\0';
		integer numberOfChannels = atol (buffer);
		const integer numberOfChannels = atol (buffer);
		trace (U"Number of channels in data record: ", numberOfChannels);
		if (numberOfBytesInHeaderRecord != (numberOfChannels + 1) * 256)
			Melder_throw (U"Number of bytes in header record (", numberOfBytesInHeaderRecord,
				U") doesn't match number of channels (", numberOfChannels, U").");
		autostring32vector channelNames (numberOfChannels);
		autoSTRVEC channelNames (numberOfChannels);
		for (integer ichannel = 1; ichannel <= numberOfChannels; ichannel ++) {
			fread (buffer, 1, 16, f);
			buffer [16] = '\0';   // labels of the channels
@@ -142,16 +141,15 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
			 * Strip all final spaces.
			 */
			for (int i = 15; i >= 0; i --) {
				if (buffer [i] == ' ') {
				if (buffer [i] == ' ')
					buffer [i] = '\0';
				} else {
				else
					break;
			}
			}
			channelNames [ichannel] = Melder_8to32 (buffer);
			trace (U"Channel <<", channelNames [ichannel].get(), U">>");
		}
		bool hasLetters = str32equ (channelNames [numberOfChannels].get(), U"EDF Annotations");
		const bool hasLetters = str32equ (channelNames [numberOfChannels].get(), U"EDF Annotations");
		double samplingFrequency = undefined;
		for (integer channel = 1; channel <= numberOfChannels; channel ++) {
			fread (buffer, 1, 80, f);
@@ -193,7 +191,7 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
		for (integer channel = 1; channel <= numberOfChannels; channel ++) {
			fread (buffer, 1, 8, f);
			buffer [8] = '\0';   // number of samples in each data record
			integer numberOfSamplesInThisDataRecord = atol (buffer);
			const integer numberOfSamplesInThisDataRecord = atol (buffer);
			if (isundef (samplingFrequency)) {
				numberOfSamplesPerDataRecord = numberOfSamplesInThisDataRecord;
				samplingFrequency = numberOfSamplesInThisDataRecord / durationOfDataRecord;
@@ -207,36 +205,37 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
			fread (buffer, 1, 32, f);
			buffer [32] = '\0';   // reserved
		}
		double duration = numberOfDataRecords * durationOfDataRecord;
		const double duration = numberOfDataRecords * durationOfDataRecord;
		autoEEG him = EEG_create (0, duration);
		his numberOfChannels = numberOfChannels;
		autoSound me = Sound_createSimple (numberOfChannels, duration, samplingFrequency);
		Melder_assert (my nx == numberOfSamplesPerDataRecord * numberOfDataRecords);
		autoNUMvector <uint8> dataBuffer ((integer) 0, 3 * numberOfSamplesPerDataRecord - 1);
		autoBYTEVEC dataBuffer = newBYTEVECzero (3 * numberOfSamplesPerDataRecord);
		for (integer record = 1; record <= numberOfDataRecords; record ++) {
			for (integer channel = 1; channel <= numberOfChannels; channel ++) {
				double factor = channel == numberOfChannels ? 1.0 : physicalMinimum [channel] / digitalMinimum [channel];
				if (channel < numberOfChannels - EEG_getNumberOfExtraSensors (him.get())) factor /= 1000000.0;
				double factor = ( channel == numberOfChannels ? 1.0 : physicalMinimum [channel] / digitalMinimum [channel] );
				if (channel < numberOfChannels - EEG_getNumberOfExtraSensors (him.get()))
					factor /= 1000000.0;
				if (is24bit) {
					fread (& dataBuffer [0], 3, (size_t) numberOfSamplesPerDataRecord, f);
					uint8 *p = & dataBuffer [0];
					fread (dataBuffer.asArgumentToFunctionThatExpectsZeroBasedArray(), 3, (size_t) numberOfSamplesPerDataRecord, f);
					byte *p = & dataBuffer [1];
					for (integer i = 1; i <= numberOfSamplesPerDataRecord; i ++) {
						integer sample = i + (record - 1) * numberOfSamplesPerDataRecord;
						const integer sample = i + (record - 1) * numberOfSamplesPerDataRecord;
						Melder_assert (sample <= my nx);
						uint8 lowByte = *p ++, midByte = *p ++, highByte = *p ++;
						const uint8 lowByte = *p ++, midByte = *p ++, highByte = *p ++;
						uint32 externalValue = ((uint32) highByte << 16) | ((uint32) midByte << 8) | (uint32) lowByte;
						if ((highByte & 128) != 0)   // is the 24-bit sign bit on?
							externalValue |= 0xFF00'0000;   // extend negative sign to 32 bits
						my z [channel] [sample] = (int32) externalValue * factor;
					}
				} else {
					fread (& dataBuffer [0], 2, (size_t) numberOfSamplesPerDataRecord, f);
					uint8 *p = & dataBuffer [0];
					fread (dataBuffer.asArgumentToFunctionThatExpectsZeroBasedArray(), 2, (size_t) numberOfSamplesPerDataRecord, f);
					byte *p = & dataBuffer [1];
					for (integer i = 1; i <= numberOfSamplesPerDataRecord; i ++) {
						integer sample = i + (record - 1) * numberOfSamplesPerDataRecord;
						const integer sample = i + (record - 1) * numberOfSamplesPerDataRecord;
						Melder_assert (sample <= my nx);
						uint8 lowByte = *p ++, highByte = *p ++;
						uint16 externalValue = (uint16) ((uint16) highByte << 8) | (uint16) lowByte;
						const uint8 lowByte = *p ++, highByte = *p ++;
						const uint16 externalValue = (uint16) ((uint16) highByte << 8) | (uint16) lowByte;
						my z [channel] [sample] = (int16) externalValue * factor;
					}
				}
@@ -244,21 +243,20 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
		}
		int numberOfStatusBits = 8;
		for (integer i = 1; i <= my nx; i ++) {
			uint32 value = (uint32) (int32) my z [numberOfChannels] [i];
			if (value & 0x0000'FF00) {
			const uint32 value = (uint32) (int32) my z [numberOfChannels] [i];
			if (value & 0x0000'FF00)
				numberOfStatusBits = 16;
		}
		}
		autoTextGrid thee;
		if (hasLetters) {
			thee = TextGrid_create (0, duration, U"Mark Trigger", U"Mark Trigger");
			autoMelderString letters;
			double time = undefined;
			for (integer i = 1; i <= my nx; i ++) {
				uint32 value = (uint32) (int32) my z [numberOfChannels] [i];
				const uint32 value = (uint32) (int32) my z [numberOfChannels] [i];
				for (int ibyte = 1; ibyte <= numberOfStatusBits / 8; ibyte ++) {
					uint32 mask = ( ibyte == 1 ? 0x0000'00ff : 0x0000'ff00 );
					char32 kar = ( ibyte == 1 ? (value & mask) : (value & mask) >> 8 );
					const uint32 mask = ( ibyte == 1 ? 0x0000'00ff : 0x0000'ff00 );
					const char32 kar = ( ibyte == 1 ? (value & mask) : (value & mask) >> 8 );
					if (kar != U'\0' && kar != 20) {
						MelderString_appendCharacter (& letters, kar);
					} else if (letters. string [0] != U'\0') {
@@ -307,13 +305,13 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
				U""
			);
			for (int bit = 1; bit <= numberOfStatusBits; bit ++) {
				uint32 bitValue = 1 << (bit - 1);
				const uint32 bitValue = 1 << (bit - 1);
				IntervalTier tier = (IntervalTier) thy tiers->at [bit];
				for (integer i = 1; i <= my nx; i ++) {
					uint32 previousValue = i == 1 ? 0 : (uint32) (int32) my z [numberOfChannels] [i - 1];
					uint32 thisValue = (uint32) (int32) my z [numberOfChannels] [i];
					const uint32 previousValue = ( i == 1 ? 0 : (uint32) (int32) my z [numberOfChannels] [i - 1] );
					const uint32 thisValue = (uint32) (int32) my z [numberOfChannels] [i];
					if ((thisValue & bitValue) != (previousValue & bitValue)) {
						double time = i == 1 ? 0.0 : my x1 + (i - 1.5) * my dx;
						const double time = ( i == 1 ? 0.0 : my x1 + (i - 1.5) * my dx );
						if (time != 0.0)
							TextGrid_insertBoundary (thee.get(), bit, time);
						if ((thisValue & bitValue) != 0)
@@ -432,7 +430,7 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
}

static void detrend (VEC const& channel) {
	double firstValue = channel [1], lastValue = channel [channel.size];
	const double firstValue = channel [1], lastValue = channel [channel.size];
	channel [1] = channel [channel.size] = 0.0;
	for (integer isamp = 2; isamp < channel.size; isamp ++)
		channel [isamp] -= ((isamp - 1.0) * lastValue + (channel.size - isamp) * firstValue) / (channel.size - 1);
@@ -529,7 +527,7 @@ void EEG_setChannelToZero (EEG me, integer channelNumber) {

void EEG_setChannelToZero (EEG me, conststring32 channelName) {
	try {
		integer channelNumber = EEG_getChannelNumber (me, channelName);
		const integer channelNumber = EEG_getChannelNumber (me, channelName);
		if (channelNumber == 0)
			Melder_throw (U"No channel named \"", channelName, U"\".");
		EEG_setChannelToZero (me, channelNumber);
@@ -554,7 +552,7 @@ autoEEG EEG_extractChannel (EEG me, integer channelNumber) {
			Melder_throw (U"No channel ", channelNumber, U".");
		autoEEG thee = EEG_create (my xmin, my xmax);
		thy numberOfChannels = 1;
		thy channelNames = autostring32vector (1);
		thy channelNames = autoSTRVEC (1);
		thy channelNames [1] = Melder_dup (my channelNames [1].get());
		thy sound = Sound_extractChannel (my sound.get(), channelNumber);
		thy textgrid = Data_copy (my textgrid.get());
@@ -566,7 +564,7 @@ autoEEG EEG_extractChannel (EEG me, integer channelNumber) {

autoEEG EEG_extractChannel (EEG me, conststring32 channelName) {
	try {
		integer channelNumber = EEG_getChannelNumber (me, channelName);
		const integer channelNumber = EEG_getChannelNumber (me, channelName);
		if (channelNumber == 0)
			Melder_throw (U"No channel named \"", channelName, U"\".");
		return EEG_extractChannel (me, channelNumber);
@@ -577,15 +575,15 @@ autoEEG EEG_extractChannel (EEG me, conststring32 channelName) {

autoEEG EEG_extractChannels (EEG me, constVECVU const& channelNumbers) {
	try {
		integer numberOfChannels = channelNumbers.size;
		const integer numberOfChannels = channelNumbers.size;
		Melder_require (numberOfChannels > 0,
			U"The number of channels should be greater than 0.");
		autoEEG you = EEG_create (my xmin, my xmax);
		your sound = Sound_extractChannels (my sound.get(), channelNumbers);
		your numberOfChannels = numberOfChannels;
		your channelNames = autostring32vector (numberOfChannels);
		your channelNames = autoSTRVEC (numberOfChannels);
		for (integer ichan = 1; ichan <= numberOfChannels; ichan ++) {
			integer originalChannelNumber = Melder_iround (channelNumbers [ichan]);
			const integer originalChannelNumber = Melder_iround (channelNumbers [ichan]);
			your channelNames [ichan] = Melder_dup (my channelNames [originalChannelNumber].get());
		}
		your textgrid = Data_copy (my textgrid.get());
@@ -614,9 +612,8 @@ void EEG_removeChannel (EEG me, integer channelNumber) {
	try {
		if (channelNumber < 1 || channelNumber > my numberOfChannels)
			Melder_throw (U"No channel ", channelNumber, U".");
		for (integer ichan = channelNumber; ichan < my numberOfChannels; ichan ++) {
		for (integer ichan = channelNumber; ichan < my numberOfChannels; ichan ++)
			my channelNames [ichan] = my channelNames [ichan + 1].move();
		}
		my channelNames [my numberOfChannels]. reset();
		my numberOfChannels -= 1;
		Sound_removeChannel (my sound.get(), channelNumber);
@@ -627,7 +624,7 @@ void EEG_removeChannel (EEG me, integer channelNumber) {

void EEG_removeChannel (EEG me, conststring32 channelName) {
	try {
		integer channelNumber = EEG_getChannelNumber (me, channelName);
		const integer channelNumber = EEG_getChannelNumber (me, channelName);
		if (channelNumber == 0)
			Melder_throw (U"No channel named \"", channelName, U"\".");
		EEG_removeChannel (me, channelNumber);
@@ -641,8 +638,8 @@ autoEEG EEGs_concatenate (OrderedOf<structEEG>* me) {
		if (my size < 1)
			Melder_throw (U"Cannot concatenate zero EEG objects.");
		EEG first = my at [1];
		integer numberOfChannels = first -> numberOfChannels;
		autostring32vector channelNames = newSTRVECcopy (first -> channelNames.get());
		const integer numberOfChannels = first -> numberOfChannels;
		autoSTRVEC channelNames = newSTRVECcopy (first -> channelNames.get());
		for (integer ieeg = 2; ieeg <= my size; ieeg ++) {
			EEG other = my at [ieeg];
			if (other -> numberOfChannels != numberOfChannels)
+35 −24
Original line number Diff line number Diff line
@@ -77,7 +77,8 @@ autostring32 FFNet_createNameFromTopology (FFNet me) {

static double sigmoid (FFNet /*me*/, double x, double *out_deriv) {
	const double act = NUMsigmoid (x);
	if (out_deriv) *out_deriv = act * (1.0 - act);
	if (out_deriv)
		*out_deriv = act * (1.0 - act);
	return act;
}

@@ -111,7 +112,6 @@ static double minimumCrossEntropy (FFNet me, constVEC& target) {
	for (integer i = 1; i <= my numberOfOutputs; i ++, k ++) {
		const double t1 = 1.0 - target [i];
		const double o1 = 1.0 - my activity [k];

		cost -= target [i] * log (my activity [k]) + t1 * log (o1);
		my error [k] = -t1 / o1 + target [i] / my activity [k];
	}
@@ -134,8 +134,9 @@ static void bookkeeping (FFNet me) {
		U"Number of weights is incorrect.");

	my numberOfWeights = numberOfWeights;

	// The following test is essential because when an FFNet is read from file the w array already exists
	/*
		The following test is essential because when an FFNet is read from file the w array already exists
	*/
	if (! my w.at)
		my w = newVECzero (my numberOfWeights);

@@ -257,7 +258,8 @@ void FFNet_setCostFunction (FFNet me, int costType) {
double FFNet_getBias (FFNet me, integer layer, integer unit) {
	try {
		const integer node = FFNet_getNodeNumberFromUnitNumber (me, unit, layer);
		Melder_require (node > 0, U"Not a valid unit / layer combination.");
		Melder_require (node > 0,
			U"Not a valid unit / layer combination.");
		const integer bias_unit = my wLast [node];
		return my w [bias_unit];
	} catch (MelderError) {
@@ -312,7 +314,7 @@ void FFNet_reset (FFNet me, double weightRange) {
conststring32 FFNet_getCategoryOfOutputUnit (FFNet me, integer outputUnit) {
	conststring32 result = U"-- undefined --";
	if (my outputCategories && outputUnit <= my outputCategories -> size) {
		SimpleString ss = my outputCategories->at [outputUnit];
		const SimpleString ss = my outputCategories->at [outputUnit];
		result = ss -> string.get();
	}
	return result;
@@ -322,7 +324,7 @@ integer FFNet_getOutputUnitOfCategory (FFNet me, const char32* category) {
	integer result = 0;
	if (my outputCategories) {
		for (integer i = 1; i <= my outputCategories -> size; i ++) {
			SimpleString s = my outputCategories->at [i];
			const SimpleString s = my outputCategories->at [i];
			if (Melder_equ (s -> string.get(), category)) {
				result = i;
				break;
@@ -336,11 +338,15 @@ integer FFNet_getOutputUnitOfCategory (FFNet me, const char32* category) {
/* step 1 */
void FFNet_propagate (FFNet me, constVEC input, autoVEC *output) {
	Melder_assert (my numberOfInputs == input.size);
	// clamp input pattern on the network
	/*
		Clamp input pattern on the network
	*/
	my activity.part (1, my numberOfInputs) <<= input;

	// on hidden units use activation function
	integer k = 1, numberOfNodes = my outputsAreLinear ? my numberOfNodes - my numberOfOutputs : my numberOfNodes;
	/*
		On hidden units use activation function
	*/
	const integer numberOfNodes = my outputsAreLinear ? my numberOfNodes - my numberOfOutputs : my numberOfNodes;
	integer k = 1;
	for (integer i = my numberOfInputs + 2; i <= numberOfNodes; i ++) {
		if (my isbias [i])
			continue;
@@ -350,7 +356,9 @@ void FFNet_propagate (FFNet me, constVEC input, autoVEC *output) {

		my activity [i] = my nonLinearity (me, act, & my deriv [i]);
	}
	// on output units use another activation function
	/*
		On output units use another activation function
	*/
	if (my outputsAreLinear) {
		for (integer i = numberOfNodes + 1; i <= my numberOfNodes; i ++) {
			if (my isbias [i])
@@ -373,12 +381,15 @@ void FFNet_propagate (FFNet me, constVEC input, autoVEC *output) {

double FFNet_computeError (FFNet me, constVEC target) {
	Melder_assert (my numberOfOutputs == target.size);
	// compute error at output layer
	/*
		Compute error at output layer
	*/
	const double cost = my costFunction (me, target);
	for (integer i = 1; i <= my numberOfNodes - my numberOfOutputs; i ++)
		my error [i] = 0.0;

	// backpropagation of errors from output to first hidden layer
	/*
		Backpropagation of errors from output to first hidden layer
	*/
	for (integer i = my numberOfNodes; i > my numberOfInputs + 1; i--) {
		if (my isbias [i])
			continue;
@@ -395,12 +406,11 @@ double FFNet_computeError (FFNet me, constVEC target) {

void FFNet_computeDerivative (FFNet me) {
	integer k = 1;
	for (integer i = my numberOfInputs + 2; i <= my numberOfNodes; i ++) {
	for (integer i = my numberOfInputs + 2; i <= my numberOfNodes; i ++)
		if (! my isbias [i])
			for (integer node = my nodeFirst [i]; node <= my nodeLast [i]; node ++, k ++)
				my dwi [k] = - my error [i] * my activity [node];
}
}

/******* end operation ******************************************************/

@@ -413,10 +423,9 @@ integer FFNet_getWinningUnit (FFNet me, integer labeling) {
			sum += my activity [k + ioutput];

		const double random = NUMrandomUniform (0.0, sum);
		for (winningUnit = my numberOfOutputs; winningUnit >= 2; winningUnit--) {
		for (winningUnit = my numberOfOutputs; winningUnit >= 2; winningUnit--)
			if (random > (sum -= my activity [k + winningUnit]))
				break;
		}
	} else { /* winner-takes-all */
		double max = my activity [k + 1];
		for (integer ioutput = 2; ioutput <= my numberOfOutputs; ioutput ++)
@@ -546,7 +555,9 @@ void FFNet_drawTopology (FFNet me, Graphics g) {
		const double y2WC = dy / 2 + layer * dy;
		double dx2 = dx, x2WC;
		double x2 = (maxNumOfUnits - numberOfUnitsInLayer + 1) * dx2 / 2;
		/* draw the units */
		/*
			Draw the units
		*/
		if (! dxIsFixed) {
			dx2 = 1.0 / numberOfUnitsInLayer;
			x2 = dx2 / 2.0;
@@ -629,8 +640,8 @@ void FFNet_drawActivation (FFNet me, Graphics g) {
		}
		x2WC = x2;
		for (integer iunit = 1; iunit <= numberOfUnitsInLayer; iunit ++, node ++) {
			double activity = my activity [node];
			double radius = r1 * (fabs (activity) < 0.05 ? 0.05 : fabs (activity));
			const double activity = my activity [node];
			const double radius = r1 * (fabs (activity) < 0.05 ? 0.05 : fabs (activity));
			/*Graphics_setColour (g, activity < 0 ? Melder_BLACK : Melder_RED);*/
			Graphics_circle (g, x2WC, y2WC, radius);
			if (activity < 0)
+7 −8
Original line number Diff line number Diff line
@@ -28,10 +28,9 @@
static integer winnerTakesAll (FFNet me, constVEC activation) {
	integer pos = 1;
	double max = activation[1];
	for (integer i = 2; i <= my numberOfOutputs; i ++) {
	for (integer i = 2; i <= my numberOfOutputs; i ++)
		if (activation [i] > max)
			max = activation [pos = i];
	}
	return pos;
}

@@ -43,7 +42,8 @@ static integer stochastic (FFNet me, constVEC activation) {
	const double number = NUMrandomUniform (0.0, range);
	for (i = 1; i <= my numberOfOutputs; i ++) {
		lower += activation [i];
		if (number < lower) break;
		if (number < lower)
			break;
	}
	return i;
}
@@ -74,17 +74,16 @@ autoActivationList FFNet_Categories_to_ActivationList (FFNet me, Categories thee
		autoCategories uniq = Categories_selectUniqueItems (thee);
		Melder_require (my outputCategories,
			U"The FFNet does not have categories.");
		
		const integer nl = OrderedOfString_isSubsetOf (uniq.get(), my outputCategories.get(), 0);
		Melder_require (nl > 0,
			U"The Categories should match the categories of the FFNet.");

		autoActivationList him = ActivationList_create (thy size, my numberOfOutputs);
		for (integer i = 1; i <= thy size; i ++) {
			SimpleString category = thy at [i];
			const SimpleString category = thy at [i];
			const integer pos = OrderedOfString_indexOfItem_c (my outputCategories.get(), category -> string.get());
			if (pos < 1)
				Melder_throw (U"The FFNet doesn't know the category ", category -> string.get(), U".");
			Melder_require (pos > 0,
				U"The FFNet doesn't know the category ", category -> string.get(), U".");
			his z [i] [pos] = 1.0;
		}
		return him;
+6 −10
Original line number Diff line number Diff line
@@ -50,28 +50,26 @@ void FFNet_Eigen_drawIntersection (FFNet me, Eigen eigen, Graphics g, integer pc
	Graphics_setWindow (g, xmin, xmax, ymin, ymax);
	for (integer i = 1; i <= my numberOfUnitsInLayer [1]; i ++) {
		const integer unitOffset = my numberOfInputs + 1;
		const double bias = my w [my wLast [unitOffset + i]];
		double c1 = 0.0, c2 = 0.0;
		double x [6], y [6], xs [3], ys [3];
		integer ns = 0;
		for (integer j = 1; j <= my numberOfInputs; j ++) {
			c1 += my w [my wFirst [unitOffset + i] + j - 1] * eigen -> eigenvectors [ix] [j];
			c2 += my w [my wFirst [unitOffset + i] + j - 1] * eigen -> eigenvectors [iy] [j];
		}
		double x [6], y [6], xs [3], ys [3];
		x [1] = x [2] = x [5] = xmin;
		x [3] = x [4] = xmax;
		y [1] = y [4] = y [5] = ymin;
		y [2] = y [3] = ymax;
		integer ns = 0;
		const double bias = my w [my wLast [unitOffset + i]];
		for (integer j = 1; j <= 4; j++) {
			const double p1 = c1 * x [j] + c2 * y [j] + bias;
			const double p2 = c1 * x [j + 1] + c2 * y [j + 1] + bias;
			const double r = fabs (p1) / (fabs (p1) + fabs (p2));
			if (p1 *p2 > 0 || r == 0.0) 
				continue;

			if (++ ns > 2)
				break;

			xs [ns] = x [j] + (x [j + 1] - x [j]) * r;
			ys [ns] = y [j] + (y [j + 1] - y [j]) * r;
		}
@@ -88,8 +86,7 @@ void FFNet_Eigen_drawIntersection (FFNet me, Eigen eigen, Graphics g, integer pc
	from layer j with the plane spanned by eigenvectors pcx and pcy.
*/
void FFNet_Eigen_drawDecisionPlaneInEigenspace (FFNet me, Eigen thee, Graphics g, integer unit, integer layer,
	integer pcx, integer pcy, double xmin, double xmax, double ymin, double ymax)
{
	integer pcx, integer pcy, double xmin, double xmax, double ymin, double ymax) {
	if (layer < 1 || layer > my numberOfLayers)
		return;
	if (unit < 1 || unit > my numberOfUnitsInLayer [layer])
@@ -100,7 +97,6 @@ void FFNet_Eigen_drawDecisionPlaneInEigenspace (FFNet me, Eigen thee, Graphics g
	if (numberOfUnitsInLayer_m1 != thy dimension)
		return;


	double x1, x2, y1, y2;
	Graphics_inqWindow (g, & x1, & x2, & y1, & y2);
	if (xmax <= xmin) {
@@ -169,7 +165,7 @@ void FFNet_Eigen_drawDecisionPlaneInEigenspace (FFNet me, Eigen thee, Graphics g
		    "for unit ", unit, U" in layer ", layer, U" with the plane spanned by the eigenvectors because \nboth planes are parallel.");
		return;
	}
	double xi [3], yi [3]; /* Intersections */
	double xi [3], yi [3]; // Intersections
	const double ni = NUMgetIntersectionsWithRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, xi, yi);
	if (ni == 2)
		Graphics_line (g, xi [1], yi [1], xi [2], yi [2]);
+28 −26

File changed.

Preview size limit exceeded, changes collapsed.

Loading