<commit_before>/**
 * @file main.cpp
 *
 * @brief File containing main Q-Learning algorithm and all necessary associated functions to implementing this routine.
 *
 * @author Machine Learning Team 2015-2016
 * @date March, 2016
 */

#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include <fstream>
#include "StateSpace.h"
#include "PriorityQueue.h"
#include "State.h"
#include "encoder.h"
#include "CreateModule.h"

/**
* @brief Gives a std::string representation of a primitive type.
*
* @remark Can be used to print priority queue contents.
* @param x Primitive type such as int, double, long ...
* @return std::string conversion of param x
*/
template<typename T> std::string to_string(T x) {
	return static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x)).str();
}

/**
 * @brief Determines whether a file exists / is accessible
 *
 * @param filename File to check for
 * @return true if file exists, false if not or is inaccessible
 */
bool fileExists(const char* filename) {
	std::ifstream file(filename);
	return file.good();
}

/**
 * @brief Analog to temperature variable in Boltzmann Distribution, computes 'evolution variable' of system.
 *
 * This function computes a normal distribution over the parameterised number of loop iterations in order
 * to provide a function which explores the state space dilligently initially which then decays off to the
 * optimal solution after a large number of loop iterations.
 *
 * The normal distribution used by this function is:
 *
 * \f[ a e^{-\frac{bt^2}{c}} + \epsilon \f]
 *
 * where a, b and c are scaling coefficients (see method body) and \f$\epsilon\f$ is some small offset.
 *
 * @param t Number of loop iterations.
 * @return Value of normal distribution at t loop iterations.
 */
double probabilityFluxDensityCoeffieicent(unsigned long t);

//function to select next action

/**
 * @brief Selects an action to perform based on experience, iterations and probabilities.
 *
 * @param a_queue A priority queue instance storing integral types with double type priorities,
 *		  represents the queue of possible actions with pre-initialised priority levels.
 * @param iterations Number of loop iterations completed.
 * @return integer corresponding to chosen action
 */
int selectAction(PriorityQueue<int, double>& a_queue, unsigned long iterations);

/**
 * @brief Updates the utility (Q-value) of the system.
 *
 * Utility (Q-Value) of the system is updated via the Temporal Difference Learning Rule given by the following equation,
 *
 * \f[ Q_{i+1} (s,a) = Q_i (s,a) + \alpha [R(s') + \gamma \underset{a}{max} Q(s',a) - Q_i (s,a)] \f]
 *
 * where Q represents the utility of a state-action pair, \f$ \alpha \f$ is the learning rate, \f$ \gamma \f$ is the discount
 * factor and \f$ max_a (Q) \f$ yields the action-maximum of the Q space. The learning rate should be set to a low value for
 * highly stochastic, asymmetric systems or a high value for a lowly stochastic, symmetric system - this value lies between 0 and 1.
 * The discount factor (also in the interval [0,1]) represents the time considerations of the learning algorithm, lower values indicate
 * "living in the moment", whilst higher values indicate "planning for the future".
 *
 * @param space Reference to StateSpace object
 * @param action Integer code to previous performed action
 * @param new_state Reference to State instance giving the new system state
 * @param old_state Reference to State instance giving the old system state
 * @param alpha Learning rate of temporal difference learning algorithm (in the interval [0,1])
 * @param gamma Discount factor applied to q-learning equation (in the interval [0,1])
 */
void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma);

/**
 * @brief Program launcher!
 *
 * Contains all initialisations including setting up the StateSpace and connecting to robot via a proxy. Holds main
 * program loop to perform algorithm continuously using calls to selectAction and updateQ sequentially to update
 * utilities and choose most optimal actions to perform based on position and velocity.
 *
 * @return Program exit code
 */
int main() {
	// STUFF WE DONT UNDERSTAND, AND DONT NEED TO
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	// Libraries to load
	std::string bodyLibName = "bodyinfo";
	std::string movementLibName = "movementtools";

	// Name of camera module in library
	std::string bodyModuleName = "BodyInfo";
	std::string movementModuleName = "MovementTools";

	// Set broker name, ip and port, finding first available port from 54000
	const std::string brokerName = "MotionTimingBroker";
	int brokerPort = qi::os::findAvailablePort(54000);
	const std::string brokerIp = "0.0.0.0";

	// Default parent port and ip
	int pport = 9559;
	std::string pip = "127.0.0.1";

	// Need this for SOAP serialisation of floats to work
	setlocale(LC_NUMERIC, "C");

	// Create a broker
	boost::shared_ptr<AL::ALBroker> broker;
	try {
		broker = AL::ALBroker::createBroker(
			brokerName,
			brokerIp,
			brokerPort,
			pip,
			pport,
			0);
	}
	// Throw error and quit if a broker could not be created
	catch (...) {
		std::cerr << "Failed to connect broker to: "
			<< pip
			<< ":"
			<< pport
			<< std::endl;
		AL::ALBrokerManager::getInstance()->killAllBroker();
		AL::ALBrokerManager::kill();

		return 1;
	}

	// Add the broker to NAOqi
	AL::ALBrokerManager::setInstance(broker->fBrokerManager.lock());
	AL::ALBrokerManager::getInstance()->addBroker(broker);

	CreateModule(movementLibName, movementModuleName, broker, false, true);
	CreateModule(bodyLibName, bodyModuleName, broker, false, true);

	AL::ALProxy bodyInfoProxy(bodyModuleName, pip, pport);
	AL::ALProxy movementToolsProxy(movementModuleName, pip, pport);
	AL::ALMotionProxy motion(pip, pport);
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	//END OF STUFF WE DONT UNDERSTAND, BREATHE NOW

	//learning factor
	const double alpha = 0.8;
	//discount factor
	const double gamma = 0.5;

	//seed rng
	std::srand(static_cast<unsigned int>(std::time(NULL)));

	int action_forwards = FORWARD;
	int action_backwards = BACKWARD;
	int chosen_action = action_forwards;

	//create a priority queue to copy to all the state space priority queues
	PriorityQueue<int, double> initiator_queue(MAX);
	initiator_queue.enqueueWithPriority(action_forwards, 0);
	initiator_queue.enqueueWithPriority(action_backwards, 0);

	//create encoder
	Encoder encoder;
	encoder.Calibrate();

	//pause briefly to allow the robot to be given a push if desired
	qi::os::msleep(5000);

	//create the state space
	StateSpace space(100, 50, M_PI * 0.25, 1.0, initiator_queue);

	const char* filename = "output.txt";

	const char* encoderData = "encoderData.txt";
	std::ofstream encoderOutput(encoderData);

	// if file containing previous state space data exists
	// get handle to this file and stream contents to space object
	if (fileExists(filename)) {
		std::ifstream inputFile(filename);
		std::string firstFileLine;
		std::getline(inputFile, firstFileLine);
		// if file is not empty, save file data to state space object
		if (!firstFileLine.empty())
			inputFile >> space;
	}

	//state objects
	State current_state(0, 0, FORWARD);
	State old_state(0, 0, FORWARD);

	std::cout << "Initialisation complete!" << std::endl;
	for( unsigned long i = 0; i<500 ;++i ) {
		// set current state angle to angle received from encoder
		// and set current state velocity to difference in new and
		// old state angles over some time difference
		current_state.theta = M_PI * (encoder.GetAngle()) / 180;
		current_state.theta_dot = (current_state.theta - old_state.theta) / 700; //Needs actual time
		current_state.robot_state = static_cast<ROBOT_STATE>(chosen_action);

		//std::cout << "Angle of current state: " << current_state.theta << std::endl;
		encoderOutput << current_state.theta << std::endl;

		// call updateQ function with state space, old and current states
		// and learning rate, discount factor
		updateQ(space, chosen_action, old_state, current_state, alpha, gamma);
	//	std::cout << "Update Q completed!" << std::endl;
		// set old_state to current_state
		old_state = current_state;

		// determine chosen_action for current state
		chosen_action = selectAction(space[current_state], i);
	//	std::cout << "Select Action completed!" << std::endl;
		// depending upon chosen action, call robot movement tools proxy with either
		// swingForwards or swingBackwards commands.
		(chosen_action) ? movementToolsProxy.callVoid("swingForwards") : movementToolsProxy.callVoid("swingBackwards");
	}

//	std::ofstream output(filename);
//	output<<space;
//	output.close();
	std::cout << space << std::endl;
	encoderOutput.close();

	return 1;
}

double probabilityFluxDensityCoeffieicent(unsigned long t) {
	return 100.0*std::exp((-8.0*t*t) / (2600.0*2600.0)) + 0.1;//0.1 is an offset
}

int selectActionAlt(PriorityQueue<int, double>& a_queue, unsigned long iterations) {

	typedef std::vector<std::pair<int, double> > VecPair ;

	//turn priority queue into a vector of pairs
	VecPair vec = a_queue.saveOrderedQueueAsVector();

    //sum for partition function
	double sum = 0.0;

	// calculate partition function by iterating over action-values
	for (VecPair::iterator iter = vec.begin(), end = vec.end(); iter < end; ++iter) {
		sum += std::exp((iter->second) / probabilityFluxDensityCoeffieicent(iterations));
	}

	// compute Boltzmann factors for action-values and enqueue to vec
	for (VecPair::iterator iter = vec.begin(); iter < vec.end(); ++iter) {
		iter->second = std::exp(iter->second / probabilityFluxDensityCoeffieicent(iterations)) / sum;
	}

	// calculate cumulative probability distribution
	for (VecPair::iterator iter = vec.begin(), end = vec.end(); iter < end; ++iter) {
        //second member of pair becomes addition of its current value
        //and that of the index before it
        	if (iter != vec.begin())
			iter->second += (iter-1)->second;
	}

	//generate RN between 0 and 1
	double rand_num = static_cast<double>(rand()) / RAND_MAX;

	// choose action based on random number relation to priorities within action queue
	for (VecPair::iterator iter = vec.begin(), end = vec.end(); iter < end; ++iter) {
		if (rand_num < iter->second)
			return iter->first;
	}

	return -1; //note that this line should never be reached
}
int selectAction(PriorityQueue<int, double>& a_queue, unsigned long iterations) {
	double epsilon = 0.8;
	double rand_num = static_cast<double>(rand()) / RAND_MAX;
	if(rand_num < epsilon){
		return a_queue.peekFront().first;
	}

	rand_num = static_cast<double>(rand()) / RAND_MAX;
	return a_queue[ round( rand_num*(a_queue.getSize()-1) ) ].first;
}

