Categories FFNet_Activation_to_Categories (FFNet me, Activation activation, int labeling)
{
	Categories thee = NULL, categories = my outputCategories;
	long i, (*labelingFunction) (I, const double act[]);
	
	if (! my outputCategories)
	{
		(void) Melder_error1 (L"FFNet & Activation: To Categories\n");
		return Melder_errorp1 (L"The neural net has no Categories (has the FFNet been trained yet?).");
	}
	if (my nOutputs != activation->nx)
	{
		(void) Melder_error1 (L"FFNet & Activation: To Categories\n");
		return Melder_errorp1 (L"The number of columns in the Activation must equal the number of outputs of FFNet.");
	}
	thee = Categories_create ();
	if (thee == NULL) return NULL;
	labelingFunction = labeling == 2 ? stochastic : winnerTakesAll;
	for (i = 1; i <= activation->ny; i++)
	{
		long index = labelingFunction (me, activation->z[i]);
		Data item = Data_copy (categories->item[index]);
		if (item == NULL || ! Collection_addItem (thee, item)) 
		{
			forget (thee);
			return Melder_errorp3 (L"FFNet & Activation: To Categories\n\nError creating label ",
				Melder_integer (i), L".");
		}
	}
	return thee;
}
autoCategories FFNet_Activation_to_Categories (FFNet me, Activation activation, int labeling) {
	try {
		long (*labelingFunction) (FFNet me, const double act[]);

		if (! my outputCategories) {
			Melder_throw (U"No Categories (has the FFNet been trained yet?).");
		}
		if (my nOutputs != activation -> nx) {
			Melder_throw (U"Number of columns and number of outputs must be equal.");
		}
		autoCategories thee = Categories_create ();
		labelingFunction = labeling == 2 ? stochastic : winnerTakesAll;
		for (long i = 1; i <= activation->ny; i++) {
			long index = labelingFunction (me, activation -> z[i]);
			autoSimpleString item = Data_copy (my outputCategories->at [index]);
			thy addItem_move (item.move());
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": no Categories created.");
	}
}