ValueTree vs Arrays. Code is giving different behavior


#1

Sorry for all the code I posted below this, but I figured I’d show everything in case it helps.

Basically, I made a Markov Chain using Arrays and OwnedArrays. I then realized I needed to expand the functionality, and so I switched to ValueTrees instead of the Arrays (To avoid structures like OwnedArray< OwnedArray< Array>>).

To make sure everything was still working properly, I tested the outputs of the two Markov chains assuming they should behave very similarly. However, the ValueTree version seems to be much more “noisy” than the Array version (the predicated values jump around a lot more in the ValueTree version)? I can’t seem to find any major difference that would lead to this.

Any thoughts?

*****************************Using Arrays/OwnedArrays

BasicMarkovUsingArrays.h

[code]#ifndef BASICMARKOVUSINGARRAYS_H_291C032F
#define BASICMARKOVUSINGARRAYS_H_291C032F

#include “…/…/JuceLibraryCode/JuceHeader.h”

class BasicMarkovUsingArrays
{
public:
BasicMarkovUsingArrays ();
~BasicMarkovUsingArrays ();

	void learnFromEvent					(int eventValue);
	
	// guess the output for a given input
	int calculateOutput					(int input);
	
private:
	
	struct EventData
	{
		int inputValue;
		int outputValue;
	};
	
	void addChain						(int inputValue, int outputValue);
	int matchMarkov						(int input);
	
	Array< float >normalizeArray		(Array< int >& input);
	int wchoose							(Array<float>& choice_weight);
	
	int									lastValue;
	
	OwnedArray< EventData >				myChain;
	Array< int >						myProbs;

};

#endif // BASICMARKOVUSINGARRAYS_H_291C032F
[/code]

BasicMarkovUsingArrays.cpp

[code]#include “BasicMarkovUsingArrays.h”

BasicMarkovUsingArrays::BasicMarkovUsingArrays()
{
lastValue = 60;

EventData* newChain = new EventData();
newChain->inputValue = 0;
newChain->outputValue = 0;

myChain.add(newChain);
myProbs.add(1);

}

BasicMarkovUsingArrays::~BasicMarkovUsingArrays()
{

}

void BasicMarkovUsingArrays::learnFromEvent (int eventValue)
{

addChain(lastValue, eventValue);

lastValue = eventValue;

}

void BasicMarkovUsingArrays::addChain (int inputValue_, int outputValue_)
{
bool found = false;

//DBG(String(inputValue_) + String("  ") + String(outputValue_) );

// see if the chain already exists
for(int i = 0; i < myChain.size(); i++)
{
	//DBG(String("input chain: ") + String(myChain[i]->inputValue) + String(" output chain: ") + String(myChain[i]->outputValue) );
	// if yes then increase its probability
	if((myChain[i]->inputValue == inputValue_) && (myChain[i]->outputValue == outputValue_) )
	{
		//DBG("found");
		//DBG(String("input value: ") + String(inputValue_) + String(" output value: ") + String(outputValue_) );
		myProbs.set(i, myProbs[i] + 1);
		found = true;
		break;
	}
}

// if not, then add to collection and set initial probability to 1
if(found != true)
{
	EventData* inputChain = new EventData();
	
	inputChain->inputValue = inputValue_;
	inputChain->outputValue = outputValue_;
	
	//DBG(String("input value: ") + String(inputChain->inputValue) + String(" output value: ") + String(inputChain->outputValue) );
	myChain.add(inputChain );
	myProbs.add(1);
}

}

// guess the output for a given input
int BasicMarkovUsingArrays::calculateOutput (int input)
{
int output;
output = matchMarkov(input);

return output;

}