void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma) {
	//oldQ value reference
	double oldQ = space[old_state].search(action).second;

	//reward given to current state
	double R = new_state.getReward();

	//optimal Q value for new state i.e. first element
	double maxQ = space[new_state].peekFront().second;

	//new Q value determined by Q learning algorithm
	double newQ = oldQ + alpha * (R + (gamma * maxQ) - oldQ);

	// change priority of action to new Q value
	space[old_state].changePriority(action, newQ);
}
/* OLD SELECT ACTION
int selectAction(const PriorityQueue<int, double>& a_queue, unsigned long iterations) {
	/*
	// queue to store action values
	PriorityQueue<int, double> actionQueue(MAX);
	double sum = 0.0;
	// calculate partition function by iterating over action-values
	for (PriorityQueue<int, double>::const_iterator iter = a_queue.begin(), end = a_queue.end(); iter < end; ++iter) {
		sum += std::exp((iter->second) / temperature(iterations));
	}
	// compute Boltzmann factors for action-values and enqueue to actionQueue
	for (PriorityQueue<int, double>::const_iterator iter = a_queue.begin(); iter < a_queue.end(); ++iter) {
		double priority = std::exp(iter.operator*().second / temperature(iterations)) / sum;
		actionQueue.enqueueWithPriority(iter.operator*().first, priority);
	}
	// calculate cumulative probability distribution
	for (PriorityQueue<int, double>::const_iterator it1 = actionQueue.begin()++, it2 = actionQueue.begin(), end = actionQueue.end(); it1 < end; ++it1, ++it2) {
		// change priority of it1->first data item in actionQueue to
		// sum of priorities of it1 and it2 items
		actionQueue.changePriority(it1->first, it1->second + it2->second);
	}
	//generate RN between 0 and 1
	double rand_num = static_cast<double>(rand()) / RAND_MAX;
	// choose action based on random number relation to priorities within action queue
	for (PriorityQueue<int, double>::const_iterator iter = actionQueue.begin(), end = actionQueue.end(); iter < end; ++iter) {
		if (rand_num < iter->second)
			return iter->first;
	}

	return -1; //note that this line should never be reached

	double rand_num = static_cast<double>(rand()) / RAND_MAX;

	return (rand_num > 0.5)?0:1;
}
*/
<commit_msg>Update Main.cpp<commit_after>/**
 * @file main.cpp
 *
 * @brief File containing main Q-Learning algorithm and all necessary associated functions to implementing this routine.
 *
 * @author Machine Learning Team 2015-2016
 * @date March, 2016
 */

#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include <fstream>
#include "StateSpace.h"
#include "PriorityQueue.h"
#include "State.h"
#include "encoder.h"
#include "CreateModule.h"

/**
* @brief Gives a std::string representation of a primitive type.
*
* @remark Can be used to print priority queue contents.
* @param x Primitive type such as int, double, long ...
* @return std::string conversion of param x
*/
template<typename T> std::string to_string(T x) {
	return static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x)).str();
}

/**
 * @brief Determines whether a file exists / is accessible
 *
 * @param filename File to check for
 * @return true if file exists, false if not or is inaccessible
 */
bool fileExists(const char* filename) {
	std::ifstream file(filename);
	return file.good();
}

/**
 * @brief Analog to temperature variable in Boltzmann Distribution, computes 'evolution variable' of system.
 *
 * This function computes a normal distribution over the parameterised number of loop iterations in order
 * to provide a function which explores the state space dilligently initially which then decays off to the
 * optimal solution after a large number of loop iterations.
 *
 * The normal distribution used by this function is:
 *
 * \f[ a e^{-\frac{bt^2}{c}} + \epsilon \f]
 *
 * where a, b and c are scaling coefficients (see method body) and \f$\epsilon\f$ is some small offset.
 *
 * @param t Number of loop iterations.
 * @return Value of normal distribution at t loop iterations.
 */
double probabilityFluxDensityCoeffieicent(unsigned long t);

//function to select next action

/**
 * @brief Selects an action to perform based on experience, iterations and probabilities.
 *
 * @param a_queue A priority queue instance storing integral types with double type priorities,
 *		  represents the queue of possible actions with pre-initialised priority levels.
 * @param iterations Number of loop iterations completed.
 * @return integer corresponding to chosen action
 */
int selectAction(PriorityQueue<int, double>& a_queue, unsigned long iterations, double epsilon);

/**
 * @brief Updates the utility (Q-value) of the system.
 *
 * Utility (Q-Value) of the system is updated via the Temporal Difference Learning Rule given by the following equation,
 *
 * \f[ Q_{i+1} (s,a) = Q_i (s,a) + \alpha [R(s') + \gamma \underset{a}{max} Q(s',a) - Q_i (s,a)] \f]
 *
 * where Q represents the utility of a state-action pair, \f$ \alpha \f$ is the learning rate, \f$ \gamma \f$ is the discount
 * factor and \f$ max_a (Q) \f$ yields the action-maximum of the Q space. The learning rate should be set to a low value for
 * highly stochastic, asymmetric systems or a high value for a lowly stochastic, symmetric system - this value lies between 0 and 1.
 * The discount factor (also in the interval [0,1]) represents the time considerations of the learning algorithm, lower values indicate
 * "living in the moment", whilst higher values indicate "planning for the future".
 *
 * @param space Reference to StateSpace object
 * @param action Integer code to previous performed action
 * @param new_state Reference to State instance giving the new system state
 * @param old_state Reference to State instance giving the old system state
 * @param alpha Learning rate of temporal difference learning algorithm (in the interval [0,1])
 * @param gamma Discount factor applied to q-learning equation (in the interval [0,1])
 */
void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma);

/**
 * @brief Program launcher!
 *
 * Contains all initialisations including setting up the StateSpace and connecting to robot via a proxy. Holds main
 * program loop to perform algorithm continuously using calls to selectAction and updateQ sequentially to update
 * utilities and choose most optimal actions to perform based on position and velocity.
 *
 * @return Program exit code
 */
int main() {
	// STUFF WE DONT UNDERSTAND, AND DONT NEED TO
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	// Libraries to load
	std::string bodyLibName = "bodyinfo";
	std::string movementLibName = "movementtools";

	// Name of camera module in library
	std::string bodyModuleName = "BodyInfo";
	std::string movementModuleName = "MovementTools";

	// Set broker name, ip and port, finding first available port from 54000
	const std::string brokerName = "MotionTimingBroker";
	int brokerPort = qi::os::findAvailablePort(54000);
	const std::string brokerIp = "0.0.0.0";

	// Default parent port and ip
	int pport = 9559;
	std::string pip = "127.0.0.1";

	// Need this for SOAP serialisation of floats to work
	setlocale(LC_NUMERIC, "C");

	// Create a broker
	boost::shared_ptr<AL::ALBroker> broker;
	try {
		broker = AL::ALBroker::createBroker(
			brokerName,
			brokerIp,
			brokerPort,
			pip,
			pport,
			0);
	}
	// Throw error and quit if a broker could not be created
	catch (...) {
		std::cerr << "Failed to connect broker to: "
			<< pip
			<< ":"
			<< pport
			<< std::endl;
		AL::ALBrokerManager::getInstance()->killAllBroker();
		AL::ALBrokerManager::kill();

		return 1;
	}

	// Add the broker to NAOqi
	AL::ALBrokerManager::setInstance(broker->fBrokerManager.lock());
	AL::ALBrokerManager::getInstance()->addBroker(broker);

	CreateModule(movementLibName, movementModuleName, broker, false, true);
	CreateModule(bodyLibName, bodyModuleName, broker, false, true);

	AL::ALProxy bodyInfoProxy(bodyModuleName, pip, pport);
	AL::ALProxy movementToolsProxy(movementModuleName, pip, pport);
	AL::ALMotionProxy motion(pip, pport);
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	//END OF STUFF WE DONT UNDERSTAND, BREATHE NOW

	//learning factor
	const double alpha = 0.8;
	//discount factor
	const double gamma = 0.5;

	//seed rng
	std::srand(static_cast<unsigned int>(std::time(NULL)));

	int action_forwards = FORWARD;
	int action_backwards = BACKWARD;
	int chosen_action = action_forwards;

	//create a priority queue to copy to all the state space priority queues
	PriorityQueue<int, double> initiator_queue(MAX);
	initiator_queue.enqueueWithPriority(action_forwards, 0);
	initiator_queue.enqueueWithPriority(action_backwards, 0);

	//create encoder
	Encoder encoder;
	encoder.Calibrate();

	std::cout << "Encoder angle calibrated... " << std::endl;

	//pause briefly to allow the robot to be given a push if desired
	qi::os::msleep(5000);

	//create the state space
	StateSpace space(100, 50, M_PI * 0.25, 1.0, initiator_queue);

	const char* filename = "output.txt";

	const char* encoderData = "encoderData.txt";
	std::ofstream encoderOutput(encoderData);

	// if file containing previous state space data exists
	// get handle to this file and stream contents to space object
	if (fileExists(filename)) {
		std::ifstream inputFile(filename);
		std::string firstFileLine;
		std::getline(inputFile, firstFileLine);
		// if file is not empty, save file data to state space object
		if (!firstFileLine.empty())
			inputFile >> space;
	}

	//state objects
	State current_state(0, 0, FORWARD);
	State old_state(0, 0, FORWARD);
	double epsilon = 1.0;
	std::cout << "Initialisation complete!" << std::endl;
	for( unsigned long i = 0; i<500 ;++i ) {
		// set current state angle to angle received from encoder
		// and set current state velocity to difference in new and
		// old state angles over some time difference
		current_state.theta = M_PI * (encoder.GetAngle()) / 180;
		current_state.theta_dot = (current_state.theta - old_state.theta) / 700; //Needs actual time
		current_state.robot_state = static_cast<ROBOT_STATE>(chosen_action);

		//std::cout << "Angle of current state: " << current_state.theta << std::endl;
		encoderOutput << current_state.theta << std::endl;

		// call updateQ function with state space, old and current states
		// and learning rate, discount factor
		updateQ(space, chosen_action, old_state, current_state, alpha, gamma);
	//	std::cout << "Update Q completed!" << std::endl;
		// set old_state to current_state
		old_state = current_state;

		if (i > 100) {
			epsilon -= 0.005;
		}

		// determine chosen_action for current state
		chosen_action = selectAction(space[current_state], i, epsilon);
	//	std::cout << "Select Action completed!" << std::endl;
		// depending upon chosen action, call robot movement tools proxy with either
		// swingForwards or swingBackwards commands.
		(chosen_action) ? movementToolsProxy.callVoid("swingForwards") : movementToolsProxy.callVoid("swingBackwards");
	}

//	std::ofstream output(filename);
//	output<<space;
//	output.close();
	std::cout << space << std::endl;
	encoderOutput.close();

	return 1;
}

double probabilityFluxDensityCoeffieicent(unsigned long t) {
	return 100.0*std::exp((-8.0*t*t) / (2600.0*2600.0)) + 0.1;//0.1 is an offset
}

int selectActionAlt(PriorityQueue<int, double>& a_queue, unsigned long iterations) {

	typedef std::vector<std::pair<int, double> > VecPair ;

	//turn priority queue into a vector of pairs
	VecPair vec = a_queue.saveOrderedQueueAsVector();

    //sum for partition function
	double sum = 0.0;

	// calculate partition function by iterating over action-values
	for (VecPair::iterator iter = vec.begin(), end = vec.end(); iter < end; ++iter) {
		sum += std::exp((iter->second) / probabilityFluxDensityCoeffieicent(iterations));
	}

	// compute Boltzmann factors for action-values and enqueue to vec
	for (VecPair::iterator iter = vec.begin(); iter < vec.end(); ++iter) {
		iter->second = std::exp(iter->second / probabilityFluxDensityCoeffieicent(iterations)) / sum;
	}

	// calculate cumulative probability distribution
	for (VecPair::iterator iter = vec.begin(), end = vec.end(); iter < end; ++iter) {
        //second member of pair becomes addition of its current value
        //and that of the index before it
        	if (iter != vec.begin())
			iter->second += (iter-1)->second;
	}

	//generate RN between 0 and 1
	double rand_num = static_cast<double>(rand()) / RAND_MAX;

	// choose action based on random number relation to priorities within action queue
	for (VecPair::iterator iter = vec.begin(), end = vec.end(); iter < end; ++iter) {
		if (rand_num < iter->second)
			return iter->first;
	}

	return -1; //note that this line should never be reached
}
int selectAction(PriorityQueue<int, double>& a_queue, unsigned long iterations, double epsilon) {
	//double epsilon = 0.8;
	double rand_num = static_cast<double>(rand()) / RAND_MAX;
	if(rand_num < epsilon){
		return a_queue.peekFront().first;
	}

	rand_num = static_cast<double>(rand()) / RAND_MAX;
	return a_queue[ round( rand_num*(a_queue.getSize()-1) ) ].first;
}

void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma) {
	//oldQ value reference
	double oldQ = space[old_state].search(action).second;

	//reward given to current state
	double R = new_state.getReward();

	//optimal Q value for new state i.e. first element
	double maxQ = space[new_state].peekFront().second;

	//new Q value determined by Q learning algorithm
	double newQ = oldQ + alpha * (R + (gamma * maxQ) - oldQ);

	// change priority of action to new Q value
	space[old_state].changePriority(action, newQ);
}
/* OLD SELECT ACTION
int selectAction(const PriorityQueue<int, double>& a_queue, unsigned long iterations) {
	/*
	// queue to store action values
	PriorityQueue<int, double> actionQueue(MAX);
	double sum = 0.0;
	// calculate partition function by iterating over action-values
	for (PriorityQueue<int, double>::const_iterator iter = a_queue.begin(), end = a_queue.end(); iter < end; ++iter) {
		sum += std::exp((iter->second) / temperature(iterations));
	}
	// compute Boltzmann factors for action-values and enqueue to actionQueue
	for (PriorityQueue<int, double>::const_iterator iter = a_queue.begin(); iter < a_queue.end(); ++iter) {
		double priority = std::exp(iter.operator*().second / temperature(iterations)) / sum;
		actionQueue.enqueueWithPriority(iter.operator*().first, priority);
	}
	// calculate cumulative probability distribution
	for (PriorityQueue<int, double>::const_iterator it1 = actionQueue.begin()++, it2 = actionQueue.begin(), end = actionQueue.end(); it1 < end; ++it1, ++it2) {
		// change priority of it1->first data item in actionQueue to
		// sum of priorities of it1 and it2 items
		actionQueue.changePriority(it1->first, it1->second + it2->second);
	}
	//generate RN between 0 and 1
	double rand_num = static_cast<double>(rand()) / RAND_MAX;
	// choose action based on random number relation to priorities within action queue
	for (PriorityQueue<int, double>::const_iterator iter = actionQueue.begin(), end = actionQueue.end(); iter < end; ++iter) {
		if (rand_num < iter->second)
			return iter->first;
	}

	return -1; //note that this line should never be reached

	double rand_num = static_cast<double>(rand()) / RAND_MAX;

	return (rand_num > 0.5)?0:1;
}
*/
<|endoftext|>


<commit_before>//=============================================================================================================
/**
 * @file     spline.cpp
 * @author   Lorenz Esch <lesch@mgh.harvard.edu>
 * @since    0.1.0
 * @date     April, 2016
 *
 * @section  LICENSE
 *
 * Copyright (C) 2016, Lorenz Esch. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *       the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
 *       to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @brief    Definition of spline class
 *
 */

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "spline.h"

#include "helpers/colormap.h"

//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QGridLayout>
#include <QtCharts/QLegendMarker>
#include <QtCharts/QChartView>
#include <QDebug>

//=============================================================================================================
// EIGEN INCLUDES
//=============================================================================================================

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace DISPLIB;
using namespace QtCharts;

//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

Spline::Spline(QWidget* parent, const QString& /*title*/)
: QWidget(parent)
, m_dMinAxisX(0)
, m_dMaxAxisX(0)
, m_pLeftThreshold(new QLineSeries())
, m_pMiddleThreshold(new QLineSeries())
, m_pRightThreshold(new QLineSeries())
, m_iMaximumFrequency(0)
{
    m_pChart = new QChart();
    //m_pChart->setTitle(title);
    m_pChart->setAnimationOptions(QChart::SeriesAnimations);
    m_pChart->setAcceptHoverEvents(false);
    m_pSeries = new QSplineSeries();
    QChartView *chartView = new QChartView(m_pChart);
    chartView->setRenderHint(QPainter::Antialiasing);
    QGridLayout* layout = new QGridLayout();
    layout->addWidget(chartView, 0, 0);
    this->setLayout(layout);
}

//=============================================================================================================