int BasicMarkovUsingArrays::matchMarkov (int input)
{
OwnedArray< EventData > matchChain;
Array matchProbs;

//DBG(String("Attempting to find a match for input value: ") + String(input) );
// try to find one that matches input, otherwise choose a random one
for(int i = 0; i < myChain.size(); i++)
{
	//DBG(String("value held in chain: ") + String(myChain[i]->inputValue) + String(" in: ") + String(input) );
	// do we have a match?
	// if so, add chain and probability to matched chains
	if(input == myChain[i]->inputValue )
	{
		matchChain.addCopiesOf(myChain, i, 1);
		matchProbs.add(myProbs[i]);
		
	}
}

//DBG(String("found ") + String(matchChain.size()) + String(" matches for input: ") + String(input) );


// if we found no matches
if(matchChain.size() == 0)
{
	// maybe we had no chains built yet
	if(myChain.size() == 0)
	{
		return -1;
	}
	// otherwise nothing matched, so choose a substitue
	else
	{
		// currently we do this randomly
		int output;
		// normalize the array;
		Array< float > normalizedProbs;
		normalizedProbs.addArray(normalizeArray(myProbs));
		// chooze a random chain using the probs 
		output = myChain[wchoose(normalizedProbs)]->outputValue; 
		
		/*
		 // but we should search chain for closest match to history using distance
		 */
		
		return output; 			
	}
}	
else
{
	int output;
	// normalize the array;
	Array< float > normalizedProbs;
	normalizedProbs.addArray(normalizeArray(matchProbs));
	// chooze a random chain using the probs 
	output = matchChain[wchoose(normalizedProbs)]->outputValue; 
	
	return output; 
}

}

// helper functions *** these should go into a seperate group of helper classes

// all elements need to sum to 1.0
Array< float > BasicMarkovUsingArrays::normalizeArray(Array< int >& input)
{
float sum = 0.0;
Array< float > output;

// find the sum
for(int i = 0; i < input.size(); i++)
{
	sum += input[i];
}

for(int i = 0; i < input.size(); i++)
{
	output.add((input[i]/sum) );
}

return output;

}

// read the slide file
int BasicMarkovUsingArrays::wchoose(Array& choice_weight)
{
// find closest match with out going over
float rnd = Random::getSystemRandom().nextFloat();

for(int i = 0; i < choice_weight.size(); i++)
{
	if(rnd < choice_weight[i])
	{
		return i;
	}
	
	rnd -= choice_weight[i];				  
}	

DBG("WChoose: Should never get to here!");
return -1;

}
[/code]

*****************************Using ValueTrees

BasicMarkov.h

[code]#ifndef BASICMARKOV_H_48A8FC63
#define BASICMARKOV_H_48A8FC63

#include “…/…/JuceLibraryCode/JuceHeader.h”

class BasicMarkov
{
public:
BasicMarkov ();
~BasicMarkov ();

void learnFromEvent					(int eventValue);

// guess the output for a given input
int calculateOutput					(int input);

private:

void addChain						(int prediction_);
int matchMarkov						(int observation_);

Array< float >normalizeProbs		(ValueTree input);
int wchoose							(Array<float>& choice_weight);
	
ValueTree							myChain;
Identifier							observation_0, prediction, eventProb;

};

#endif // BASICMARKOV_H_48A8FC63
[/code]

BasicMarkov.cpp

[code]#include “BasicMarkov.h”

BasicMarkov::BasicMarkov()
: myChain(Identifier(“MyChain”)),
observation_0(“Observation_0”),
prediction(“Prediction”),
eventProb(“EventProb”)
{
}

BasicMarkov::~BasicMarkov()
{
}

void BasicMarkov::learnFromEvent (int eventValue)
{
// pass in current event as prediction value
addChain(eventValue);
}