void Spline::mousePressEvent(QMouseEvent *event)
{
    if (m_pSeries->count() == 0)               //protect integrity of the histogram widget in case series contain no data values
    {
        qDebug() << "Data set not found.";  //do nothing
    }

    else
    {
        QXYSeries *shadowSeries = qobject_cast<QXYSeries *>(sender());
        QLineSeries *verticalLine = new QLineSeries();
        QPointF point = event->pos();
        QPointF pointY = point;
        pointY.setX(m_dMinAxisX);
        pointY.setY(pointY.y()-10.5);   //-10.5 needed to correctly position the line at mouse position
        point.setX(point.x()-10.5);
        point.setY(0);

        QPointF localX = m_pChart->mapToValue(point, shadowSeries);
        QPointF localY = m_pChart->mapToValue(pointY, shadowSeries);
        verticalLine->append(localX.x(), 0);
        verticalLine->append(localX.x(), m_iMaximumFrequency);
        double boundaryX = double(localX.x());   //casting localX.x() from float to double for comparison with minAxisX and maxAxisX
        double boundaryY = double(localY.y());   //casting localY.y() from float to double for comparison with 0 and the maximum frequency

        if((boundaryX >= float(m_dMinAxisX)) && (boundaryX <= float(m_dMaxAxisX)))  //this condition ensures that threshold lines can only be created within the boundary of the x-axis
        {
            if((boundaryY >= 0.0) && (boundaryY <= float(m_iMaximumFrequency)))  // this condition ensures that threshold lines can only be created within the boundary of the y-axis
            {
                QVector<QPointF> middlePoint = m_pMiddleThreshold->pointsVector();   //Point values need to be updated before tested and displayed on the widget
                QVector<QPointF> rightPoint = m_pRightThreshold->pointsVector();
                QVector<QPointF> leftPoint = m_pLeftThreshold->pointsVector();

                double emitLeft = (leftPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                double emitMiddle = (middlePoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                double emitRight = (rightPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));

                if (event->buttons() == Qt::LeftButton)
                {
                    leftPoint = verticalLine->pointsVector();
                    if((leftPoint[0].x() < middlePoint[0].x()) && (leftPoint[0].x() < rightPoint[0].x()))
                    {
                        m_pChart->removeSeries(m_pLeftThreshold);
                        m_pLeftThreshold = verticalLine;
                        m_pLeftThreshold->setName("left");
                        updateThreshold(m_pLeftThreshold);
                        emitLeft = (leftPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                        emit borderChanged(emitLeft, emitMiddle, emitRight);
                    }
                }

                if (event->buttons() == Qt::MiddleButton)
                {
                    middlePoint = verticalLine->pointsVector();
                    if((middlePoint[0].x() > leftPoint[0].x()) && (middlePoint[0].x() < rightPoint[0].x()))
                    {
                        m_pChart->removeSeries(m_pMiddleThreshold);
                        m_pMiddleThreshold = verticalLine;
                        m_pMiddleThreshold->setName("middle");
                        updateThreshold(m_pMiddleThreshold);
                        emitMiddle = (middlePoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                        emit borderChanged(emitLeft, emitMiddle, emitRight);
                    }
                }

                if (event->buttons() == Qt::RightButton)
                {
                    rightPoint = verticalLine->pointsVector();
                    if((rightPoint[0].x() > leftPoint[0].x()) && (rightPoint[0].x() > middlePoint[0].x()))
                    {
                        m_pChart->removeSeries(m_pRightThreshold);
                        m_pRightThreshold = verticalLine;
                        m_pRightThreshold->setName("right");
                        updateThreshold(m_pRightThreshold);
                        emitRight = (rightPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                        emit borderChanged(emitLeft, emitMiddle, emitRight);
                    }
                }
            }
        }
        setColorMap(m_colorMap);
    }
}

//=============================================================================================================

void Spline::setThreshold(const QVector3D& vecThresholdValues)
{
    float leftThresholdValue = vecThresholdValues.x();
    float middleThresholdValue = vecThresholdValues.y();
    float rightThresholdValue = vecThresholdValues.z();

    QVector3D correctedVectorThreshold = correctionDisplayTrueValue(vecThresholdValues, "up");

    if (m_pSeries->count() == 0)               //protect integrity of the histogram widget in case series contain no data values
    {
        qDebug() << "Data set not found.";
    }

//    the condition below tests the threshold values given and ensures that all three must be within minAxisX and maxAxisX otherwise they will be given either minAxisX or maxAxisX value
    else if (correctedVectorThreshold.x() < m_dMinAxisX || correctedVectorThreshold.y() < m_dMinAxisX || correctedVectorThreshold.z() < m_dMinAxisX || correctedVectorThreshold.x() > m_dMaxAxisX || correctedVectorThreshold.y() > m_dMaxAxisX || correctedVectorThreshold.z() > m_dMaxAxisX)
    {
        qDebug() << "One or more of the values given are out of the minimum and maximum range. Changed to default thresholds.";
        leftThresholdValue = 1.01 * m_dMinAxisX;
        middleThresholdValue = (m_dMinAxisX + m_dMaxAxisX) / 2;
        rightThresholdValue = 0.99 * m_dMaxAxisX;
    }
    else
    {
        if ((correctedVectorThreshold.x() < correctedVectorThreshold.y()) && (correctedVectorThreshold.x() < correctedVectorThreshold.z()))
        {
            leftThresholdValue = correctedVectorThreshold.x();
            if(correctedVectorThreshold.y() < correctedVectorThreshold.z())
            {
                middleThresholdValue = correctedVectorThreshold.y();
                rightThresholdValue = correctedVectorThreshold.z();
            }
            else
            {
                middleThresholdValue = correctedVectorThreshold.z();
                rightThresholdValue = correctedVectorThreshold.y();
            }
        }
        if ((correctedVectorThreshold.y() < correctedVectorThreshold.x()) && (correctedVectorThreshold.y() < correctedVectorThreshold.z()))
        {
            leftThresholdValue = correctedVectorThreshold.y();

            if(correctedVectorThreshold.x() < correctedVectorThreshold.z())
            {
                middleThresholdValue = correctedVectorThreshold.x();
                rightThresholdValue = correctedVectorThreshold.z();
            }
            else
            {
                middleThresholdValue = correctedVectorThreshold.z();
                rightThresholdValue = correctedVectorThreshold.x();
            }
        }
        if ((correctedVectorThreshold.z() < correctedVectorThreshold.x()) && (correctedVectorThreshold.z() < correctedVectorThreshold.y()))
        {
            leftThresholdValue = correctedVectorThreshold.z();

            if(correctedVectorThreshold.x() < correctedVectorThreshold.y())
            {
                middleThresholdValue = correctedVectorThreshold.x();
                rightThresholdValue = correctedVectorThreshold.y();
            }
            else
            {
                middleThresholdValue = correctedVectorThreshold.y();
                rightThresholdValue = correctedVectorThreshold.x();
            }
        }
    }

    QPointF leftThresholdPoint;
    QPointF middleThresholdPoint;
    QPointF rightThresholdPoint;

    leftThresholdPoint.setX(leftThresholdValue);
    middleThresholdPoint.setX(middleThresholdValue);
    rightThresholdPoint.setX(rightThresholdValue);

    m_pLeftThreshold->append(leftThresholdPoint.x(), 0);
    m_pLeftThreshold->append(leftThresholdPoint.x(), m_iMaximumFrequency);
    m_pMiddleThreshold->append(middleThresholdPoint.x(), 0);
    m_pMiddleThreshold->append(middleThresholdPoint.x(), m_iMaximumFrequency);
    m_pRightThreshold->append(rightThresholdPoint.x(), 0);
    m_pRightThreshold->append(rightThresholdPoint.x(), m_iMaximumFrequency);

    updateThreshold(m_pLeftThreshold);
    updateThreshold(m_pMiddleThreshold);
    updateThreshold(m_pRightThreshold);
    setColorMap(m_colorMap);
}

//=============================================================================================================

void Spline::updateThreshold(QLineSeries* lineSeries)
{
    if (lineSeries->name() == "left")
    {
        lineSeries->setColor("red");
    }
    else if (lineSeries->name() == "middle")
    {
        lineSeries->setColor("green");
    }
    else if (lineSeries->name() == "right")
    {
        lineSeries->setColor("blue");
    }
    else
    {
        qDebug()<< "Error: lineSeries->name() is not 'left', 'middle' or 'right'.";
    }
    lineSeries->setVisible(true);
    m_pChart->addSeries(lineSeries);
    m_pChart->legend()->markers().at(m_pChart->legend()->markers().size()-1)->setVisible(false);
    m_pChart->createDefaultAxes();
}

//=============================================================================================================

void Spline::setColorMap(const QString& colorMap)
{
    m_colorMap = colorMap;
    double leftThresholdValue = (m_pLeftThreshold->at(0).x())/ m_dMaxAxisX;
    double middleThresholdValue = (m_pMiddleThreshold->at(0).x())/ m_dMaxAxisX;
    double rightThresholdValue = (m_pRightThreshold->at(0).x())/ m_dMaxAxisX;
    int stepsNumber = 25;
    double stepsSizeLeftMiddle = (middleThresholdValue - leftThresholdValue) / stepsNumber;
    double stepsSizeMiddleRight = (rightThresholdValue - middleThresholdValue) / stepsNumber;
    QLinearGradient plotAreaGradient;
    plotAreaGradient.setStart(QPointF(0, 0));
    plotAreaGradient.setFinalStop(QPointF(1, 0));

    plotAreaGradient.setColorAt(leftThresholdValue, ColorMap::valueToColor(0.0, colorMap));

    for (int i = 1; i < stepsNumber; ++i)
    {
        plotAreaGradient.setColorAt(leftThresholdValue + (stepsSizeLeftMiddle * i), ColorMap::valueToColor((double)i * (0.5 / (double)stepsNumber), colorMap));
        plotAreaGradient.setColorAt(middleThresholdValue + (stepsSizeMiddleRight * i), ColorMap::valueToColor((double)0.5 + (i * (0.5 / (double)stepsNumber)), colorMap));
    }
    plotAreaGradient.setColorAt(rightThresholdValue, ColorMap::valueToColor(1.0, colorMap));

    // Customize plot area background
    plotAreaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
    m_pChart->setPlotAreaBackgroundBrush(plotAreaGradient);
    m_pChart->setPlotAreaBackgroundVisible(true);
}

//=============================================================================================================

const QVector3D& Spline::getThreshold()
{
    QVector<QPointF> middlePoint = m_pMiddleThreshold->pointsVector();   //Point values need to be updated before tested and displayed on the widget
    QVector<QPointF> rightPoint = m_pRightThreshold->pointsVector();
    QVector<QPointF> leftPoint = m_pLeftThreshold->pointsVector();
    float emitLeft = leftPoint[0].x();
    float emitMiddle = middlePoint[0].x();
    float emitRight = rightPoint[0].x();
    QVector3D originalVector;
    originalVector.setX(emitLeft);
    originalVector.setY(emitMiddle);
    originalVector.setZ(emitRight);
    m_vecReturnVector = correctionDisplayTrueValue(originalVector, "down");
    return m_vecReturnVector;
}

//=============================================================================================================

QVector3D Spline::correctionDisplayTrueValue(QVector3D vecOriginalValues, QString upOrDown)
{
    QVector3D returnCorrectedVector;

    if(m_vecResultExponentValues.rows() > 0) {
        int exponent;
        if (upOrDown == "up")
        {
            if (m_vecResultExponentValues[0] < 0)
            {
                exponent = std::abs(m_vecResultExponentValues[0]);
            }
            else if (m_vecResultExponentValues[0] > 0)
            {
                exponent = -(std::abs(m_vecResultExponentValues[0]));
            }
            else
            {
                exponent = 0;
            }
        }
        else if (upOrDown == "down")
        {
            if (m_vecResultExponentValues[0] < 0)
            {
                exponent = -(std::abs(m_vecResultExponentValues[0]));
            }
            else if (m_vecResultExponentValues[0] > 0)
            {
                exponent = std::abs(m_vecResultExponentValues[0]);
            }
            else
            {
                exponent = 0;
            }
        }
        else
        {
            qDebug() << "Spline::correctionDisplayTrueValue error.";
        }

        returnCorrectedVector.setX(vecOriginalValues.x() * (pow(10, exponent)));
        returnCorrectedVector.setY(vecOriginalValues.y() * (pow(10, exponent)));
        returnCorrectedVector.setZ(vecOriginalValues.z() * (pow(10, exponent)));
    }

    return returnCorrectedVector;
}
<commit_msg>undo comment unused variable in spline.cpp<commit_after>//=============================================================================================================
/**
 * @file     spline.cpp
 * @author   Lorenz Esch <lesch@mgh.harvard.edu>
 * @since    0.1.0
 * @date     April, 2016
 *
 * @section  LICENSE
 *
 * Copyright (C) 2016, Lorenz Esch. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *       the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
 *       to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @brief    Definition of spline class
 *
 */

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "spline.h"

#include "helpers/colormap.h"

//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QGridLayout>
#include <QtCharts/QLegendMarker>
#include <QtCharts/QChartView>
#include <QDebug>

//=============================================================================================================
// EIGEN INCLUDES
//=============================================================================================================

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace DISPLIB;
using namespace QtCharts;

//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

Spline::Spline(QWidget* parent, const QString& title)
: QWidget(parent)
, m_dMinAxisX(0)
, m_dMaxAxisX(0)
, m_pLeftThreshold(new QLineSeries())
, m_pMiddleThreshold(new QLineSeries())
, m_pRightThreshold(new QLineSeries())
, m_iMaximumFrequency(0)
{
    m_pChart = new QChart();
    //m_pChart->setTitle(title);
    m_pChart->setAnimationOptions(QChart::SeriesAnimations);
    m_pChart->setAcceptHoverEvents(false);
    m_pSeries = new QSplineSeries();
    QChartView *chartView = new QChartView(m_pChart);
    chartView->setRenderHint(QPainter::Antialiasing);
    QGridLayout* layout = new QGridLayout();
    layout->addWidget(chartView, 0, 0);
    this->setLayout(layout);
}

//=============================================================================================================

void Spline::mousePressEvent(QMouseEvent *event)
{
    if (m_pSeries->count() == 0)               //protect integrity of the histogram widget in case series contain no data values
    {
        qDebug() << "Data set not found.";  //do nothing
    }

    else
    {
        QXYSeries *shadowSeries = qobject_cast<QXYSeries *>(sender());
        QLineSeries *verticalLine = new QLineSeries();
        QPointF point = event->pos();
        QPointF pointY = point;
        pointY.setX(m_dMinAxisX);
        pointY.setY(pointY.y()-10.5);   //-10.5 needed to correctly position the line at mouse position
        point.setX(point.x()-10.5);
        point.setY(0);

        QPointF localX = m_pChart->mapToValue(point, shadowSeries);
        QPointF localY = m_pChart->mapToValue(pointY, shadowSeries);
        verticalLine->append(localX.x(), 0);
        verticalLine->append(localX.x(), m_iMaximumFrequency);
        double boundaryX = double(localX.x());   //casting localX.x() from float to double for comparison with minAxisX and maxAxisX
        double boundaryY = double(localY.y());   //casting localY.y() from float to double for comparison with 0 and the maximum frequency

        if((boundaryX >= float(m_dMinAxisX)) && (boundaryX <= float(m_dMaxAxisX)))  //this condition ensures that threshold lines can only be created within the boundary of the x-axis
        {
            if((boundaryY >= 0.0) && (boundaryY <= float(m_iMaximumFrequency)))  // this condition ensures that threshold lines can only be created within the boundary of the y-axis
            {
                QVector<QPointF> middlePoint = m_pMiddleThreshold->pointsVector();   //Point values need to be updated before tested and displayed on the widget
                QVector<QPointF> rightPoint = m_pRightThreshold->pointsVector();
                QVector<QPointF> leftPoint = m_pLeftThreshold->pointsVector();

                double emitLeft = (leftPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                double emitMiddle = (middlePoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                double emitRight = (rightPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));

                if (event->buttons() == Qt::LeftButton)
                {
                    leftPoint = verticalLine->pointsVector();
                    if((leftPoint[0].x() < middlePoint[0].x()) && (leftPoint[0].x() < rightPoint[0].x()))
                    {
                        m_pChart->removeSeries(m_pLeftThreshold);
                        m_pLeftThreshold = verticalLine;
                        m_pLeftThreshold->setName("left");
                        updateThreshold(m_pLeftThreshold);
                        emitLeft = (leftPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                        emit borderChanged(emitLeft, emitMiddle, emitRight);
                    }
                }

                if (event->buttons() == Qt::MiddleButton)
                {
                    middlePoint = verticalLine->pointsVector();
                    if((middlePoint[0].x() > leftPoint[0].x()) && (middlePoint[0].x() < rightPoint[0].x()))
                    {
                        m_pChart->removeSeries(m_pMiddleThreshold);
                        m_pMiddleThreshold = verticalLine;
                        m_pMiddleThreshold->setName("middle");
                        updateThreshold(m_pMiddleThreshold);
                        emitMiddle = (middlePoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                        emit borderChanged(emitLeft, emitMiddle, emitRight);
                    }
                }

                if (event->buttons() == Qt::RightButton)
                {
                    rightPoint = verticalLine->pointsVector();
                    if((rightPoint[0].x() > leftPoint[0].x()) && (rightPoint[0].x() > middlePoint[0].x()))
                    {
                        m_pChart->removeSeries(m_pRightThreshold);
                        m_pRightThreshold = verticalLine;
                        m_pRightThreshold->setName("right");
                        updateThreshold(m_pRightThreshold);
                        emitRight = (rightPoint[0].x() * (pow(10, m_vecResultExponentValues[0])));
                        emit borderChanged(emitLeft, emitMiddle, emitRight);
                    }
                }
            }
        }
        setColorMap(m_colorMap);
    }
}

//=============================================================================================================

void Spline::setThreshold(const QVector3D& vecThresholdValues)
{
    float leftThresholdValue = vecThresholdValues.x();
    float middleThresholdValue = vecThresholdValues.y();
    float rightThresholdValue = vecThresholdValues.z();

    QVector3D correctedVectorThreshold = correctionDisplayTrueValue(vecThresholdValues, "up");

    if (m_pSeries->count() == 0)               //protect integrity of the histogram widget in case series contain no data values
    {
        qDebug() << "Data set not found.";
    }

//    the condition below tests the threshold values given and ensures that all three must be within minAxisX and maxAxisX otherwise they will be given either minAxisX or maxAxisX value
    else if (correctedVectorThreshold.x() < m_dMinAxisX || correctedVectorThreshold.y() < m_dMinAxisX || correctedVectorThreshold.z() < m_dMinAxisX || correctedVectorThreshold.x() > m_dMaxAxisX || correctedVectorThreshold.y() > m_dMaxAxisX || correctedVectorThreshold.z() > m_dMaxAxisX)
    {
        qDebug() << "One or more of the values given are out of the minimum and maximum range. Changed to default thresholds.";
        leftThresholdValue = 1.01 * m_dMinAxisX;
        middleThresholdValue = (m_dMinAxisX + m_dMaxAxisX) / 2;
        rightThresholdValue = 0.99 * m_dMaxAxisX;
    }
    else
    {
        if ((correctedVectorThreshold.x() < correctedVectorThreshold.y()) && (correctedVectorThreshold.x() < correctedVectorThreshold.z()))
        {
            leftThresholdValue = correctedVectorThreshold.x();
            if(correctedVectorThreshold.y() < correctedVectorThreshold.z())
            {
                middleThresholdValue = correctedVectorThreshold.y();
                rightThresholdValue = correctedVectorThreshold.z();
            }
            else
            {
                middleThresholdValue = correctedVectorThreshold.z();
                rightThresholdValue = correctedVectorThreshold.y();
            }
        }
        if ((correctedVectorThreshold.y() < correctedVectorThreshold.x()) && (correctedVectorThreshold.y() < correctedVectorThreshold.z()))
        {
            leftThresholdValue = correctedVectorThreshold.y();

            if(correctedVectorThreshold.x() < correctedVectorThreshold.z())
            {
                middleThresholdValue = correctedVectorThreshold.x();
                rightThresholdValue = correctedVectorThreshold.z();
            }
            else
            {
                middleThresholdValue = correctedVectorThreshold.z();
                rightThresholdValue = correctedVectorThreshold.x();
            }
        }
        if ((correctedVectorThreshold.z() < correctedVectorThreshold.x()) && (correctedVectorThreshold.z() < correctedVectorThreshold.y()))
        {
            leftThresholdValue = correctedVectorThreshold.z();

            if(correctedVectorThreshold.x() < correctedVectorThreshold.y())
            {
                middleThresholdValue = correctedVectorThreshold.x();
                rightThresholdValue = correctedVectorThreshold.y();
            }
            else
            {
                middleThresholdValue = correctedVectorThreshold.y();
                rightThresholdValue = correctedVectorThreshold.x();
            }
        }
    }

    QPointF leftThresholdPoint;
    QPointF middleThresholdPoint;
    QPointF rightThresholdPoint;

    leftThresholdPoint.setX(leftThresholdValue);
    middleThresholdPoint.setX(middleThresholdValue);
    rightThresholdPoint.setX(rightThresholdValue);

    m_pLeftThreshold->append(leftThresholdPoint.x(), 0);
    m_pLeftThreshold->append(leftThresholdPoint.x(), m_iMaximumFrequency);
    m_pMiddleThreshold->append(middleThresholdPoint.x(), 0);
    m_pMiddleThreshold->append(middleThresholdPoint.x(), m_iMaximumFrequency);
    m_pRightThreshold->append(rightThresholdPoint.x(), 0);
    m_pRightThreshold->append(rightThresholdPoint.x(), m_iMaximumFrequency);

    updateThreshold(m_pLeftThreshold);
    updateThreshold(m_pMiddleThreshold);
    updateThreshold(m_pRightThreshold);
    setColorMap(m_colorMap);
}

//=============================================================================================================

void Spline::updateThreshold(QLineSeries* lineSeries)
{
    if (lineSeries->name() == "left")
    {
        lineSeries->setColor("red");
    }
    else if (lineSeries->name() == "middle")
    {
        lineSeries->setColor("green");
    }
    else if (lineSeries->name() == "right")
    {
        lineSeries->setColor("blue");
    }
    else
    {
        qDebug()<< "Error: lineSeries->name() is not 'left', 'middle' or 'right'.";
    }
    lineSeries->setVisible(true);
    m_pChart->addSeries(lineSeries);
    m_pChart->legend()->markers().at(m_pChart->legend()->markers().size()-1)->setVisible(false);
    m_pChart->createDefaultAxes();
}

//=============================================================================================================

void Spline::setColorMap(const QString& colorMap)
{
    m_colorMap = colorMap;
    double leftThresholdValue = (m_pLeftThreshold->at(0).x())/ m_dMaxAxisX;
    double middleThresholdValue = (m_pMiddleThreshold->at(0).x())/ m_dMaxAxisX;
    double rightThresholdValue = (m_pRightThreshold->at(0).x())/ m_dMaxAxisX;
    int stepsNumber = 25;
    double stepsSizeLeftMiddle = (middleThresholdValue - leftThresholdValue) / stepsNumber;
    double stepsSizeMiddleRight = (rightThresholdValue - middleThresholdValue) / stepsNumber;
    QLinearGradient plotAreaGradient;
    plotAreaGradient.setStart(QPointF(0, 0));
    plotAreaGradient.setFinalStop(QPointF(1, 0));

    plotAreaGradient.setColorAt(leftThresholdValue, ColorMap::valueToColor(0.0, colorMap));

    for (int i = 1; i < stepsNumber; ++i)
    {
        plotAreaGradient.setColorAt(leftThresholdValue + (stepsSizeLeftMiddle * i), ColorMap::valueToColor((double)i * (0.5 / (double)stepsNumber), colorMap));
        plotAreaGradient.setColorAt(middleThresholdValue + (stepsSizeMiddleRight * i), ColorMap::valueToColor((double)0.5 + (i * (0.5 / (double)stepsNumber)), colorMap));
    }
    plotAreaGradient.setColorAt(rightThresholdValue, ColorMap::valueToColor(1.0, colorMap));

    // Customize plot area background
    plotAreaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
    m_pChart->setPlotAreaBackgroundBrush(plotAreaGradient);
    m_pChart->setPlotAreaBackgroundVisible(true);
}

//=============================================================================================================

const QVector3D& Spline::getThreshold()
{
    QVector<QPointF> middlePoint = m_pMiddleThreshold->pointsVector();   //Point values need to be updated before tested and displayed on the widget
    QVector<QPointF> rightPoint = m_pRightThreshold->pointsVector();
    QVector<QPointF> leftPoint = m_pLeftThreshold->pointsVector();
    float emitLeft = leftPoint[0].x();
    float emitMiddle = middlePoint[0].x();
    float emitRight = rightPoint[0].x();
    QVector3D originalVector;
    originalVector.setX(emitLeft);
    originalVector.setY(emitMiddle);
    originalVector.setZ(emitRight);
    m_vecReturnVector = correctionDisplayTrueValue(originalVector, "down");
    return m_vecReturnVector;
}

//=============================================================================================================

QVector3D Spline::correctionDisplayTrueValue(QVector3D vecOriginalValues, QString upOrDown)
{
    QVector3D returnCorrectedVector;

    if(m_vecResultExponentValues.rows() > 0) {
        int exponent;
        if (upOrDown == "up")
        {
            if (m_vecResultExponentValues[0] < 0)
            {
                exponent = std::abs(m_vecResultExponentValues[0]);
            }
            else if (m_vecResultExponentValues[0] > 0)
            {
                exponent = -(std::abs(m_vecResultExponentValues[0]));
            }
            else
            {
                exponent = 0;
            }
        }
        else if (upOrDown == "down")
        {
            if (m_vecResultExponentValues[0] < 0)
            {
                exponent = -(std::abs(m_vecResultExponentValues[0]));
            }
            else if (m_vecResultExponentValues[0] > 0)
            {
                exponent = std::abs(m_vecResultExponentValues[0]);
            }
            else
            {
                exponent = 0;
            }
        }
        else
        {
            qDebug() << "Spline::correctionDisplayTrueValue error.";
        }

        returnCorrectedVector.setX(vecOriginalValues.x() * (pow(10, exponent)));
        returnCorrectedVector.setY(vecOriginalValues.y() * (pow(10, exponent)));
        returnCorrectedVector.setZ(vecOriginalValues.z() * (pow(10, exponent)));
    }

    return returnCorrectedVector;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

/*
    After installation of the OOo filter for the indexing service
    it is necessary to restart the indexing service in order to
    activate the filter. This is the most reliable way to get the
    indexing service working. We only restart the service if it is
    already running. If we have insufficient privileges to restart
    the service we do nothing.
*/

#ifdef _MSC_VER
#pragma warning(push, 1) /* disable warnings within system headers */
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <msiquery.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif

/*
    Advapi.dll needs to be loaded dynamically because the service
    control functions are not available under Windows 9x.
*/
typedef BOOL (__stdcall * CloseServiceHandle_t)(SC_HANDLE);
typedef BOOL (__stdcall * ControlService_t)(SC_HANDLE, DWORD, LPSERVICE_STATUS);
typedef SC_HANDLE (__stdcall * OpenSCManager_t)(LPCSTR, LPCSTR, DWORD);
typedef SC_HANDLE (__stdcall * OpenService_t)(SC_HANDLE, LPCSTR, DWORD);
typedef BOOL (__stdcall * QueryServiceStatus_t)(SC_HANDLE, LPSERVICE_STATUS);
typedef BOOL (__stdcall * StartService_t)(SC_HANDLE, DWORD, LPCSTR*);

CloseServiceHandle_t CloseServiceHandle_ = NULL;
ControlService_t ControlService_ = NULL;
OpenSCManager_t OpenSCManager_ = NULL;
OpenService_t OpenService_ = NULL;
QueryServiceStatus_t QueryServiceStatus_ = NULL;
StartService_t StartService_ = NULL;

const LPTSTR INDEXING_SERVICE_NAME = TEXT("cisvc");

bool StopIndexingService(SC_HANDLE hService)
{
    SERVICE_STATUS status;

    if (ControlService_(hService, SERVICE_CONTROL_STOP, &status))
    {
        // Check the status until the service is no longer stop pending.
        if (QueryServiceStatus_(hService, &status))
        {
            DWORD startTime = GetTickCount();
            DWORD oldCheckPoint = status.dwCheckPoint;

            while (status.dwCurrentState == SERVICE_STOP_PENDING)
            {
                // Do not wait longer than the wait hint. A good interval is
                // one tenth the wait hint, but no less than 1 second and no
                // more than 10 seconds.
                DWORD waitTime = status.dwWaitHint / 10;

                if (waitTime < 1000)
                    waitTime = 1000;
                else if (waitTime > 10000)
                    waitTime = 10000;

                Sleep(waitTime);

                // Check the status again.
                if (!QueryServiceStatus_(hService, &status) ||
                    (status.dwCurrentState == SERVICE_STOPPED))
                    break;

                if (status.dwCheckPoint > oldCheckPoint)
                {
                    startTime = GetTickCount();
                    oldCheckPoint = status.dwCheckPoint;
                }
                else if ((GetTickCount() - startTime) > status.dwWaitHint)
                {
                    break; // service doesn't react anymore
                }
            }
        }
    }
    return (status.dwCurrentState == SERVICE_STOPPED);
}

void StartIndexingService(SC_HANDLE hService)
{
    if (StartService_(hService, 0, NULL))
    {
        SERVICE_STATUS status;

        // Check the status until the service is no longer stop pending.
        if (QueryServiceStatus_(hService, &status))
        {
            DWORD startTime = GetTickCount();
            DWORD oldCheckPoint = status.dwCheckPoint;

            while (status.dwCurrentState == SERVICE_START_PENDING)
            {
                // Do not wait longer than the wait hint. A good interval is
                // one tenth the wait hint, but no less than 1 second and no
                // more than 10 seconds.
                DWORD waitTime = status.dwWaitHint / 10;

                if (waitTime < 1000)
                    waitTime = 1000;
                else if (waitTime > 10000)
                    waitTime = 10000;

                Sleep(waitTime);

                // Check the status again.
                if (!QueryServiceStatus_(hService, &status) ||
                    (status.dwCurrentState == SERVICE_STOPPED))
                    break;

                if (status.dwCheckPoint > oldCheckPoint)
                {
                    startTime = GetTickCount();
                    oldCheckPoint = status.dwCheckPoint;
                }
                else if ((GetTickCount() - startTime) > status.dwWaitHint)
                {
                    // service doesn't react anymore
                    break;
                }
            }
        }
    }
}

extern "C" UINT __stdcall RestartIndexingService(MSIHANDLE)
{
    //MessageBox(NULL, TEXT("Restarting Indexing Service"), TEXT("Message"), MB_OK | MB_ICONINFORMATION);

    HMODULE hAdvapi32 = LoadLibrary("advapi32.dll");

    if (hAdvapi32)
    {
        CloseServiceHandle_ = reinterpret_cast<CloseServiceHandle_t>(GetProcAddress(hAdvapi32, "CloseServiceHandle"));
        ControlService_ = reinterpret_cast<ControlService_t>(GetProcAddress(hAdvapi32, "ControlService"));
        OpenSCManager_ = reinterpret_cast<OpenSCManager_t>(GetProcAddress(hAdvapi32, "OpenSCManagerA"));
        OpenService_ = reinterpret_cast<OpenService_t>(GetProcAddress(hAdvapi32, "OpenServiceA"));
        QueryServiceStatus_ = reinterpret_cast<QueryServiceStatus_t>(GetProcAddress(hAdvapi32, "QueryServiceStatus"));
        StartService_ = reinterpret_cast<StartService_t>(GetProcAddress(hAdvapi32, "StartServiceA"));
    }

    /* On systems other than Windows 2000/XP the service API
       functions might not be available */
    if (!hAdvapi32 ||
        !(CloseServiceHandle_ && ControlService_ && OpenSCManager_ && OpenService_ && QueryServiceStatus_ && StartService_))
        return ERROR_SUCCESS;

    SC_HANDLE hSCManager = OpenSCManager_(
        NULL, // local machine
        NULL, // ServicesActive database
        SC_MANAGER_ALL_ACCESS);

    if (hSCManager != NULL)
    {
        SC_HANDLE hIndexingService = OpenService_(
            hSCManager, INDEXING_SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP);

        if (hIndexingService)
        {
            SERVICE_STATUS status;
            ZeroMemory(&status, sizeof(status));

            if (QueryServiceStatus_(hIndexingService, &status) &&
                (status.dwCurrentState == SERVICE_RUNNING))
            {
                if (StopIndexingService(hIndexingService))
                    StartIndexingService(hIndexingService);
            }
            CloseServiceHandle_(hIndexingService);
        }
        CloseServiceHandle_(hSCManager);
    }
    return ERROR_SUCCESS;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>WaE: deprecated conversion from string constant to 'LPTSTR'<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

/*
    After installation of the OOo filter for the indexing service
    it is necessary to restart the indexing service in order to
    activate the filter. This is the most reliable way to get the
    indexing service working. We only restart the service if it is
    already running. If we have insufficient privileges to restart
    the service we do nothing.
*/

#ifdef _MSC_VER
#pragma warning(push, 1) /* disable warnings within system headers */
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <msiquery.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif

/*
    Advapi.dll needs to be loaded dynamically because the service
    control functions are not available under Windows 9x.
*/
typedef BOOL (__stdcall * CloseServiceHandle_t)(SC_HANDLE);
typedef BOOL (__stdcall * ControlService_t)(SC_HANDLE, DWORD, LPSERVICE_STATUS);
typedef SC_HANDLE (__stdcall * OpenSCManager_t)(LPCSTR, LPCSTR, DWORD);
typedef SC_HANDLE (__stdcall * OpenService_t)(SC_HANDLE, LPCSTR, DWORD);
typedef BOOL (__stdcall * QueryServiceStatus_t)(SC_HANDLE, LPSERVICE_STATUS);
typedef BOOL (__stdcall * StartService_t)(SC_HANDLE, DWORD, LPCSTR*);

CloseServiceHandle_t CloseServiceHandle_ = NULL;
ControlService_t ControlService_ = NULL;
OpenSCManager_t OpenSCManager_ = NULL;
OpenService_t OpenService_ = NULL;
QueryServiceStatus_t QueryServiceStatus_ = NULL;
StartService_t StartService_ = NULL;

const TCHAR* const INDEXING_SERVICE_NAME = TEXT("cisvc");

bool StopIndexingService(SC_HANDLE hService)
{
    SERVICE_STATUS status;

    if (ControlService_(hService, SERVICE_CONTROL_STOP, &status))
    {
        // Check the status until the service is no longer stop pending.
        if (QueryServiceStatus_(hService, &status))
        {
            DWORD startTime = GetTickCount();
            DWORD oldCheckPoint = status.dwCheckPoint;

            while (status.dwCurrentState == SERVICE_STOP_PENDING)
            {
                // Do not wait longer than the wait hint. A good interval is
                // one tenth the wait hint, but no less than 1 second and no
                // more than 10 seconds.
                DWORD waitTime = status.dwWaitHint / 10;

                if (waitTime < 1000)
                    waitTime = 1000;
                else if (waitTime > 10000)
                    waitTime = 10000;

                Sleep(waitTime);

                // Check the status again.
                if (!QueryServiceStatus_(hService, &status) ||
                    (status.dwCurrentState == SERVICE_STOPPED))
                    break;

                if (status.dwCheckPoint > oldCheckPoint)
                {
                    startTime = GetTickCount();
                    oldCheckPoint = status.dwCheckPoint;
                }
                else if ((GetTickCount() - startTime) > status.dwWaitHint)
                {
                    break; // service doesn't react anymore
                }
            }
        }
    }
    return (status.dwCurrentState == SERVICE_STOPPED);
}

void StartIndexingService(SC_HANDLE hService)
{
    if (StartService_(hService, 0, NULL))
    {
        SERVICE_STATUS status;

        // Check the status until the service is no longer stop pending.
        if (QueryServiceStatus_(hService, &status))
        {
            DWORD startTime = GetTickCount();
            DWORD oldCheckPoint = status.dwCheckPoint;

            while (status.dwCurrentState == SERVICE_START_PENDING)
            {
                // Do not wait longer than the wait hint. A good interval is
                // one tenth the wait hint, but no less than 1 second and no
                // more than 10 seconds.
                DWORD waitTime = status.dwWaitHint / 10;

                if (waitTime < 1000)
                    waitTime = 1000;
                else if (waitTime > 10000)
                    waitTime = 10000;

                Sleep(waitTime);

                // Check the status again.
                if (!QueryServiceStatus_(hService, &status) ||
                    (status.dwCurrentState == SERVICE_STOPPED))
                    break;

                if (status.dwCheckPoint > oldCheckPoint)
                {
                    startTime = GetTickCount();
                    oldCheckPoint = status.dwCheckPoint;
                }
                else if ((GetTickCount() - startTime) > status.dwWaitHint)
                {
                    // service doesn't react anymore
                    break;
                }
            }
        }
    }
}

extern "C" UINT __stdcall RestartIndexingService(MSIHANDLE)
{
    //MessageBox(NULL, TEXT("Restarting Indexing Service"), TEXT("Message"), MB_OK | MB_ICONINFORMATION);

    HMODULE hAdvapi32 = LoadLibrary("advapi32.dll");

    if (hAdvapi32)
    {
        CloseServiceHandle_ = reinterpret_cast<CloseServiceHandle_t>(GetProcAddress(hAdvapi32, "CloseServiceHandle"));
        ControlService_ = reinterpret_cast<ControlService_t>(GetProcAddress(hAdvapi32, "ControlService"));
        OpenSCManager_ = reinterpret_cast<OpenSCManager_t>(GetProcAddress(hAdvapi32, "OpenSCManagerA"));
        OpenService_ = reinterpret_cast<OpenService_t>(GetProcAddress(hAdvapi32, "OpenServiceA"));
        QueryServiceStatus_ = reinterpret_cast<QueryServiceStatus_t>(GetProcAddress(hAdvapi32, "QueryServiceStatus"));
        StartService_ = reinterpret_cast<StartService_t>(GetProcAddress(hAdvapi32, "StartServiceA"));
    }

    /* On systems other than Windows 2000/XP the service API
       functions might not be available */
    if (!hAdvapi32 ||
        !(CloseServiceHandle_ && ControlService_ && OpenSCManager_ && OpenService_ && QueryServiceStatus_ && StartService_))
        return ERROR_SUCCESS;

    SC_HANDLE hSCManager = OpenSCManager_(
        NULL, // local machine
        NULL, // ServicesActive database
        SC_MANAGER_ALL_ACCESS);

    if (hSCManager != NULL)
    {
        SC_HANDLE hIndexingService = OpenService_(
            hSCManager, INDEXING_SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP);

        if (hIndexingService)
        {
            SERVICE_STATUS status;
            ZeroMemory(&status, sizeof(status));

            if (QueryServiceStatus_(hIndexingService, &status) &&
                (status.dwCurrentState == SERVICE_RUNNING))
            {
                if (StopIndexingService(hIndexingService))
                    StartIndexingService(hIndexingService);
            }
            CloseServiceHandle_(hIndexingService);
        }
        CloseServiceHandle_(hSCManager);
    }
    return ERROR_SUCCESS;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */

#include <cassert>
#include "stored-value.hh"

#ifndef DEFAULT_HT_SIZE
#define DEFAULT_HT_SIZE 12582917
#endif

#ifndef DEFAULT_MAX_DATA_SIZE
/* Something something something ought to be enough for anybody */
#define DEFAULT_MAX_DATA_SIZE (static_cast<size_t>(-1))
#endif

size_t HashTable::defaultNumBuckets = DEFAULT_HT_SIZE;
size_t HashTable::defaultNumLocks = 193;
enum stored_value_type HashTable::defaultStoredValueType = featured;

size_t StoredValue::maxDataSize = DEFAULT_MAX_DATA_SIZE;
Atomic<size_t> StoredValue::currentSize;

static inline size_t getDefault(size_t x, size_t d) {
    return x == 0 ? d : x;
}

/**
 * Get the number of buckets for a hash table.
 *
 * @param n the desired number of buckets, if 0, use the default
 *
 * @return the number of buckets to create
 */
size_t HashTable::getNumBuckets(size_t n = 0) {
    return getDefault(n, defaultNumBuckets);
}

/**
 * Get the number of locks for a hash table.
 *
 * @param n the desired number of locks, if 0, use the default
 *
 * @return the number of locks to create
 */
size_t HashTable::getNumLocks(size_t n = 0) {
    return getDefault(n, defaultNumLocks);
}

/**
 * Set the default number of hashtable buckets.
 */
void HashTable::setDefaultNumBuckets(size_t to) {
    if (to != 0) {
        defaultNumBuckets = to;
    }
}

/**
 * Set the default number of hashtable locks.
 */
void HashTable::setDefaultNumLocks(size_t to) {
    if (to != 0) {
        defaultNumLocks = to;
    }
}

size_t HashTable::clear(bool deactivate) {
    size_t rv = 0;

    if (!deactivate) {
        // If not deactivating, assert we're already active.
        assert(active());
    }
    MultiLockHolder(mutexes, n_locks);
    if (deactivate) {
        active(false);
    }
    for (int i = 0; i < (int)size; i++) {
        while (values[i]) {
            ++rv;
            StoredValue *v = values[i];
            values[i] = v->next;
            delete v;
        }
    }

    return rv;
}

void HashTable::visit(HashTableVisitor &visitor) {
    if (!active()) {
        return;
    }
    VisitorTracker vt(&visitors);
    bool aborted = !visitor.shouldContinue();
    size_t visited = 0;
    for (int l = 0; active() && !aborted && l < static_cast<int>(n_locks); l++) {
        LockHolder lh(getMutex(l));
        for (int i = l; i < static_cast<int>(size); i+= n_locks) {
            assert(l == mutexForBucket(i));
            StoredValue *v = values[i];
            while (v) {
                visitor.visit(v);
                v = v->next;
            }
            ++visited;
        }
        lh.unlock();
        aborted = !visitor.shouldContinue();
    }
    assert(aborted || visited == size);
}

void HashTable::visitDepth(HashTableDepthVisitor &visitor) {
    if (!active()) {
        return;
    }
    size_t visited = 0;
    VisitorTracker vt(&visitors);

    for (int l = 0; l < static_cast<int>(n_locks); l++) {
        LockHolder lh(getMutex(l));
        for (int i = l; i < static_cast<int>(size); i+= n_locks) {
            size_t depth = 0;
            StoredValue *p = values[i];
            while (p) {
                depth++;
                p = p->next;
            }
            visitor.visit(i, depth);
            ++visited;
        }
    }

    assert(visited == size);
}

bool HashTable::setDefaultStorageValueType(const char *t) {
    bool rv = false;
    if (t && strcmp(t, "featured") == 0) {
        setDefaultStorageValueType(featured);
        rv = true;
    } else if (t && strcmp(t, "small") == 0) {
        setDefaultStorageValueType(small);
        rv = true;
    }
    return rv;
}

void HashTable::setDefaultStorageValueType(enum stored_value_type t) {
    defaultStoredValueType = t;
}

enum stored_value_type HashTable::getDefaultStorageValueType() {
    return defaultStoredValueType;
}

const char* HashTable::getDefaultStorageValueTypeStr() {
    const char *rv = "unknown";
    switch(getDefaultStorageValueType()) {
    case small: rv = "small"; break;
    case featured: rv = "featured"; break;
    default: abort();
    }
    return rv;
}

/**
 * Get the maximum amount of memory available for storing data.
 *
 * @return the memory ceiling
 */
size_t StoredValue::getMaxDataSize() {
    return maxDataSize;
}

/**
 * Set the default number of bytes available for stored values.
 */
void StoredValue::setMaxDataSize(size_t to) {
    if (to != 0) {
        maxDataSize = to;
    }
}

/**
 * What's the total size of allocations?
 */
size_t StoredValue::getCurrentSize() {
    return currentSize.get();
}

void StoredValue::increaseCurrentSize(size_t by) {
    currentSize.incr(by);
}

void StoredValue::reduceCurrentSize(size_t by) {
    currentSize.decr(by);
    assert(static_cast<ssize_t>(getCurrentSize()) >= 0);
}

/**
 * Is there enough space for this thing?
 */
bool StoredValue::hasAvailableSpace(const Item &item) {
    return getCurrentSize() + sizeof(StoredValue) + item.getNKey() + item.getNBytes()
        <= getMaxDataSize();
}
<commit_msg>Refactor: increase debugability<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */

#include <cassert>
#include "stored-value.hh"

#ifndef DEFAULT_HT_SIZE
#define DEFAULT_HT_SIZE 12582917
#endif

#ifndef DEFAULT_MAX_DATA_SIZE
/* Something something something ought to be enough for anybody */
#define DEFAULT_MAX_DATA_SIZE (static_cast<size_t>(-1))
#endif

size_t HashTable::defaultNumBuckets = DEFAULT_HT_SIZE;
size_t HashTable::defaultNumLocks = 193;
enum stored_value_type HashTable::defaultStoredValueType = featured;

size_t StoredValue::maxDataSize = DEFAULT_MAX_DATA_SIZE;
Atomic<size_t> StoredValue::currentSize;

static inline size_t getDefault(size_t x, size_t d) {
    return x == 0 ? d : x;
}

/**
 * Get the number of buckets for a hash table.
 *
 * @param n the desired number of buckets, if 0, use the default
 *
 * @return the number of buckets to create
 */
size_t HashTable::getNumBuckets(size_t n = 0) {
    return getDefault(n, defaultNumBuckets);
}

/**
 * Get the number of locks for a hash table.
 *
 * @param n the desired number of locks, if 0, use the default
 *
 * @return the number of locks to create
 */
size_t HashTable::getNumLocks(size_t n = 0) {
    return getDefault(n, defaultNumLocks);
}

/**
 * Set the default number of hashtable buckets.
 */
void HashTable::setDefaultNumBuckets(size_t to) {
    if (to != 0) {
        defaultNumBuckets = to;
    }
}

/**
 * Set the default number of hashtable locks.
 */
void HashTable::setDefaultNumLocks(size_t to) {
    if (to != 0) {
        defaultNumLocks = to;
    }
}

size_t HashTable::clear(bool deactivate) {
    size_t rv = 0;

    if (!deactivate) {
        // If not deactivating, assert we're already active.
        assert(active());
    }
    MultiLockHolder(mutexes, n_locks);
    if (deactivate) {
        active(false);
    }
    for (int i = 0; i < (int)size; i++) {
        while (values[i]) {
            ++rv;
            StoredValue *v = values[i];
            values[i] = v->next;
            delete v;
        }
    }

    return rv;
}

void HashTable::visit(HashTableVisitor &visitor) {
    if (!active()) {
        return;
    }
    VisitorTracker vt(&visitors);
    bool aborted = !visitor.shouldContinue();
    size_t visited = 0;
    for (int l = 0; active() && !aborted && l < static_cast<int>(n_locks); l++) {
        LockHolder lh(getMutex(l));
        for (int i = l; i < static_cast<int>(size); i+= n_locks) {
            assert(l == mutexForBucket(i));
            StoredValue *v = values[i];
            while (v) {
                visitor.visit(v);
                v = v->next;
            }
            ++visited;
        }
        lh.unlock();
        aborted = !visitor.shouldContinue();
    }
    assert(aborted || visited == size);
}

void HashTable::visitDepth(HashTableDepthVisitor &visitor) {
    if (!active()) {
        return;
    }
    size_t visited = 0;
    VisitorTracker vt(&visitors);

    for (int l = 0; l < static_cast<int>(n_locks); l++) {
        LockHolder lh(getMutex(l));
        for (int i = l; i < static_cast<int>(size); i+= n_locks) {
            size_t depth = 0;
            StoredValue *p = values[i];
            while (p) {
                depth++;
                p = p->next;
            }
            visitor.visit(i, depth);
            ++visited;
        }
    }

    assert(visited == size);
}

bool HashTable::setDefaultStorageValueType(const char *t) {
    bool rv = false;
    if (t && strcmp(t, "featured") == 0) {
        setDefaultStorageValueType(featured);
        rv = true;
    } else if (t && strcmp(t, "small") == 0) {
        setDefaultStorageValueType(small);
        rv = true;
    }
    return rv;
}

void HashTable::setDefaultStorageValueType(enum stored_value_type t) {
    defaultStoredValueType = t;
}

enum stored_value_type HashTable::getDefaultStorageValueType() {
    return defaultStoredValueType;
}

const char* HashTable::getDefaultStorageValueTypeStr() {
    const char *rv = "unknown";
    switch(getDefaultStorageValueType()) {
    case small: rv = "small"; break;
    case featured: rv = "featured"; break;
    default: abort();
    }
    return rv;
}

/**
 * Get the maximum amount of memory available for storing data.
 *
 * @return the memory ceiling
 */
size_t StoredValue::getMaxDataSize() {
    return maxDataSize;
}

/**
 * Set the default number of bytes available for stored values.
 */
void StoredValue::setMaxDataSize(size_t to) {
    if (to != 0) {
        maxDataSize = to;
    }
}

/**
 * What's the total size of allocations?
 */
size_t StoredValue::getCurrentSize() {
    return currentSize.get();
}

void StoredValue::increaseCurrentSize(size_t by) {
    currentSize.incr(by);
}

void StoredValue::reduceCurrentSize(size_t by) {
    size_t val;

    do {
        val = currentSize.get();
        assert(val >= by);
    } while (!currentSize.cas(val, val - by));;
}

/**
 * Is there enough space for this thing?
 */
bool StoredValue::hasAvailableSpace(const Item &item) {
    return getCurrentSize() + sizeof(StoredValue) + item.getNKey() + item.getNBytes()
        <= getMaxDataSize();
}
<|endoftext|>