void BasicMarkov::addChain (int prediction_)
{
bool found = false;
// get last prediction as the observed value
int observation_ = (int)myChain.getChild (myChain.getNumChildren()-1).getPropertyAsValue(prediction, 0).getValue();

// see if the chain already exists
for(int i = 0; i < myChain.getNumChildren(); i++)
{
	// if yes then increase its probability
	if(((int)myChain.getChild(i).getPropertyAsValue(observation_0, 0).getValue() == observation_) && ((int)myChain.getChild(i).getPropertyAsValue(prediction, 0).getValue() == prediction_) )
	{
		//DBG("Found existing vector, increasing probabilities");
		int currentProb = myChain.getChild(i).getPropertyAsValue(eventProb, 0).getValue();
		myChain.getChild(i).setProperty(eventProb, currentProb++, 0);
		
		found = true;
		break;
	}
}

// if not, then add to collection and set initial probability to 1
if(found == false)
{		
	//DBG("Adding new Vector");
	myChain.addChild(ValueTree(Identifier("DataNode")), -1, 0);
	
	myChain.getChild(myChain.getNumChildren()-1).setProperty(prediction, prediction_, 0);
	myChain.getChild(myChain.getNumChildren()-1).setProperty(observation_0, observation_, 0);
	myChain.getChild(myChain.getNumChildren()-1).setProperty(eventProb, 1, 0);
}

}

// guess the output for a given input
int BasicMarkov::calculateOutput (int input)
{
int output;
output = matchMarkov(input);

return output;

}

int BasicMarkov::matchMarkov (int observation_)
{
ValueTree* matchChain = new ValueTree(Identifier(“MatchChain”));

// try to find one that matches input, otherwise choose a random one
for(int i = 0; i < myChain.getNumChildren(); i++)
{
	// do we have a match?
	// if so, add chain and probability to matched chains
	if(( myChain.getChild(i).getPropertyAsValue(observation_0, 0) == observation_) )
	{
		matchChain->addChild(myChain.getChild(i).createCopy(), -1, 0);
	}
}

//DBG(String("found ") + String(matchChain->getNumChildren()) + String(" matches for input: ") + String(observation_) );


// if we found no matches
if(matchChain->getNumChildren() == 0)
{
	// maybe we had no chains built yet
	if(myChain.getNumChildren() == 0)
	{
		return -1;
	}
	// otherwise nothing matched, so choose a substitue
	else
	{
		// currently we do this randomly
		int output;
		// normalize the array;
		Array< float > normalizedProbs;
		normalizedProbs.addArray(normalizeProbs(myChain));
		// chooze a random chain using the probs 
		output = myChain.getChild(wchoose(normalizedProbs)).getPropertyAsValue(prediction, 0).getValue(); 
		
		/*
		 // but we should search chain for closest match to history using distance
		 */
		
		return output; 			
	}
}	
else
{
	int output;
	// normalize the array;
	Array< float > normalizedProbs;
	normalizedProbs.addArray(normalizeProbs(*matchChain));
	// chooze a random chain using the probs 
	output = matchChain->getChild(wchoose(normalizedProbs)).getPropertyAsValue(prediction, 0).getValue(); 
	
	return output; 
}

}

// helper functions *** these should go into a seperate group of helper classes

// all elements need to sum to 1.0
Array< float > BasicMarkov::normalizeProbs(ValueTree input)
{
float sum = 0.0;
Array< float > output;

// find the sum
for(int i = 0; i < input.getNumChildren(); i++)
{
	sum += (float)input.getChild(i).getPropertyAsValue(eventProb, 0).getValue();
}

for(int i = 0; i < input.getNumChildren(); i++)
{
	output.add((float)input.getChild(i).getPropertyAsValue(eventProb, 0).getValue()/sum );
}

return output;

}

// read the slide file
int BasicMarkov::wchoose(Array& choice_weight)
{
// find closest match with out going over
float rnd = Random::getSystemRandom().nextFloat();

for(int i = 0; i < choice_weight.size(); i++)
{
	if(rnd < choice_weight[i])
	{
		return i;
	}
	
	rnd -= choice_weight[i];				  
}	

DBG("WChoose: Should never get to here!");
return -1;

}[/code]


#2

I’m afraid that’s a bit too complicated for me to be able to understand what’s going on very well… Perhaps you’re using floating points somewhere but accidentally casting them to ints when you add or remove them to a value tree?