<commit_before>#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netdb.h>

#include <common/buffer.h>
#include <common/endian.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/file_descriptor.h>
#include <io/socket.h>

static bool socket_address(struct sockaddr_in *, int, const std::string&, uint16_t);

Socket::Socket(int fd, int domain)
: FileDescriptor(fd),
  log_("/socket"),
  domain_(domain),
  accept_action_(NULL),
  accept_callback_(NULL),
  connect_callback_(NULL),
  connect_action_(NULL)
{
	ASSERT(fd_ != -1);
}

Socket::~Socket()
{
	ASSERT(fd_ == -1);
	ASSERT(accept_action_ == NULL);
	ASSERT(accept_callback_ == NULL);
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);
}

Action *
Socket::accept(EventCallback *cb)
{
	ASSERT(accept_action_ == NULL);
	ASSERT(accept_callback_ == NULL);

	accept_callback_ = cb;
	accept_action_ = accept_schedule();
	return (cancellation(this, &Socket::accept_cancel));
}

bool
Socket::bind(const std::string& name, unsigned *portp)
{
	struct sockaddr_in bind_address;

	if (!socket_address(&bind_address, domain_, name, *portp))
		return (false);

	int rv = ::bind(fd_, (struct sockaddr *)&bind_address,
			sizeof bind_address);
	if (rv == -1)
		return (false);

	if (*portp == 0) {
		socklen_t addrlen = sizeof bind_address;
		rv = ::getsockname(fd_, (struct sockaddr *)&bind_address,
				   &addrlen);
		if (rv == -1 || addrlen != sizeof bind_address)
			return (false);
		ASSERT(bind_address.sin_family == domain_);
		*portp = ntohs(bind_address.sin_port);
	}

	return (true);
}

Action *
Socket::connect(const std::string& name, unsigned port, EventCallback *cb)
{
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);

	struct sockaddr_in connect_address;

	if (!socket_address(&connect_address, domain_, name, port)) {
		cb->event(Event(Event::Error, ENOENT));
		Action *a = EventSystem::instance()->schedule(cb);
		return (a);
	}

	return (this->connect(&connect_address, cb));
}

Action *
Socket::connect(uint32_t ip, uint16_t port, EventCallback *cb)
{
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);

	struct sockaddr_in connect_address;

	memset(&connect_address, 0, sizeof connect_address);
#if !defined(__linux__)
	connect_address.sin_len = sizeof connect_address;
#endif
	connect_address.sin_family = domain_;
	connect_address.sin_addr.s_addr = BigEndian::encode(ip);
	connect_address.sin_port = BigEndian::encode(port);

	return (this->connect(&connect_address, cb));
}

Action *
Socket::connect(struct sockaddr_in *sinp, EventCallback *cb)
{
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);

	int rv = ::connect(fd_, (struct sockaddr *)sinp, sizeof *sinp);
	switch (rv) {
	case 0:
		cb->event(Event(Event::Done, 0));
		connect_action_ = EventSystem::instance()->schedule(cb);
		break;
	case -1:
		switch (errno) {
		case EINPROGRESS:
			connect_callback_ = cb;
			connect_action_ = connect_schedule();
			break;
		default:
			cb->event(Event(Event::Error, errno));
			connect_action_ = EventSystem::instance()->schedule(cb);
			break;
		}
		break;
	default:
		HALT(log_) << "Connect returned " << errno;
	}
	return (cancellation(this, &Socket::connect_cancel));
}

bool
Socket::listen(int backlog)
{
	int rv = ::listen(fd_, backlog);
	if (rv == -1)
		return (false);
	return (true);
}

void
Socket::accept_callback(Event e, void *)
{
	accept_action_->cancel();
	accept_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	case Event::EOS:
	case Event::Error:
		accept_callback_->event(Event(Event::Error, e.error_));
		accept_action_ = EventSystem::instance()->schedule(accept_callback_);
		accept_callback_ = NULL;
		return;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	int s = ::accept(fd_, NULL, NULL);
	if (s == -1) {
		switch (errno) {
		case EAGAIN:
			accept_action_ = accept_schedule();
			return;
		default:
			accept_callback_->event(Event(Event::Error, e.error_));
			accept_action_ = EventSystem::instance()->schedule(accept_callback_);
			accept_callback_ = NULL;
			return;
		}
	}

	Socket *child = new Socket(s, domain_);
	accept_callback_->event(Event(Event::Done, 0, (void *)child));
	Action *a = EventSystem::instance()->schedule(accept_callback_);
	accept_action_ = a;
	accept_callback_ = NULL;
}

void
Socket::accept_cancel(void)
{
	ASSERT(accept_action_ != NULL);
	accept_action_->cancel();
	accept_action_ = NULL;

	if (accept_callback_ != NULL) {
		delete accept_callback_;
		accept_callback_ = NULL;
	}
}

Action *
Socket::accept_schedule(void)
{
	EventCallback *cb = callback(this, &Socket::accept_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Readable, fd_, cb);
	return (a);
}

void
Socket::connect_callback(Event e, void *)
{
	connect_action_->cancel();
	connect_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		connect_callback_->event(Event(Event::Done, 0));
		break;
	case Event::EOS:
	case Event::Error:
		connect_callback_->event(Event(Event::Error, e.error_));
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}
	Action *a = EventSystem::instance()->schedule(connect_callback_);
	connect_action_ = a;
	connect_callback_ = NULL;
}

void
Socket::connect_cancel(void)
{
	ASSERT(connect_action_ != NULL);
	connect_action_->cancel();
	connect_action_ = NULL;

	if (connect_callback_ != NULL) {
		delete connect_callback_;
		connect_callback_ = NULL;
	}
}

Action *
Socket::connect_schedule(void)
{
	EventCallback *cb = callback(this, &Socket::connect_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Writable, fd_, cb);
	return (a);
}

Socket *
Socket::create(int domain, int type, const std::string& protocol)
{
	struct protoent *proto = getprotobyname(protocol.c_str());
	if (proto == NULL)
		HALT("/socket") << "Invalid protocol: " << protocol;

	int s = ::socket(domain, type, proto->p_proto);
	if (s == -1)
		return (NULL);

	return (new Socket(s, domain));
}

static bool
socket_address(struct sockaddr_in *sinp, int domain, const std::string& name,
	       uint16_t port)
{
	struct hostent *host = gethostbyname(name.c_str());
	if (host == NULL) {
		return (false);
	}
	ASSERT(host->h_addrtype == domain);
	ASSERT(host->h_length == sizeof sinp->sin_addr);

	memset(sinp, 0, sizeof *sinp);
#if !defined(__linux__)
	sinp->sin_len = sizeof *sinp;
#endif
	sinp->sin_family = domain;
	memcpy(&sinp->sin_addr, host->h_addr_list[0], sizeof sinp->sin_addr);
	sinp->sin_port = htons(port);
	return (true);
}
<commit_msg>Pass errno when accept fails.<commit_after>#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netdb.h>

#include <common/buffer.h>
#include <common/endian.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/file_descriptor.h>
#include <io/socket.h>

static bool socket_address(struct sockaddr_in *, int, const std::string&, uint16_t);

Socket::Socket(int fd, int domain)
: FileDescriptor(fd),
  log_("/socket"),
  domain_(domain),
  accept_action_(NULL),
  accept_callback_(NULL),
  connect_callback_(NULL),
  connect_action_(NULL)
{
	ASSERT(fd_ != -1);
}

Socket::~Socket()
{
	ASSERT(fd_ == -1);
	ASSERT(accept_action_ == NULL);
	ASSERT(accept_callback_ == NULL);
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);
}

Action *
Socket::accept(EventCallback *cb)
{
	ASSERT(accept_action_ == NULL);
	ASSERT(accept_callback_ == NULL);

	accept_callback_ = cb;
	accept_action_ = accept_schedule();
	return (cancellation(this, &Socket::accept_cancel));
}

bool
Socket::bind(const std::string& name, unsigned *portp)
{
	struct sockaddr_in bind_address;

	if (!socket_address(&bind_address, domain_, name, *portp))
		return (false);

	int rv = ::bind(fd_, (struct sockaddr *)&bind_address,
			sizeof bind_address);
	if (rv == -1)
		return (false);

	if (*portp == 0) {
		socklen_t addrlen = sizeof bind_address;
		rv = ::getsockname(fd_, (struct sockaddr *)&bind_address,
				   &addrlen);
		if (rv == -1 || addrlen != sizeof bind_address)
			return (false);
		ASSERT(bind_address.sin_family == domain_);
		*portp = ntohs(bind_address.sin_port);
	}

	return (true);
}

Action *
Socket::connect(const std::string& name, unsigned port, EventCallback *cb)
{
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);

	struct sockaddr_in connect_address;

	if (!socket_address(&connect_address, domain_, name, port)) {
		cb->event(Event(Event::Error, ENOENT));
		Action *a = EventSystem::instance()->schedule(cb);
		return (a);
	}

	return (this->connect(&connect_address, cb));
}

Action *
Socket::connect(uint32_t ip, uint16_t port, EventCallback *cb)
{
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);

	struct sockaddr_in connect_address;

	memset(&connect_address, 0, sizeof connect_address);
#if !defined(__linux__)
	connect_address.sin_len = sizeof connect_address;
#endif
	connect_address.sin_family = domain_;
	connect_address.sin_addr.s_addr = BigEndian::encode(ip);
	connect_address.sin_port = BigEndian::encode(port);

	return (this->connect(&connect_address, cb));
}

Action *
Socket::connect(struct sockaddr_in *sinp, EventCallback *cb)
{
	ASSERT(connect_callback_ == NULL);
	ASSERT(connect_action_ == NULL);

	int rv = ::connect(fd_, (struct sockaddr *)sinp, sizeof *sinp);
	switch (rv) {
	case 0:
		cb->event(Event(Event::Done, 0));
		connect_action_ = EventSystem::instance()->schedule(cb);
		break;
	case -1:
		switch (errno) {
		case EINPROGRESS:
			connect_callback_ = cb;
			connect_action_ = connect_schedule();
			break;
		default:
			cb->event(Event(Event::Error, errno));
			connect_action_ = EventSystem::instance()->schedule(cb);
			break;
		}
		break;
	default:
		HALT(log_) << "Connect returned " << errno;
	}
	return (cancellation(this, &Socket::connect_cancel));
}

bool
Socket::listen(int backlog)
{
	int rv = ::listen(fd_, backlog);
	if (rv == -1)
		return (false);
	return (true);
}

void
Socket::accept_callback(Event e, void *)
{
	accept_action_->cancel();
	accept_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	case Event::EOS:
	case Event::Error:
		accept_callback_->event(Event(Event::Error, e.error_));
		accept_action_ = EventSystem::instance()->schedule(accept_callback_);
		accept_callback_ = NULL;
		return;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	int s = ::accept(fd_, NULL, NULL);
	if (s == -1) {
		switch (errno) {
		case EAGAIN:
			accept_action_ = accept_schedule();
			return;
		default:
			accept_callback_->event(Event(Event::Error, errno));
			accept_action_ = EventSystem::instance()->schedule(accept_callback_);
			accept_callback_ = NULL;
			return;
		}
	}

	Socket *child = new Socket(s, domain_);
	accept_callback_->event(Event(Event::Done, 0, (void *)child));
	Action *a = EventSystem::instance()->schedule(accept_callback_);
	accept_action_ = a;
	accept_callback_ = NULL;
}

void
Socket::accept_cancel(void)
{
	ASSERT(accept_action_ != NULL);
	accept_action_->cancel();
	accept_action_ = NULL;

	if (accept_callback_ != NULL) {
		delete accept_callback_;
		accept_callback_ = NULL;
	}
}

Action *
Socket::accept_schedule(void)
{
	EventCallback *cb = callback(this, &Socket::accept_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Readable, fd_, cb);
	return (a);
}

void
Socket::connect_callback(Event e, void *)
{
	connect_action_->cancel();
	connect_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		connect_callback_->event(Event(Event::Done, 0));
		break;
	case Event::EOS:
	case Event::Error:
		connect_callback_->event(Event(Event::Error, e.error_));
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}
	Action *a = EventSystem::instance()->schedule(connect_callback_);
	connect_action_ = a;
	connect_callback_ = NULL;
}

void
Socket::connect_cancel(void)
{
	ASSERT(connect_action_ != NULL);
	connect_action_->cancel();
	connect_action_ = NULL;

	if (connect_callback_ != NULL) {
		delete connect_callback_;
		connect_callback_ = NULL;
	}
}

Action *
Socket::connect_schedule(void)
{
	EventCallback *cb = callback(this, &Socket::connect_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Writable, fd_, cb);
	return (a);
}

Socket *
Socket::create(int domain, int type, const std::string& protocol)
{
	struct protoent *proto = getprotobyname(protocol.c_str());
	if (proto == NULL)
		HALT("/socket") << "Invalid protocol: " << protocol;

	int s = ::socket(domain, type, proto->p_proto);
	if (s == -1)
		return (NULL);

	return (new Socket(s, domain));
}

static bool
socket_address(struct sockaddr_in *sinp, int domain, const std::string& name,
	       uint16_t port)
{
	struct hostent *host = gethostbyname(name.c_str());
	if (host == NULL) {
		return (false);
	}
	ASSERT(host->h_addrtype == domain);
	ASSERT(host->h_length == sizeof sinp->sin_addr);

	memset(sinp, 0, sizeof *sinp);
#if !defined(__linux__)
	sinp->sin_len = sizeof *sinp;
#endif
	sinp->sin_family = domain;
	memcpy(&sinp->sin_addr, host->h_addr_list[0], sizeof sinp->sin_addr);
	sinp->sin_port = htons(port);
	return (true);
}
<|endoftext|>


<commit_before>
#ifndef MANAGER_HPP_
#define MANAGER_HPP_

#include <iostream>

#include <vector>			 // vector
#include <random>            // mt19937, uniform_int_distribution, random_device

#include <utility>			 // make_pair

#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/atomic.hpp>

#include "Chromosome.hpp"
#include "RouletteWheel.hpp"
#include "Result.hpp"

#include "SafeQueue.hpp"

template <class T>
class Manager {
protected:

	unsigned int population_size;
	unsigned int chromosome_size;

	unsigned int max_generation_number;

	T max_chromosome_value;
	T min_chromosome_value;

	bool use_self_adaptive;
	double mutation_rate;
	double mutation_change_rate;
	double similarity_index;

	double crossover_rate;

	std::vector<Chromosome<T> > population;

	// Need to have some way of ensure no duplication of solutions
	std::vector<Chromosome<T> > solutions;

	RouletteWheel rw;

	//boost::lockfree::queue<Result > result_queue;
	//boost::lockfree::queue<unsigned int> safe_queue;
	SafeQueue<unsigned int> safe_queue;
	SafeQueue<Result > result_queue;

	boost::thread_group fitness_group;

	std::mt19937 rand_engine;
	std::uniform_real_distribution<float> op_dist;
	std::uniform_real_distribution<float> mutation_dist;
	//std::uniform_int_distribution<int> chrom_dist;

	// With this we can limit the number of threads used
	unsigned int num_threads_used;
	unsigned int max_num_threads;

	// Library flags
	//int number_of_threads = 5;
	boost::atomic<bool> done;
	boost::atomic<bool> waiting;

	boost::condition_variable m_cond;
	boost::mutex mtx_;

	// Fitness function
	double (*fitness_function)(Chromosome<T>);

public:

    // TODO this should take a configuration struct/object that has a lot of default parameters
	/**
	 * Create a manager for GA.
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param use_self_adaptive Whether to use a self adaptive approach. If this is true
	 * then the mutation rate will be updated based on the similarity of the population.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param mutation_change_rate The rate by which the mutation rate will be updated.
	 * If use_self_adaptive is set to false then this parameter is ignored.
	 * @param similarity_index The threshold at which the similarity mutation rate is
	 * updated.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param cloning_rate The cloning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
			T max_chromosome_value, T min_chromosome_value, bool use_self_adaptive,
			double mutation_rate, double mutation_change_rate, double similarity_index,
			double crossover_rate, unsigned int num_threads) : population_size(population_size),
			chromosome_size(chromosome_size), max_generation_number(max_generation_number),
			max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
			use_self_adaptive(use_self_adaptive), mutation_rate(mutation_rate),
			mutation_change_rate(mutation_change_rate), similarity_index(similarity_index),
			crossover_rate(crossover_rate), max_num_threads(num_threads)//, safe_queue(population_size),
			//result_queue(population_size)
			{
		population = std::vector<Chromosome<T > >(population_size);
		initialize();
	}

    // TODO this should take a configuration struct/object that has a lot of default parameters
	/**
	 * Create a non self-adaptive GA manager
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param cloning_rate The cloning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
				T max_chromosome_value, T min_chromosome_value, double mutation_rate,
				double crossover_rate, unsigned int num_threads) : population_size(population_size),
				chromosome_size(chromosome_size), max_generation_number(max_generation_number),
				max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
				use_self_adaptive(false), mutation_rate(mutation_rate), mutation_change_rate(0),
				similarity_index(0), crossover_rate(crossover_rate), population(population_size),
				max_num_threads(num_threads){

		initialize();

	}

	~Manager() {

        // TODO if object no longer exists what does finished do?
		//finished = true;
		//safe_queue.finish(threadpool.size());
	}

    /**
	 * Run the algorithm for the specificed number of generations
	 */
	void run(double (*fitness_function)(Chromosome<T>)) {
		this->fitness_function = fitness_function;

		initPopulation();

		for(unsigned int i = 0; i < max_generation_number; i++) {
			std::cout << "Generation " << i << std::endl;
			runGeneration();
		}

		done = true;
		m_cond.notify_all();

		//TODO remove
		safe_queue.finish();
		//result_queue.finish();

		fitness_group.join_all();

	}

    // TODO make this private (after testing)
	/**
	 * Prepare the population for the next generation by apply the genetic operations.
	 */
	void breed(std::vector<Result > &fitness) {
		std::vector<Chromosome<T> > new_population;

		//std::cout << "Breeding" << std::endl;
		rw.init(fitness);

		// Iterate through the chromosomes
		while(new_population.size() < population_size) {
			// Use a random number between to identify which operation to apply (each operation gets a slice of the range)
			float selected_operation = op_dist(rand_engine);
			unsigned int selected_chromosome = rw.next();

			if(selected_operation <= crossover_rate) {
				// Crossover
				unsigned int other_selected_chromosome = rw.next();

				// This was the cause of the slow down!
				/*while(other_selected_chromosome == selected_chromosome) {
					other_selected_chromosome = rw.next();
				}*/

				// If the chromosome selected are the same than there is no point apply the crossover.
				if(other_selected_chromosome != selected_chromosome) {
					population[selected_chromosome].crossover(population[other_selected_chromosome], new_population);
				} else {
					population[selected_chromosome].cloning(new_population);
					population[other_selected_chromosome].cloning(new_population);
				}

				// Mutate the second chromosome in the crossover
				mutate((*(new_population.end() - 2)));

				// Handle the case where the new_population.size() -1 == popluation size and then crossover is selected.
				if(new_population.size() == population_size+1) {
					new_population.pop_back();
				}
			}
			else {
				// Clone
                population[selected_chromosome].cloning(new_population);
			}

			// Mutate the chromosome
			mutate(new_population.back());

		}

		// Update the population to the new population
		population = new_population; // Check if this creates a shallow copy (since we aren't going to change new_population so we just want it to be deallocated at the end of the method).

	}

	/**
 	 * Apply the self-adaptive operation to determine the similarity of the chromosomes
	 * and update the mutation rate accordingly.
	 *
	 * This might be best fit to have 1 thread designated for it (and if more are available use more).
	 * Since the fitness function is most likely the longest process, if we complete the fitness functions
	 * concurrently and then to the selfadaptive (which is a sort and then a comparison) nlogn + n. So by
	 * doing as many fitness function calls (available_threads - 2, 1 for self adaptive and 1 for fitness
	 * function manager) we can then call self adaptive as well and and therefore if the fitness functions
	 * take a long time to execute (or pop_size > available_threads - 2) then we will execute some fitness
	 * function but will actual finish the self adaptive. This means we wont be doing do all fitness functions
	 * then self adaptive (aka approx. fitness function execution time * pop_size/(available_threads - 1) + (self adaptive execution time)) rather we'll
	 * do (some) fitness functions and self adaptive and then remaining as threads become available (approx. fitness function execution * pop_size - 1 / (available_threads - 2) + .
	 */
	void selfAdapt() {
		// Determine how similar the chromosome is to the rest of the population

		// Sequencial solution
		// Iterate through the chromosomes
			// Calculate the current chromosome with each of the others in the population

		// Based on the similarity of the population identify adjust the mutaiton rate
			//if the similarity is too high (above threshold), increase mutation rate
			//if similarity is too low (below threshold), decrease mutation rate
			//otherwise (same as threshold), do nothing
	}

	/**
	 * Apply the self adaptive function.
	 * @param param The manager class.
	 */
	/*static void *applySelfAdaptive(void *param) {
		if(param != NULL) {
			Manager * m = (Manager *) param;
			while(true) {
				pthread_mutex_lock(&m->self_adapt_lock);
				pthread_cond_wait(&m->self_adapt_wait, &m->self_adapt_lock);
				pthread_mutex_unlock(&m->self_adapt_lock);

				if(m->finished) {
					break;
				}

				m->selfAdapt();

				// proceed with calculating some fitness functions
			}

		}
		return NULL;
	}*/

	/**
	 * Get another chromosome and apply the fitness function.
	 * @param param The manager the thread is running for.
	 */
	static void calcFitnessFunction(void *param, unsigned int start_index, unsigned int problem_size) {
		if(param != NULL) {
			Manager * m = (Manager *) param;
			unsigned int problem_index;

			//std::vector<unsigned int > indexes;
			std::vector<Result > results;
			while(!m->done) {

				if(m->wait_for_work()) {
					break;
				}

				//bool value = ;
				//if(m->safe_queue.pop(problem_size, indexes)) {
					//std::cout << "Grabbing a Chromosome " << std::endl;
					// Can we trust the user to not change the chromosome? No.

					for(unsigned int i = 0; i < problem_size; i++) {
						// TODO loop through the grabbed indexes and apply them
						Chromosome<T> t = m->population[start_index+i];

						results.push_back(Result(start_index+i, m->fitness_function(t)));
					}

					//std::pair<unsigned int, double >temp (problem_index, m->fitness_function(t));
					//Result r = Result(problem_index, m->fitness_function(t));
					m->result_queue.push(results);

					// Store them in results;
				//}

				//indexes.clear();
				results.clear();
			}
		}
	}

    // TODO make this private (after testing)
	/**
	 * Create an initial population of random chromosomes.
	 */
	void initPopulation() {
		Chromosome<unsigned int>::initPopulation(this->population, this->population_size, this->chromosome_size);
	}

    /**
	 * Returns the population size specified for the manager class.
     * @return The population size
     */
	unsigned int size() {
		return this->population_size;
	}

    /**
     * Returns the entire chromosome population.
     * @return The chromosome population
     */
	std::vector<Chromosome<T> > getPopulation() {
		return this->population;
	}

private:

	bool wait_for_work() {
		boost::unique_lock<boost::mutex> lock(mtx_);
		if(!done) {
			if(!waiting) {
				m_cond.wait(lock);
			}
		}
		else {
			return true;
		}
		return false;
	}

	void set_waiting(bool val){
		boost::unique_lock<boost::mutex> guard(mtx_);
		waiting = val;
	}

	/**
	 * Setup the necessary variables for genetic algorithm.
	 */
	void initialize() {
		// Create the random objects that will be used
		std::random_device rd;
		rand_engine = std::mt19937(rd());
		op_dist = std::uniform_real_distribution<float>(0.0, 1.0);
		mutation_dist = std::uniform_real_distribution<float>(0.0, 1.0);
		Chromosome<T>::initialize(chromosome_size, min_chromosome_value, max_chromosome_value);
		done = false;

		int problem_size = population_size/max_num_threads;
		int count = 0;

		// Create the number of threads requested. If we are using self adaptive we will require 1 thread for the self adaptive
		for(unsigned int i = 0; i < max_num_threads; i++) {

			if (i+1 == max_num_threads && population_size % max_num_threads != 0) {

				// Handle the case where the problem_size does not evenly divide by the
				// number of threads available. Last thread receives remainder.
				// This is not the best solution but is passible.
				problem_size = population_size % max_num_threads;
			}

			//pthread_create(&threadpool.back(), 0, calcFitnessFunction, (void *) this);
			fitness_group.create_thread(boost::bind(calcFitnessFunction, (void *) this, count, problem_size));
			count+= problem_size;

			// TODO decide if this is useful
			//this->num_threads_used++;
		}

		/*
		if(use_self_adaptive) {
			pthread_mutex_init(&self_adapt_lock, 0);
			pthread_cond_init(&self_adapt_wait, 0);

			pthread_t self_adapt;
			pthread_create(&self_adapt, 0, applySelfAdaptive, (void *)this);
		}*/
	}

	/**
	 * Mutate the given chromosome on the likelihood of the mutation rate.
	 * @param chromosome The chromosome to mutate.
	 */
	void mutate(Chromosome<T > &chromosome) {
		if(mutation_dist(rand_engine) <= mutation_rate) {
			chromosome.mutate();
		}
	}

	/**
	 * Apply the fitness function to the population. Given the result of the
	 * fitness function, the next population is bred.
	 *
	 * There are several approaches we could take to mapping the number of available threads to the problems:
	 * Each thread is given a problem to solve and will pull off another problem once it is finished.
	 * 	- Adv. Can effectively balance the load
	 * 	- Adv. Easy to implement (with shared memory which threads have).
	 * 	- Dis. Requires more communication
	 * 	- Dis. Requires a manager thread
	 */
	void runGeneration() {

		set_waiting(true);
		m_cond.notify_all();

		// For each thread push the problems
		/*for(unsigned int i = 0; i < this->max_num_threads; i++) {
			// Push on the index for each chromosome in the population.
			//std::cout << "Pushing population value " << i << std::endl;

		// Could push a set of values into the queue (each threads work set).
			safe_queue.push(i);
		}*/
		// Could potentially have a second generic method that you could use to apply heuristics to a found solution.
			// eg; in N-Queens you can rotate the board in order to find more solutions.

		// Can be done concurrently with the fitness function
		/*if(use_self_adaptive) {
				// Create a thread to handle selfAdapt()
				pthread_mutex_lock(&self_adapt_lock);
				pthread_cond_signal(&self_adapt_wait);
				pthread_mutex_unlock(&self_adapt_lock);
		}*/

		//fitness_group.join_all();

		// Main thread will wait for all children to finish executing before proceeding.
		// Construct the list of results for the fitness function in a map which maps the chromosome's index to the chromosome's fitness value.
		std::vector<Result >fitness_results;

		// Wait for all the chromosomes to finish calculating their fitness value.
		std::vector<Result > results;
		while(fitness_results.size() < population_size) {
			while(result_queue.popAll(results, false)) {

				for(unsigned int i = 0; i < results.size(); i++) {
					fitness_results.push_back(results[i]);
				}
				results.clear();
				//TODO add results to solutions.
			}
		}

		set_waiting(false);

		breed(fitness_results);//*/
	}
};

#endif /* MANAGER_HPP_ */
<commit_msg>Cleaned up some of the documentation and method visibility<commit_after>
#ifndef MANAGER_HPP_
#define MANAGER_HPP_

#include <iostream>

#include <vector>			 // vector
#include <random>            // mt19937, uniform_int_distribution, random_device

#include <utility>			 // make_pair

#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/atomic.hpp>

#include "Chromosome.hpp"
#include "RouletteWheel.hpp"
#include "Result.hpp"

#include "SafeQueue.hpp"

template <class T>
class Manager {
protected:

	unsigned int population_size;
	unsigned int chromosome_size;

	unsigned int max_generation_number;

	T max_chromosome_value;
	T min_chromosome_value;

	bool use_self_adaptive;
	double mutation_rate;
	double mutation_change_rate;
	double similarity_index;

	double crossover_rate;

	std::vector<Chromosome<T> > population;

	// Need to have some way of ensure no duplication of solutions
	std::vector<Chromosome<T> > solutions;

	RouletteWheel rw;

	//SafeQueue<unsigned int> safe_queue;
	SafeQueue<Result > result_queue;

	boost::thread_group fitness_group;

	std::mt19937 rand_engine;
	std::uniform_real_distribution<float> op_dist;
	std::uniform_real_distribution<float> mutation_dist;
	//std::uniform_int_distribution<int> chrom_dist;

	// With this we can limit the number of threads used
	unsigned int num_threads_used;
	unsigned int max_num_threads;

	// Library flags
	//int number_of_threads = 5;
	boost::atomic<bool> done;
	boost::atomic<bool> waiting;

	boost::condition_variable m_cond;
	boost::mutex mtx_;

	// Fitness function
	double (*fitness_function)(Chromosome<T>);

public:

    // TODO this should take a configuration struct/object that has a lot of default parameters
	/**
	 * Create a manager for GA.
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param use_self_adaptive Whether to use a self adaptive approach. If this is true
	 * then the mutation rate will be updated based on the similarity of the population.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param mutation_change_rate The rate by which the mutation rate will be updated.
	 * If use_self_adaptive is set to false then this parameter is ignored.
	 * @param similarity_index The threshold at which the similarity mutation rate is
	 * updated.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param cloning_rate The cloning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
			T max_chromosome_value, T min_chromosome_value, bool use_self_adaptive,
			double mutation_rate, double mutation_change_rate, double similarity_index,
			double crossover_rate, unsigned int num_threads) : population_size(population_size),
			chromosome_size(chromosome_size), max_generation_number(max_generation_number),
			max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
			use_self_adaptive(use_self_adaptive), mutation_rate(mutation_rate),
			mutation_change_rate(mutation_change_rate), similarity_index(similarity_index),
			crossover_rate(crossover_rate), max_num_threads(num_threads)//, safe_queue(population_size),
			//result_queue(population_size)
			{
		population = std::vector<Chromosome<T > >(population_size);
		initialize();
	}

    // TODO this should take a configuration struct/object that has a lot of default parameters
	/**
	 * Create a non self-adaptive GA manager
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param cloning_rate The cloning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
				T max_chromosome_value, T min_chromosome_value, double mutation_rate,
				double crossover_rate, unsigned int num_threads) : population_size(population_size),
				chromosome_size(chromosome_size), max_generation_number(max_generation_number),
				max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
				use_self_adaptive(false), mutation_rate(mutation_rate), mutation_change_rate(0),
				similarity_index(0), crossover_rate(crossover_rate), population(population_size),
				max_num_threads(num_threads){

		initialize();

	}

	~Manager() {

	}

    /**
	 * Run the algorithm for the specificed number of generations
	 */
	void run(double (*fitness_function)(Chromosome<T>)) {
		this->fitness_function = fitness_function;

		initPopulation();

		for(unsigned int i = 0; i < max_generation_number; i++) {
			//std::cout << "Generation " << i << std::endl;
			runGeneration();
		}

		done = true;
		m_cond.notify_all();

		//TODO remove
		//safe_queue.finish();
		//result_queue.finish();

		fitness_group.join_all();

	}

	/**
	 * Get another chromosome and apply the fitness function.
	 * @param param The manager the thread is running for.
	 */
	static void calcFitnessFunction(void *param, unsigned int start_index, unsigned int problem_size) {
		if(param != NULL) {
			Manager * m = (Manager *) param;
			unsigned int problem_index;

			std::vector<Result > results;
			while(!m->done) {

				if(m->wait_for_work()) {
					break;
				}

				// Can we trust the user to not change the chromosome? No.
				for(unsigned int i = 0; i < problem_size; i++) {

					Chromosome<T> t = m->population[start_index+i];

					results.push_back(Result(start_index+i, m->fitness_function(t)));
				}

				// Store them in results
				m->result_queue.push(results);

				results.clear();

				//TODO consider a barrier to make all the threads wait until all other threads are complete and then apply breeding in the threads.
			}
		}
	}

    // TODO make this private (after testing)
	/**
	 * Create an initial population of random chromosomes.
	 */
	void initPopulation() {
		Chromosome<unsigned int>::initPopulation(this->population, this->population_size, this->chromosome_size);
	}

    /**
	 * Returns the population size specified for the manager class.
     * @return The population size
     */
	unsigned int size() {
		return this->population_size;
	}

    /**
     * Returns the entire chromosome population.
     * @return The chromosome population
     */
	std::vector<Chromosome<T> > getPopulation() {
		return this->population;
	}

private:

	bool wait_for_work() {
		boost::unique_lock<boost::mutex> lock(mtx_);
		if(!done) {
			if(!waiting) {
				m_cond.wait(lock);
			}
		}
		else {
			return true;
		}
		return false;
	}

	void set_waiting(bool val){
		boost::unique_lock<boost::mutex> guard(mtx_);
		waiting = val;
	}

	/**
	 * Setup the necessary variables for genetic algorithm.
	 */
	void initialize() {
		// Create the random objects that will be used
		std::random_device rd;
		rand_engine = std::mt19937(rd());
		op_dist = std::uniform_real_distribution<float>(0.0, 1.0);
		mutation_dist = std::uniform_real_distribution<float>(0.0, 1.0);
		Chromosome<T>::initialize(chromosome_size, min_chromosome_value, max_chromosome_value);
		done = false;

		int problem_size = population_size/max_num_threads;
		int count = 0;

		// Create the number of threads requested. If we are using self adaptive we will require 1 thread for the self adaptive
		for(unsigned int i = 0; i < max_num_threads; i++) {

			if (i+1 == max_num_threads && population_size % max_num_threads != 0) {

				// Handle the case where the problem_size does not evenly divide by the
				// number of threads available. Last thread receives remainder.
				// This is not the best solution but is passible.
				problem_size = population_size % max_num_threads;
			}

			//pthread_create(&threadpool.back(), 0, calcFitnessFunction, (void *) this);
			fitness_group.create_thread(boost::bind(calcFitnessFunction, (void *) this, count, problem_size));
			count+= problem_size;
		}
	}

	/**
	 * Mutate the given chromosome on the likelihood of the mutation rate.
	 * @param chromosome The chromosome to mutate.
	 */
	void mutate(Chromosome<T > &chromosome) {
		if(mutation_dist(rand_engine) <= mutation_rate) {
			chromosome.mutate();
		}
	}

	/**
	 * Apply the fitness function to the population. Given the result of the
	 * fitness function, the next population is bred.
	 */
	void runGeneration() {

		set_waiting(true);
		m_cond.notify_all();

		// Main thread will wait for all children to finish executing before proceeding.
		// Construct the list of results for the fitness function in a map which maps the chromosome's index to the chromosome's fitness value.
		std::vector<Result >fitness_results;

		// Wait for all the chromosomes to finish calculating their fitness value.
		std::vector<Result > results;
		while(fitness_results.size() < population_size) {
			while(result_queue.popAll(results, false)) {

				for(unsigned int i = 0; i < results.size(); i++) {
					fitness_results.push_back(results[i]);
				}
				results.clear();
				//TODO add results to solutions.
			}
		}

		set_waiting(false);

		breed(fitness_results);
	}

	/**
	 * Prepare the population for the next generation by apply the genetic operations.
	 */
	void breed(std::vector<Result > &fitness) {
		std::vector<Chromosome<T> > new_population;

		//std::cout << "Breeding" << std::endl;
		rw.init(fitness);

		// Iterate through the chromosomes
		while(new_population.size() < population_size) {
			// Use a random number between to identify which operation to apply (each operation gets a slice of the range)
			float selected_operation = op_dist(rand_engine);
			unsigned int selected_chromosome = rw.next();

			if(selected_operation <= crossover_rate) {
				// Crossover
				unsigned int other_selected_chromosome = rw.next();

				// If the chromosome selected are the same than there is no point apply the crossover.
				if(other_selected_chromosome != selected_chromosome) {
					population[selected_chromosome].crossover(population[other_selected_chromosome], new_population);
				} else {
					population[selected_chromosome].cloning(new_population);
					population[other_selected_chromosome].cloning(new_population);
				}

				// Mutate the second chromosome in the crossover
				mutate((*(new_population.end() - 2)));

				// Handle the case where the new_population.size() -1 == popluation size and then crossover is selected.
				if(new_population.size() == population_size+1) {
					new_population.pop_back();
				}
			}
			else {
				// Clone
                population[selected_chromosome].cloning(new_population);
			}

			// Mutate the chromosome
			mutate(new_population.back());

		}

		//std::cout << "Finished Breeding" << std::endl;

		// Update the population to the new population
		population = new_population;
	}
};

#endif /* MANAGER_HPP_ */
<|endoftext|>


<commit_before>#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestCase.h>
#include <cppunit/extensions/HelperMacros.h>
#include <iostream>
#include <vector>
#include "Hand.h"
//#include "Card.cpp"

class CardTest : public CppUnit::TestCase
{
	private:

	public:
		void testCreateHand()
		{//Basic test of creating a hand.
			//Set up the hand without cards.
			Blackjack::Hand h;

			//Verify the hand without cards.
			CPPUNIT_ASSERT( h.getNumCards() == 0 );

			//Add a card.
			h.addCard( Blackjack::Two, Blackjack::Clubs );

			//Verify the values.
			CPPUNIT_ASSERT( h.getNumCards() == 1 );
			CPPUNIT_ASSERT( h.getCard(0).getRank() == Blackjack::Two );
			CPPUNIT_ASSERT( h.getCard(0).getSuit() == Blackjack::Clubs );
			CPPUNIT_ASSERT( h.getCard(0).getPoints() == 2 );
			CPPUNIT_ASSERT( h.getCard(0).isAce() == false );
		}

		void testAddCardToHand()
		{//Basic test of creating a hand.
			//Set up the hand without cards.
			Blackjack::Hand h;

			//Verify the hand without cards.
			CPPUNIT_ASSERT( h.getNumCards() == 0 );

			//Add a card.
			h.addCard( Blackjack::Two, Blackjack::Clubs );

			//Verify the values.
			CPPUNIT_ASSERT( h.getNumCards() == 1 );
			CPPUNIT_ASSERT( h.getCard(0).getRank() == Blackjack::Two );
			CPPUNIT_ASSERT( h.getCard(0).getSuit() == Blackjack::Clubs );
			CPPUNIT_ASSERT( h.getCard(0).getPoints() == 2 );
			CPPUNIT_ASSERT( h.getCard(0).isAce() == false );

			//Add another card.
			h.addCard( Blackjack::Ace, Blackjack::Hearts );

			//Verify the values.
			CPPUNIT_ASSERT( h.getNumCards() == 2 );
			CPPUNIT_ASSERT( h.getCard(1).getRank() == Blackjack::Ace );
			CPPUNIT_ASSERT( h.getCard(1).getSuit() == Blackjack::Hearts );
			CPPUNIT_ASSERT( h.getCard(1).getPoints() == 11 );
			CPPUNIT_ASSERT( h.getCard(1).isAce() == true );
		}

		//Create the test suite using CPPUnit macros.
		CPPUNIT_TEST_SUITE( CardTest );
		CPPUNIT_TEST( testCreateHand );
		CPPUNIT_TEST( testAddCardToHand );
		CPPUNIT_TEST_SUITE_END( );
};

int main()
{
	CPPUNIT_TEST_SUITE_REGISTRATION( CardTest );
	CppUnit::TextUi::TestRunner runner;
	CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry( );
	runner.addTest( registry.makeTest( ) );
	if ( runner.run( ) )
	{//Runner had success.
		return 0;
	}
	else
	{//Runner failed.
		return 1;
	}
}
<commit_msg>Added a unit test to clear a hand.<commit_after>#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestCase.h>
#include <cppunit/extensions/HelperMacros.h>
#include <iostream>
#include <vector>
#include "Hand.h"

class CardTest : public CppUnit::TestCase
{
	private:

	public:
		void testCreateHand()
		{//Basic test of creating a hand.
			//Set up the hand without cards.
			Blackjack::Hand h;

			//Verify the hand without cards.
			CPPUNIT_ASSERT( h.getNumCards() == 0 );

			//Add a card.
			h.addCard( Blackjack::Two, Blackjack::Clubs );

			//Verify the values.
			CPPUNIT_ASSERT( h.getNumCards() == 1 );
			CPPUNIT_ASSERT( h.getCard(0).getRank() == Blackjack::Two );
			CPPUNIT_ASSERT( h.getCard(0).getSuit() == Blackjack::Clubs );
			CPPUNIT_ASSERT( h.getCard(0).getPoints() == 2 );
			CPPUNIT_ASSERT( h.getCard(0).isAce() == false );
		}

		void testAddCardToHand()
		{//Basic test of creating a hand.
			//Set up the hand without cards.
			Blackjack::Hand h;

			//Verify the hand without cards.
			CPPUNIT_ASSERT( h.getNumCards() == 0 );

			//Add a card.
			h.addCard( Blackjack::Two, Blackjack::Clubs );

			//Verify the values.
			CPPUNIT_ASSERT( h.getNumCards() == 1 );
			CPPUNIT_ASSERT( h.getCard(0).getRank() == Blackjack::Two );
			CPPUNIT_ASSERT( h.getCard(0).getSuit() == Blackjack::Clubs );
			CPPUNIT_ASSERT( h.getCard(0).getPoints() == 2 );
			CPPUNIT_ASSERT( h.getCard(0).isAce() == false );

			//Add another card.
			h.addCard( Blackjack::Ace, Blackjack::Hearts );

			//Verify the values.
			CPPUNIT_ASSERT( h.getNumCards() == 2 );
			CPPUNIT_ASSERT( h.getCard(1).getRank() == Blackjack::Ace );
			CPPUNIT_ASSERT( h.getCard(1).getSuit() == Blackjack::Hearts );
			CPPUNIT_ASSERT( h.getCard(1).getPoints() == 11 );
			CPPUNIT_ASSERT( h.getCard(1).isAce() == true );
		}

		void testClearHand()
		{//Basic test of creating a hand.
			//Set up the hand without cards.
			Blackjack::Hand h;

			//Verify the hand without cards.
			CPPUNIT_ASSERT( h.getNumCards() == 0 );

			//Add a card.
			h.addCard( Blackjack::Two, Blackjack::Clubs );

			//Verify the values.
			CPPUNIT_ASSERT( h.getNumCards() == 1 );
			CPPUNIT_ASSERT( h.getCard(0).getRank() == Blackjack::Two );
			CPPUNIT_ASSERT( h.getCard(0).getSuit() == Blackjack::Clubs );
			CPPUNIT_ASSERT( h.getCard(0).getPoints() == 2 );
			CPPUNIT_ASSERT( h.getCard(0).isAce() == false );

			//Clear the hand.
			h.clearCards();

			//Verify the hand's cleared.
			CPPUNIT_ASSERT( h.getNumCards() == 0 );
		}

		//Create the test suite using CPPUnit macros.
		CPPUNIT_TEST_SUITE( CardTest );
		CPPUNIT_TEST( testCreateHand );
		CPPUNIT_TEST( testAddCardToHand );
		CPPUNIT_TEST_SUITE_END( );
};

int main()
{
	CPPUNIT_TEST_SUITE_REGISTRATION( CardTest );
	CppUnit::TextUi::TestRunner runner;
	CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry( );
	runner.addTest( registry.makeTest( ) );
	if ( runner.run( ) )
	{//Runner had success.
		return 0;
	}
	else
	{//Runner failed.
		return 1;
	}
}
<|endoftext|>


<commit_before>#pragma once
/** @file Vec.hpp
 * @brief A wrapper class to provide simple vector operations for
 * primitive types and classes that only require op[].
 */

#include <iostream>
#include <type_traits>
#include <cstdarg>
#include <math.h>
#include <assert.h>

//! Predeclaration of SmallVec
template <unsigned DIM, typename DATA>
class SmallVec;

/** @class Vec
 * A general class that endows types with vector operations. If the base type
 * is a primitive type, the Vec stores information as an array of that type.
 * If the base type is not a primitive type, then it must implement the bracket
 * operator (lvalue and rvalue)
 *
 * All of the following result in nearly the same public Vec interface
 * Vec<3, double> v1;
 * Vec<3, double[3]> v2;
 * Vec<3, MyClassThatImplementsOpBracketWithDoubles> v3;
 */
template <unsigned DIM, typename DATA>
using Vec = typename std::conditional<std::is_fundamental<DATA>::value,
                                      SmallVec<DIM, DATA[DIM]>,
                                      SmallVec<DIM, DATA>>::type;

#define for_i for(unsigned i=0; i!=dimension; ++i)

/** @class SmallVec
 * @brief Class representing ND points and vectors.
 *
 * SmallVec contains methods that support use of the underlying type
 * as points in ND space. The underlying data is stored as type POINT,
 * which must only provide the operators:
 * value_type& operator[](unsigned i)
 * const value_type& operator[](unsigned i) const
 */
template <unsigned DIM, typename POINT>
class SmallVec {
  static_assert(DIM > 0, "SmallVec DIM must be greater than 0");

  POINT a;

 public:
  static constexpr unsigned dimension = DIM;
  typedef POINT point_type;
  typedef typename std::decay<decltype(a[0])>::type value_type;

  // CONSTRUCTORS

  SmallVec() {
    for_i a[i] = value_type(0);
  }
  SmallVec(const SmallVec& b) {
    for_i a[i] = b[i];
  }
  explicit SmallVec(const point_type& b) {
    for_i a[i] = b[i];
  }
  explicit SmallVec(value_type b) {
    for_i a[i] = b;
  }
  SmallVec(value_type b0, value_type b1) {
    static_assert(dimension == 2, "Calling 2-value Vec constructor for Non-2D Vec");
    a[0] = b0; a[1] = b1;
  }
  SmallVec(value_type b0, value_type b1, value_type b2) {
    static_assert(dimension == 3, "Calling 3-value Vec constructor for Non-3D Vec");
    a[0] = b0; a[1] = b1; a[2] = b2;
  }
  SmallVec(value_type b0, value_type b1, value_type b2, value_type b3) {
    static_assert(dimension == 4, "Calling 4-value Vec constructor for Non-4D Vec");
    a[0] = b0; a[1] = b1; a[2] = b2; a[3] = b3;
  }

  inline bool operator==(const SmallVec& b) const {
    for_i if (a[i] != b[i]) return false;
    return true;
  }

  // MODIFIERS

  /** Return a negated version of @a p. */
  inline SmallVec operator-() const {
    return SmallVec(-a[0], -a[1], -a[2]);
  }
  /** Scalar assignment */
  inline SmallVec& operator=(const value_type b) {
    for_i a[i] = b;
    return *this;
  }
  /** Add scalar @a b to this SmallVec */
  inline SmallVec& operator+=(const value_type b) {
    for_i a[i] += b;
    return *this;
  }
  /** Subtract scalar @a b from this SmallVec */
  inline SmallVec& operator-=(const value_type b) {
    for_i a[i] -= b;
    return *this;
  }
  /** Scale this SmallVec up by scalar @a b */
  inline SmallVec& operator*=(const value_type b) {
    for_i a[i] *= b;
    return *this;
  }
  /** Scale this SmallVec down by scalar @a b */
  inline SmallVec& operator/=(const value_type b) {
    for_i a[i] /= b;
    return *this;
  }
  /** Add SmallVec @a b to this SmallVec */
  inline SmallVec& operator+=(const SmallVec& b) {
    for_i a[i] += b[i];
    return *this;
  }
  /** Subtract SmallVec @a b from this SmallVec */
  inline SmallVec& operator-=(const SmallVec& b) {
    for_i a[i] -= b[i];
    return *this;
  }
  /** Scale this SmallVec up by factors in @a b */
  inline SmallVec& operator*=(const SmallVec& b) {
    for_i a[i] *= b[i];
    return *this;
  }
  /** Scale this SmallVec down by factors in @a b */
  inline SmallVec& operator/=(const SmallVec& b) {
    for_i a[i] /= b[i];
    return *this;
  }
  /** Compute the dot product of this SmallVec with another SmallVec */
  inline value_type dot(const SmallVec& b) const {
    value_type d(0);
    for_i d += a[i]*b[i];
    return d;
  }

  // ACCESSORS

  /** Access the @a i th (lvalue) element of this SmallVec
   * @pre i < dimension */
  inline value_type& operator[](unsigned i) {
    //assert(i < dimension);
    return a[i];
  }
  /** Access the @a i th (rvalue) element of this SmallVec
   * @pre i < dimension */
  inline const value_type& operator[](unsigned i) const {
    //assert(i < dimension);
    return a[i];
  }
  static constexpr unsigned size() {
    return dimension;
  }

  /** Compute the dot product of this SmallVec with another SmallVec */
  inline friend value_type dot(const SmallVec& a, const SmallVec& b) {
    return a.dot(b);
  }
  /** Compute cross product of two SmallVecs */
  inline friend SmallVec cross(const SmallVec& a, const SmallVec& b) {
    static_assert(SmallVec::dimension == 3, "Cross product only defined for 3D");
    SmallVec r;
    r[0] = a[1]*b[2] - a[2]*b[1];
    r[1] = -(a[0]*b[2] - a[2]*b[0]);
    r[2] = a[0]*b[1] - a[1]*b[0];
    return r;
  }
  /** Compute the squared L2 norm of this SmallVec */
  inline friend value_type normSq(const SmallVec& b) {
    return b.dot(b);
  }
  /** Compute the L2 norm of this SmallVec */
  inline friend value_type norm(const SmallVec& b) {
    return sqrt(normSq(b));
  }
  /** Write a SmallVec to an output stream */
  inline friend std::ostream& operator<<(std::ostream& s, const SmallVec& a) {
    for_i s << a[i] << " ";
    return s;
  }
  /** Read a SmallVec from an input stream */
  inline friend std::istream& operator>>(std::istream& s, const SmallVec& a) {
    for_i s >> a[i];
    return s;
  }
};

#undef for_i

// OPERATORS

/** Compute the dot product of two SmallVecs */
template <unsigned D, typename P>
inline typename SmallVec<D,P>::value_type dot(const SmallVec<D,P>& a,
                                              const SmallVec<D,P>& b) {
  return a.dot(b);
}
/** Compute the squared L2 norm of this SmallVec */
template <unsigned D, typename P>
inline typename SmallVec<D,P>::value_type normSq(const SmallVec<D,P>& a) {
  return a.dot(a);
}
/** Compute the L2 norm of this SmallVec */
template <unsigned D, typename P>
inline typename SmallVec<D,P>::value_type norm(const SmallVec<D,P>& a) {
  return sqrt(normSq(a));
}

// ARITHMETIC

/** Unary plus: Return @a p. ("+p" should work if "-p" works.) */
template <unsigned D, typename P>
inline SmallVec<D,P> operator+(const SmallVec<D,P>& a) {
  return a;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator+(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a += b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator-(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a -= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator*(SmallVec<D,P> a, double b) {
  return a *= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator*(double b, SmallVec<D,P> a) {
  return a *= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator*(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a *= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator/(SmallVec<D,P> a, double b) {
  return a /= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator/(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a /= b;
}
<commit_msg>Fix read op for SmallVec...<commit_after>#pragma once
/** @file Vec.hpp
 * @brief A wrapper class to provide simple vector operations for
 * primitive types and classes that only require op[].
 */

#include <iostream>
#include <type_traits>
#include <cstdarg>
#include <math.h>
#include <assert.h>

//! Predeclaration of SmallVec
template <unsigned DIM, typename DATA>
class SmallVec;

/** @class Vec
 * A general class that endows types with vector operations. If the base type
 * is a primitive type, the Vec stores information as an array of that type.
 * If the base type is not a primitive type, then it must implement the bracket
 * operator (lvalue and rvalue)
 *
 * All of the following result in nearly the same public Vec interface
 * Vec<3, double> v1;
 * Vec<3, double[3]> v2;
 * Vec<3, MyClassThatImplementsOpBracketWithDoubles> v3;
 */
template <unsigned DIM, typename DATA>
using Vec = typename std::conditional<std::is_fundamental<DATA>::value,
                                      SmallVec<DIM, DATA[DIM]>,
                                      SmallVec<DIM, DATA>>::type;

#define for_i for(unsigned i=0; i!=dimension; ++i)

/** @class SmallVec
 * @brief Class representing ND points and vectors.
 *
 * SmallVec contains methods that support use of the underlying type
 * as points in ND space. The underlying data is stored as type POINT,
 * which must only provide the operators:
 * value_type& operator[](unsigned i)
 * const value_type& operator[](unsigned i) const
 */
template <unsigned DIM, typename POINT>
class SmallVec {
  static_assert(DIM > 0, "SmallVec DIM must be greater than 0");

  POINT a;

 public:
  static constexpr unsigned dimension = DIM;
  typedef POINT point_type;
  typedef typename std::decay<decltype(a[0])>::type value_type;

  // CONSTRUCTORS

  SmallVec() {
    for_i a[i] = value_type(0);
  }
  SmallVec(const SmallVec& b) {
    for_i a[i] = b[i];
  }
  explicit SmallVec(const point_type& b) {
    for_i a[i] = b[i];
  }
  explicit SmallVec(value_type b) {
    for_i a[i] = b;
  }
  SmallVec(value_type b0, value_type b1) {
    static_assert(dimension == 2, "Calling 2-value Vec constructor for Non-2D Vec");
    a[0] = b0; a[1] = b1;
  }
  SmallVec(value_type b0, value_type b1, value_type b2) {
    static_assert(dimension == 3, "Calling 3-value Vec constructor for Non-3D Vec");
    a[0] = b0; a[1] = b1; a[2] = b2;
  }
  SmallVec(value_type b0, value_type b1, value_type b2, value_type b3) {
    static_assert(dimension == 4, "Calling 4-value Vec constructor for Non-4D Vec");
    a[0] = b0; a[1] = b1; a[2] = b2; a[3] = b3;
  }

  inline bool operator==(const SmallVec& b) const {
    for_i if (a[i] != b[i]) return false;
    return true;
  }

  // MODIFIERS

  /** Return a negated version of @a p. */
  inline SmallVec operator-() const {
    return SmallVec(-a[0], -a[1], -a[2]);
  }
  /** Scalar assignment */
  inline SmallVec& operator=(const value_type b) {
    for_i a[i] = b;
    return *this;
  }
  /** Add scalar @a b to this SmallVec */
  inline SmallVec& operator+=(const value_type b) {
    for_i a[i] += b;
    return *this;
  }
  /** Subtract scalar @a b from this SmallVec */
  inline SmallVec& operator-=(const value_type b) {
    for_i a[i] -= b;
    return *this;
  }
  /** Scale this SmallVec up by scalar @a b */
  inline SmallVec& operator*=(const value_type b) {
    for_i a[i] *= b;
    return *this;
  }
  /** Scale this SmallVec down by scalar @a b */
  inline SmallVec& operator/=(const value_type b) {
    for_i a[i] /= b;
    return *this;
  }
  /** Add SmallVec @a b to this SmallVec */
  inline SmallVec& operator+=(const SmallVec& b) {
    for_i a[i] += b[i];
    return *this;
  }
  /** Subtract SmallVec @a b from this SmallVec */
  inline SmallVec& operator-=(const SmallVec& b) {
    for_i a[i] -= b[i];
    return *this;
  }
  /** Scale this SmallVec up by factors in @a b */
  inline SmallVec& operator*=(const SmallVec& b) {
    for_i a[i] *= b[i];
    return *this;
  }
  /** Scale this SmallVec down by factors in @a b */
  inline SmallVec& operator/=(const SmallVec& b) {
    for_i a[i] /= b[i];
    return *this;
  }
  /** Compute the dot product of this SmallVec with another SmallVec */
  inline value_type dot(const SmallVec& b) const {
    value_type d(0);
    for_i d += a[i]*b[i];
    return d;
  }

  // ACCESSORS

  /** Access the @a i th (lvalue) element of this SmallVec
   * @pre i < dimension */
  inline value_type& operator[](unsigned i) {
    //assert(i < dimension);
    return a[i];
  }
  /** Access the @a i th (rvalue) element of this SmallVec
   * @pre i < dimension */
  inline const value_type& operator[](unsigned i) const {
    //assert(i < dimension);
    return a[i];
  }
  static constexpr unsigned size() {
    return dimension;
  }

  /** Compute the dot product of this SmallVec with another SmallVec */
  inline friend value_type dot(const SmallVec& a, const SmallVec& b) {
    return a.dot(b);
  }
  /** Compute cross product of two SmallVecs */
  inline friend SmallVec cross(const SmallVec& a, const SmallVec& b) {
    static_assert(SmallVec::dimension == 3, "Cross product only defined for 3D");
    SmallVec r;
    r[0] = a[1]*b[2] - a[2]*b[1];
    r[1] = -(a[0]*b[2] - a[2]*b[0]);
    r[2] = a[0]*b[1] - a[1]*b[0];
    return r;
  }
  /** Compute the squared L2 norm of this SmallVec */
  inline friend value_type normSq(const SmallVec& b) {
    return b.dot(b);
  }
  /** Compute the L2 norm of this SmallVec */
  inline friend value_type norm(const SmallVec& b) {
    return sqrt(normSq(b));
  }
  /** Write a SmallVec to an output stream */
  inline friend std::ostream& operator<<(std::ostream& s, const SmallVec& a) {
    for_i s << a[i] << " ";
    return s;
  }
  /** Read a SmallVec from an input stream */
  inline friend std::istream& operator>>(std::istream& s, SmallVec& a) {
    for_i s >> a[i];
    return s;
  }
};

#undef for_i

// OPERATORS

/** Compute the dot product of two SmallVecs */
template <unsigned D, typename P>
inline typename SmallVec<D,P>::value_type dot(const SmallVec<D,P>& a,
                                              const SmallVec<D,P>& b) {
  return a.dot(b);
}
/** Compute the squared L2 norm of this SmallVec */
template <unsigned D, typename P>
inline typename SmallVec<D,P>::value_type normSq(const SmallVec<D,P>& a) {
  return a.dot(a);
}
/** Compute the L2 norm of this SmallVec */
template <unsigned D, typename P>
inline typename SmallVec<D,P>::value_type norm(const SmallVec<D,P>& a) {
  return sqrt(normSq(a));
}

// ARITHMETIC

/** Unary plus: Return @a p. ("+p" should work if "-p" works.) */
template <unsigned D, typename P>
inline SmallVec<D,P> operator+(const SmallVec<D,P>& a) {
  return a;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator+(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a += b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator-(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a -= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator*(SmallVec<D,P> a, double b) {
  return a *= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator*(double b, SmallVec<D,P> a) {
  return a *= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator*(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a *= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator/(SmallVec<D,P> a, double b) {
  return a /= b;
}
template <unsigned D, typename P>
inline SmallVec<D,P> operator/(SmallVec<D,P> a, const SmallVec<D,P>& b) {
  return a /= b;
}
<|endoftext|>


<commit_before>#pragma once

// only included in case there's a C++11 compiler out there that doesn't support `#pragma once`
#ifndef DKM_KMEANS_H
#define DKM_KMEANS_H

#include <vector>
#include <array>
#include <tuple>
#include <cstddef>
#include <cstdint>
#include <random>
#include <type_traits>
#include <cassert>

/*
DKM - A k-means implementation that is generic across variable data dimensions.
*/
namespace dkm {

/*
These functions are all private implementation details and shouldn't be referenced outside of this
file.
*/
namespace details {

/*
Calculate the square of the distance between two points.
*/
template <typename T, size_t N>
T distance_squared(const std::array<T, N>& point_a, const std::array<T, N>& point_b) {
	T d_squared = T();
	for (typename std::array<T, N>::size_type i = 0; i < N; ++i) {
		auto delta = point_a[i] - point_b[i];
		d_squared += delta * delta;
	}
	return d_squared;
}

/*
Calculate the smallest distance between each of the data points and any of the input means.
*/
template <typename T, size_t N>
std::vector<T> closest_distance(const std::vector<std::array<T, N>>& means, const std::vector<std::array<T, N>>& data, uint32_t k) {
	std::vector<T> distances;
	distances.reserve(k);
	for (auto&d : data) {
		T closest = distance_squared(d, means[0]);
		for (auto& m: means) {
			T distance = distance_squared(d, m);
			if (distance < closest)
				closest = distance;
		}
		distances.push_back(closest);
	}
	return distances;
}

/*
This is an alternate initialization method based on the [kmeans++](https://en.wikipedia.org/wiki/K-means%2B%2B)
initialization algorithm.
*/
template <typename T, size_t N>
std::vector<std::array<T, N>> random_plusplus(const std::vector<std::array<T, N>>& data, uint32_t k) {
	assert(k > 0);
	using input_size_t = typename std::array<T,N>::size_type;
	std::vector<std::array<T, N>> means;
	// Using a very simple PRBS generator, parameters selected according to
	// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
	std::random_device rand_device;
	std::linear_congruential_engine<uint64_t, 6364136223846793005, 1442695040888963407, UINT64_MAX> rand_engine(rand_device());

	// Select first mean at random from the set
	{
		std::uniform_int_distribution<input_size_t> uniform_generator(0, data.size() - 1);
		means.push_back(data[uniform_generator(rand_engine)]);
	}

	for (uint32_t count = 1; count < k; ++count) {
		// Calculate the distance to the closest mean for each data point
		auto distances = details::closest_distance(means, data, k);
		// Pick a random point weighted by the distance from existing means
		std::discrete_distribution<input_size_t> generator(distances.begin(), distances.end());
		means.push_back(data[generator(rand_engine)]);
	}
	return means;
}

/*
Calculate the index of the mean a particular data point is closest to (euclidean distance)
*/
template <typename T, size_t N>
uint32_t closest_mean(const std::array<T, N>& point, const std::vector<std::array<T, N>>& means) {
	assert(!means.empty());
	auto calculate_distance = [](const std::array<T, N>& point, const std::array<T, N>& mean){
		T distance = T();
		for (size_t i = 0; i < point.size(); ++i) {
			T difference = point[i] - mean[i];
			distance += difference * difference;
		}
		return distance;
	};
	T smallest_distance = calculate_distance(point, means[0]);
	typename std::array<T, N>::size_type index = 0;
	T distance;
	for (size_t i = 1; i < means.size(); ++i) {
		distance = calculate_distance(point, means[i]);
		if (distance < smallest_distance) {
			smallest_distance = distance;
			index = i;
		}
	}
	return index;
}

/*
Calculate the index of the mean each data point is closest to (euclidean distance).
*/
template <typename T, size_t N>
std::vector<uint32_t> calculate_clusters(const std::vector<std::array<T, N>>& data, const std::vector<std::array<T, N>>& means) {
	std::vector<uint32_t> clusters;
	for (auto& point : data) {
		clusters.push_back(closest_mean(point, means));
	}
	return clusters;
}

/*
Calculate means based on data points and their cluster assignments.
*/
template <typename T, size_t N>
std::vector<std::array<T, N>> calculate_means(const std::vector<std::array<T, N>>& data, const std::vector<uint32_t> clusters, const std::vector<std::array<T, N>>& old_means, uint32_t k) {
	std::vector<std::array<T, N>> means(k);
	std::vector<T> count(k, T());
	for (size_t i = 0; i < std::min(clusters.size(), data.size()); ++i) {
		auto& mean = means[clusters[i]];
		count[clusters[i]] += 1;
		for (size_t j = 0; j < std::min(data[i].size(), mean.size()); ++j) {
			mean[j] += data[i][j];
		}
	}
	for (size_t i = 0; i < k; ++i) {
		if (count[i] == 0) {
			means[i] = old_means[i];
		} else {
			for (size_t j = 0; j < means[i].size(); ++j) {
				means[i][j] /= count[i];
			}
		}

	}
	return means;
}

} // namespace details

/*
Implementation of k-means generic across the data type and the dimension of each data item. Expects
the data to be a vector of fixed-size arrays. Generic parameters are the type of the base data (T)
and the dimensionality of each data point (N). All points must have the same dimensionality.

e.g. points of the form (X, Y, Z) would be N = 3.

Returns a std::tuple containing:
  0: A vector holding the means for each cluster from 0 to k-1.
  1: A vector containing the cluster number (0 to k-1) for each corresponding element of the input
     data vector.

Implementation details:
This implementation of k-means uses [Lloyd's Algorithm](https://en.wikipedia.org/wiki/Lloyd%27s_algorithm)
with the [kmeans++](https://en.wikipedia.org/wiki/K-means%2B%2B)
used for initializing the means.

TODO: formatting
TODO: add test using the iris data set
*/
template <typename T, size_t N>
std::tuple<std::vector<std::array<T, N>>, std::vector<uint32_t>> kmeans_lloyd(const std::vector<std::array<T, N>>& data, uint32_t k) {
	static_assert(std::is_arithmetic<T>::value && std::is_signed<T>::value, "kmeans_lloyd requires the template parameter T to be a signed arithmetic type (e.g. float, double, int)");
	assert(k > 0); // k must be greater than zero
	assert(data.size() >= k); // there must be at least k data points
	std::vector<std::array<T, N>> means = details::random_plusplus(data, k);

	std::vector<std::array<T, N>> old_means;
	std::vector<uint32_t> clusters;
	// Calculate new means until convergence is reached
	int count = 0;
	do {
		clusters = details::calculate_clusters(data, means);
		old_means = means;
		means = details::calculate_means(data, clusters, old_means, k);
		++count;
	} while (means != old_means && count < 20); // TODO: not converging for some reason

	return std::tuple<std::vector<std::array<T, N>>, std::vector<uint32_t>>(means, clusters);
}

} // namespace dkm

#endif /* DKM_KMEANS_H */
<commit_msg>Removed iteration cap and related TODO.<commit_after>#pragma once

// only included in case there's a C++11 compiler out there that doesn't support `#pragma once`
#ifndef DKM_KMEANS_H
#define DKM_KMEANS_H

#include <vector>
#include <array>
#include <tuple>
#include <cstddef>
#include <cstdint>
#include <random>
#include <type_traits>
#include <cassert>

/*
DKM - A k-means implementation that is generic across variable data dimensions.
*/
namespace dkm {

/*
These functions are all private implementation details and shouldn't be referenced outside of this
file.
*/
namespace details {

/*
Calculate the square of the distance between two points.
*/
template <typename T, size_t N>
T distance_squared(const std::array<T, N>& point_a, const std::array<T, N>& point_b) {
	T d_squared = T();
	for (typename std::array<T, N>::size_type i = 0; i < N; ++i) {
		auto delta = point_a[i] - point_b[i];
		d_squared += delta * delta;
	}
	return d_squared;
}

/*
Calculate the smallest distance between each of the data points and any of the input means.
*/
template <typename T, size_t N>
std::vector<T> closest_distance(const std::vector<std::array<T, N>>& means, const std::vector<std::array<T, N>>& data, uint32_t k) {
	std::vector<T> distances;
	distances.reserve(k);
	for (auto&d : data) {
		T closest = distance_squared(d, means[0]);
		for (auto& m: means) {
			T distance = distance_squared(d, m);
			if (distance < closest)
				closest = distance;
		}
		distances.push_back(closest);
	}
	return distances;
}

/*
This is an alternate initialization method based on the [kmeans++](https://en.wikipedia.org/wiki/K-means%2B%2B)
initialization algorithm.
*/
template <typename T, size_t N>
std::vector<std::array<T, N>> random_plusplus(const std::vector<std::array<T, N>>& data, uint32_t k) {
	assert(k > 0);
	using input_size_t = typename std::array<T,N>::size_type;
	std::vector<std::array<T, N>> means;
	// Using a very simple PRBS generator, parameters selected according to
	// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
	std::random_device rand_device;
	std::linear_congruential_engine<uint64_t, 6364136223846793005, 1442695040888963407, UINT64_MAX> rand_engine(rand_device());

	// Select first mean at random from the set
	{
		std::uniform_int_distribution<input_size_t> uniform_generator(0, data.size() - 1);
		means.push_back(data[uniform_generator(rand_engine)]);
	}

	for (uint32_t count = 1; count < k; ++count) {
		// Calculate the distance to the closest mean for each data point
		auto distances = details::closest_distance(means, data, k);
		// Pick a random point weighted by the distance from existing means
		std::discrete_distribution<input_size_t> generator(distances.begin(), distances.end());
		means.push_back(data[generator(rand_engine)]);
	}
	return means;
}

/*
Calculate the index of the mean a particular data point is closest to (euclidean distance)
*/
template <typename T, size_t N>
uint32_t closest_mean(const std::array<T, N>& point, const std::vector<std::array<T, N>>& means) {
	assert(!means.empty());
	auto calculate_distance = [](const std::array<T, N>& point, const std::array<T, N>& mean){
		T distance = T();
		for (size_t i = 0; i < point.size(); ++i) {
			T difference = point[i] - mean[i];
			distance += difference * difference;
		}
		return distance;
	};
	T smallest_distance = calculate_distance(point, means[0]);
	typename std::array<T, N>::size_type index = 0;
	T distance;
	for (size_t i = 1; i < means.size(); ++i) {
		distance = calculate_distance(point, means[i]);
		if (distance < smallest_distance) {
			smallest_distance = distance;
			index = i;
		}
	}
	return index;
}

/*
Calculate the index of the mean each data point is closest to (euclidean distance).
*/
template <typename T, size_t N>
std::vector<uint32_t> calculate_clusters(const std::vector<std::array<T, N>>& data, const std::vector<std::array<T, N>>& means) {
	std::vector<uint32_t> clusters;
	for (auto& point : data) {
		clusters.push_back(closest_mean(point, means));
	}
	return clusters;
}

/*
Calculate means based on data points and their cluster assignments.
*/
template <typename T, size_t N>
std::vector<std::array<T, N>> calculate_means(const std::vector<std::array<T, N>>& data, const std::vector<uint32_t> clusters, const std::vector<std::array<T, N>>& old_means, uint32_t k) {
	std::vector<std::array<T, N>> means(k);
	std::vector<T> count(k, T());
	for (size_t i = 0; i < std::min(clusters.size(), data.size()); ++i) {
		auto& mean = means[clusters[i]];
		count[clusters[i]] += 1;
		for (size_t j = 0; j < std::min(data[i].size(), mean.size()); ++j) {
			mean[j] += data[i][j];
		}
	}
	for (size_t i = 0; i < k; ++i) {
		if (count[i] == 0) {
			means[i] = old_means[i];
		} else {
			for (size_t j = 0; j < means[i].size(); ++j) {
				means[i][j] /= count[i];
			}
		}

	}
	return means;
}

} // namespace details

/*
Implementation of k-means generic across the data type and the dimension of each data item. Expects
the data to be a vector of fixed-size arrays. Generic parameters are the type of the base data (T)
and the dimensionality of each data point (N). All points must have the same dimensionality.

e.g. points of the form (X, Y, Z) would be N = 3.

Returns a std::tuple containing:
  0: A vector holding the means for each cluster from 0 to k-1.
  1: A vector containing the cluster number (0 to k-1) for each corresponding element of the input
     data vector.

Implementation details:
This implementation of k-means uses [Lloyd's Algorithm](https://en.wikipedia.org/wiki/Lloyd%27s_algorithm)
with the [kmeans++](https://en.wikipedia.org/wiki/K-means%2B%2B)
used for initializing the means.

TODO: formatting
TODO: add test using the iris data set
*/
template <typename T, size_t N>
std::tuple<std::vector<std::array<T, N>>, std::vector<uint32_t>> kmeans_lloyd(const std::vector<std::array<T, N>>& data, uint32_t k) {
	static_assert(std::is_arithmetic<T>::value && std::is_signed<T>::value, "kmeans_lloyd requires the template parameter T to be a signed arithmetic type (e.g. float, double, int)");
	assert(k > 0); // k must be greater than zero
	assert(data.size() >= k); // there must be at least k data points
	std::vector<std::array<T, N>> means = details::random_plusplus(data, k);

	std::vector<std::array<T, N>> old_means;
	std::vector<uint32_t> clusters;
	// Calculate new means until convergence is reached
	int count = 0;
	do {
		clusters = details::calculate_clusters(data, means);
		old_means = means;
		means = details::calculate_means(data, clusters, old_means, k);
		++count;
	} while (means != old_means);

	return std::tuple<std::vector<std::array<T, N>>, std::vector<uint32_t>>(means, clusters);
}

} // namespace dkm

#endif /* DKM_KMEANS_H */
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>
#include <stdint.h>

extern unsigned char findSensor(char);
extern int set_sensor_dbus_state_v(uint8_t , const char *, char *);

struct sensorRES_t {
	uint8_t sensor_number;
	uint8_t operation;
	uint8_t sensor_reading;
	uint8_t assert_state7_0;
	uint8_t assert_state14_8;
	uint8_t deassert_state7_0;
	uint8_t deassert_state14_8;
	uint8_t event_data1;
	uint8_t event_data2;
	uint8_t event_data3;
} __attribute__ ((packed));

#define ISBITSET(x,y) (((x)>>(y))&0x01)
#define ASSERTINDEX 0
#define DEASSERTINDEX 1

// Sensor Type,  Offset, function handler, Dbus Method, Assert value, Deassert value
struct lookup_t {
	uint8_t sensor_type;
	uint8_t offset;
	int (*func)(const sensorRES_t *, const lookup_t *, const char *);
	char    method[16];
	char    assertion[16];
	char    deassertion[16];
};

extern int updateDbusInterface(uint8_t , const char *, const char *) ;
extern int set_sensor_dbus_state(uint8_t ,const char *, const char *);

int set_sensor_dbus_state_simple(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {

	return set_sensor_dbus_state(pRec->sensor_number, pTable->method, value);
}

struct event_data_t {
	uint8_t data;
	char    text[32];
};

event_data_t g_fwprogress02h[] = {
	{0x00, "Unspecified"},
	{0x01, "Memory Init"},
	{0x02, "HD Init"},
	{0x03, "Secondary Proc Init"},
	{0x04, "User Authentication"},
	{0x05, "User init system setup"},
	{0x06, "USB configuration"},
	{0x07, "PCI configuration"},
	{0x08, "Option ROM Init"},
	{0x09, "Video Init"},
	{0x0A, "Cache Init"},
	{0x0B, "SM Bus init"},
	{0x0C, "Keyboard Init"},
	{0x0D, "Embedded ctrl init"},
	{0x0E, "Docking station attachment"},
	{0x0F, "Enable docking station"},
	{0x10, "Docking station ejection"},
	{0x11, "Disabling docking station"},
	{0x12, "Calling OS Wakeup"},
	{0x13, "Starting OS"},
	{0x14, "Baseboard Init"},
	{0x15, ""},
	{0x16, "Floppy Init"},
	{0x17, "Keyboard Test"},
	{0x18, "Pointing Device Test"},
	{0x19, "Primary Proc Init"},
	{0xFF, "Unknown"}
};

char *getfw02string(uint8_t b) {

	int i = 0;
	event_data_t *p = g_fwprogress02h;

	do {

		if ((p+i)->data == b)
			break;
		i++;
	} while ((p+i)->data != 0xFF);

	return (p+i)->text;
}
//  The fw progress sensor contains some additional information that needs to be processed
//  prior to calling the dbus code.
int set_sensor_dbus_state_fwprogress(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {

	char valuestring[32];
	char* pStr = valuestring;

	switch (pTable->offset) {

		case 0x00 : sprintf(valuestring, "POST Error, 0x%02x", pRec->event_data2);
					break;
		case 0x01 : sprintf(valuestring, "FW Hang, 0x%02x", pRec->event_data2);
					break;
		case 0x02 : sprintf(valuestring, "FW Progress, %s", getfw02string(pRec->event_data2));
	}

	return set_sensor_dbus_state_v(pRec->sensor_number, pTable->method, pStr);
}

// Handling this special OEM sensor by coping what is in byte 4.  I also think that is odd
// considering byte 3 is for sensor reading.  This seems like a misuse of the IPMI spec
int set_sensor_dbus_state_osboot(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {
	char valuestring[32];
	char* pStr = valuestring;

	sprintf(valuestring, "%d", pRec->assert_state7_0);

	return set_sensor_dbus_state_v(pRec->sensor_number, pTable->method, pStr);
}

//  This table lists only senors we care about telling dbus about.
//  Offset definition cab be found in section 42.2 of the IPMI 2.0
//  spec.  Add more if/when there are more items of interest.
lookup_t g_ipmidbuslookup[] = {

	{0x07, 0x07, set_sensor_dbus_state_simple, "setPresent", "True", "False"},
	{0x07, 0x08, set_sensor_dbus_state_simple, "setFault",   "True", "False"},
	{0x0C, 0x06, set_sensor_dbus_state_simple, "setPresent", "True", "False"},
	{0x0C, 0x04, set_sensor_dbus_state_simple, "setFault",   "True", "False"},
	{0x0F, 0x02, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
	{0x0F, 0x01, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
	{0x0F, 0x00, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
	{0xC7, 0x01, set_sensor_dbus_state_simple, "setFault", "True", "False"},
	{0x07, 0x00, set_sensor_dbus_state_simple, "setPresent", "False", "False"}, // OCC Inactive 0
	{0x07, 0x01, set_sensor_dbus_state_simple, "setPresent", "True", "True"},   // OCC Active 1
	{0xc3, 0x00, set_sensor_dbus_state_osboot, "setValue", "" ,""},

	{0xFF, 0xFF, NULL, "", "", ""}
};

void reportSensorEventAssert(sensorRES_t *pRec, int index) {
	lookup_t *pTable = &g_ipmidbuslookup[index];
	(*pTable->func)(pRec, pTable, pTable->assertion);
}
void reportSensorEventDeassert(sensorRES_t *pRec, int index) {
	lookup_t *pTable = &g_ipmidbuslookup[index];
	(*pTable->func)(pRec, pTable, pTable->deassertion);
}

int findindex(const uint8_t sensor_type, int offset, int *index) {

	int i=0, rc=0;
	lookup_t *pTable = g_ipmidbuslookup;

	do {
		if ( ((pTable+i)->sensor_type == sensor_type) &&
			 ((pTable+i)->offset  == offset) ) {
			rc = 1;
			*index = i;
			break;
		}
		i++;
	} while ((pTable+i)->sensor_type  != 0xFF);

	return rc;
}

void debug_print_ok_to_dont_care(uint8_t stype, int offset)
{
	printf("Sensor should not be reported:  Type 0x%02x, Offset 0x%02x\n",
		stype, offset);
}

bool shouldReport(uint8_t sensorType, int offset, int *index) {

	bool rc = false;

	if (findindex(sensorType, offset, index)) { rc = true;	}

	if (rc==false) { debug_print_ok_to_dont_care(sensorType, offset); }

	return rc;
}

int updateSensorRecordFromSSRAESC(const void *record) {

	sensorRES_t *pRec = (sensorRES_t *) record;
	unsigned char stype;
	int index, i=0;
	stype = findSensor(pRec->sensor_number);

	// Scroll through each bit position .  Determine
	// if any bit is either asserted or Deasserted.
	for(i=0;i<8;i++) {
		if ((ISBITSET(pRec->assert_state7_0,i))  &&
			(shouldReport(stype, i, &index)))
		{
			reportSensorEventAssert(pRec, index);
		}
		if ((ISBITSET(pRec->assert_state14_8,i+8))  &&
			(shouldReport(stype, i+8, &index)))
		{
			reportSensorEventAssert(pRec, index);
		}
		if ((ISBITSET(pRec->deassert_state7_0,i))  &&
			(shouldReport(stype, i, &index)))
		{
			reportSensorEventDeassert(pRec, index);
		}
		if ((ISBITSET(pRec->deassert_state14_8,i+8))  &&
			(shouldReport(stype, i+8, &index)))
		{
			reportSensorEventDeassert(pRec, index);
		}
	}

	return 0;
}
<commit_msg>Fix a buffer overrun<commit_after>#include <stdio.h>
#include <string.h>
#include <stdint.h>

extern unsigned char findSensor(char);
extern int set_sensor_dbus_state_v(uint8_t , const char *, char *);

struct sensorRES_t {
	uint8_t sensor_number;
	uint8_t operation;
	uint8_t sensor_reading;
	uint8_t assert_state7_0;
	uint8_t assert_state14_8;
	uint8_t deassert_state7_0;
	uint8_t deassert_state14_8;
	uint8_t event_data1;
	uint8_t event_data2;
	uint8_t event_data3;
} __attribute__ ((packed));

#define ISBITSET(x,y) (((x)>>(y))&0x01)
#define ASSERTINDEX 0
#define DEASSERTINDEX 1

// Sensor Type,  Offset, function handler, Dbus Method, Assert value, Deassert value
struct lookup_t {
	uint8_t sensor_type;
	uint8_t offset;
	int (*func)(const sensorRES_t *, const lookup_t *, const char *);
	char    method[16];
	char    assertion[16];
	char    deassertion[16];
};

extern int updateDbusInterface(uint8_t , const char *, const char *) ;
extern int set_sensor_dbus_state(uint8_t ,const char *, const char *);

int set_sensor_dbus_state_simple(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {

	return set_sensor_dbus_state(pRec->sensor_number, pTable->method, value);
}

struct event_data_t {
	uint8_t data;
	char    text[32];
};

event_data_t g_fwprogress02h[] = {
	{0x00, "Unspecified"},
	{0x01, "Memory Init"},
	{0x02, "HD Init"},
	{0x03, "Secondary Proc Init"},
	{0x04, "User Authentication"},
	{0x05, "User init system setup"},
	{0x06, "USB configuration"},
	{0x07, "PCI configuration"},
	{0x08, "Option ROM Init"},
	{0x09, "Video Init"},
	{0x0A, "Cache Init"},
	{0x0B, "SM Bus init"},
	{0x0C, "Keyboard Init"},
	{0x0D, "Embedded ctrl init"},
	{0x0E, "Docking station attachment"},
	{0x0F, "Enable docking station"},
	{0x10, "Docking station ejection"},
	{0x11, "Disabling docking station"},
	{0x12, "Calling OS Wakeup"},
	{0x13, "Starting OS"},
	{0x14, "Baseboard Init"},
	{0x15, ""},
	{0x16, "Floppy Init"},
	{0x17, "Keyboard Test"},
	{0x18, "Pointing Device Test"},
	{0x19, "Primary Proc Init"},
	{0xFF, "Unknown"}
};

char *getfw02string(uint8_t b) {

	int i = 0;
	event_data_t *p = g_fwprogress02h;

	do {

		if ((p+i)->data == b)
			break;
		i++;
	} while ((p+i)->data != 0xFF);

	return (p+i)->text;
}
//  The fw progress sensor contains some additional information that needs to be processed
//  prior to calling the dbus code.
int set_sensor_dbus_state_fwprogress(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {

	char valuestring[48];
	char* pStr = valuestring;

	switch (pTable->offset) {

		case 0x00 : snprintf(valuestring, sizeof(valuestring), "POST Error, 0x%02x", pRec->event_data2);
					break;
		case 0x01 : snprintf(valuestring, sizeof(valuestring), "FW Hang, 0x%02x", pRec->event_data2);
					break;
		case 0x02 : snprintf(valuestring, sizeof(valuestring), "FW Progress, %s", getfw02string(pRec->event_data2));
	}

	return set_sensor_dbus_state_v(pRec->sensor_number, pTable->method, pStr);
}

// Handling this special OEM sensor by coping what is in byte 4.  I also think that is odd
// considering byte 3 is for sensor reading.  This seems like a misuse of the IPMI spec
int set_sensor_dbus_state_osboot(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {
	char valuestring[32];
	char* pStr = valuestring;

	sprintf(valuestring, "%d", pRec->assert_state7_0);

	return set_sensor_dbus_state_v(pRec->sensor_number, pTable->method, pStr);
}

//  This table lists only senors we care about telling dbus about.
//  Offset definition cab be found in section 42.2 of the IPMI 2.0
//  spec.  Add more if/when there are more items of interest.
lookup_t g_ipmidbuslookup[] = {

	{0x07, 0x07, set_sensor_dbus_state_simple, "setPresent", "True", "False"},
	{0x07, 0x08, set_sensor_dbus_state_simple, "setFault",   "True", "False"},
	{0x0C, 0x06, set_sensor_dbus_state_simple, "setPresent", "True", "False"},
	{0x0C, 0x04, set_sensor_dbus_state_simple, "setFault",   "True", "False"},
	{0x0F, 0x02, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
	{0x0F, 0x01, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
	{0x0F, 0x00, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
	{0xC7, 0x01, set_sensor_dbus_state_simple, "setFault", "True", "False"},
	{0x07, 0x00, set_sensor_dbus_state_simple, "setPresent", "False", "False"}, // OCC Inactive 0
	{0x07, 0x01, set_sensor_dbus_state_simple, "setPresent", "True", "True"},   // OCC Active 1
	{0xc3, 0x00, set_sensor_dbus_state_osboot, "setValue", "" ,""},

	{0xFF, 0xFF, NULL, "", "", ""}
};

void reportSensorEventAssert(sensorRES_t *pRec, int index) {
	lookup_t *pTable = &g_ipmidbuslookup[index];
	(*pTable->func)(pRec, pTable, pTable->assertion);
}
void reportSensorEventDeassert(sensorRES_t *pRec, int index) {
	lookup_t *pTable = &g_ipmidbuslookup[index];
	(*pTable->func)(pRec, pTable, pTable->deassertion);
}

int findindex(const uint8_t sensor_type, int offset, int *index) {

	int i=0, rc=0;
	lookup_t *pTable = g_ipmidbuslookup;

	do {
		if ( ((pTable+i)->sensor_type == sensor_type) &&
			 ((pTable+i)->offset  == offset) ) {
			rc = 1;
			*index = i;
			break;
		}
		i++;
	} while ((pTable+i)->sensor_type  != 0xFF);

	return rc;
}

void debug_print_ok_to_dont_care(uint8_t stype, int offset)
{
	printf("Sensor should not be reported:  Type 0x%02x, Offset 0x%02x\n",
		stype, offset);
}

bool shouldReport(uint8_t sensorType, int offset, int *index) {

	bool rc = false;

	if (findindex(sensorType, offset, index)) { rc = true;	}

	if (rc==false) { debug_print_ok_to_dont_care(sensorType, offset); }

	return rc;
}

int updateSensorRecordFromSSRAESC(const void *record) {

	sensorRES_t *pRec = (sensorRES_t *) record;
	unsigned char stype;
	int index, i=0;
	stype = findSensor(pRec->sensor_number);

	// Scroll through each bit position .  Determine
	// if any bit is either asserted or Deasserted.
	for(i=0;i<8;i++) {
		if ((ISBITSET(pRec->assert_state7_0,i))  &&
			(shouldReport(stype, i, &index)))
		{
			reportSensorEventAssert(pRec, index);
		}
		if ((ISBITSET(pRec->assert_state14_8,i+8))  &&
			(shouldReport(stype, i+8, &index)))
		{
			reportSensorEventAssert(pRec, index);
		}
		if ((ISBITSET(pRec->deassert_state7_0,i))  &&
			(shouldReport(stype, i, &index)))
		{
			reportSensorEventDeassert(pRec, index);
		}
		if ((ISBITSET(pRec->deassert_state14_8,i+8))  &&
			(shouldReport(stype, i+8, &index)))
		{
			reportSensorEventDeassert(pRec, index);
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>// #include guards
#ifndef ICEFIELD_HPP
#define ICEFIELD_HPP

// Used for overloading << operator with an ostream
#include <iostream>

/* A class representing an ice rink that, like in Pac-Man and
 * Final Fantasy, has wraparound geography and finite dimensions.
 */
class IceField {
public:

    /* Creates a new IceField object
     * PARAMS
     **** rows: number of rows on the IceField
     **** cols: number of columns on the IceField
     **** startRow: initial row number of the zamboni, zero-indexed
     **** startCol: initial column number of the zamboni, zero-indexed
     **** numMoves: number of time the zamboni moves and changes color
     * RETURN
     **** IceField object created with the given parameters
     */
    IceField(int rows, int cols, int startRow, int startCol, int numMoves);

    /* Safely destroys the IceField object.
     */
    ~IceField();

    /* Cleans the ice according to the Pac-Man algorithm:
     * stepSize := 1
     * loop numMoves times
     *     Move stepSize steps in the current direction
     *     Rotate the direction of the zamboni 90 degrees clockwise
     *     Switch to the next color
     *     stepSize := stepSize + 1
     * end loop
     * The zamboni starts by facing up.
     */
    clean();

    /* Outputs a visual representation of the ice field, with
     * the letters A-Z representing the different colors, the
     * character '.' representing white ice, and the character
     * '@' representing the current location of the Zamboni.
     */
    friend std::ostream& operator<<(std::ostream& o, const IceField ice);

private:

    /* The number of colors the zamboni can paint. Since each
     * letter of the alphabet represents a different color,
     * there are 26 possible colors.
     */
    static const int NUMBER_OF_COLORS = 26;

    /* The character that represents the first color the zamboni
     * will paint. This is used to the field currentColor into
     * a character, since the expressions ZERO_COLOR + 0,
     * ZERO_COLOR + 1, and ZERO_COLOR + 2 will have the values
     * 'A', 'B', and 'C', respectively, and so on.
     */
    static const char ZERO_COLOR = 'A';

    /* Constants that represent the four directions in which the
     * zamboni can move.
     */
    static const int NORTH = 0;
    static const int EAST = 1;
    static const int SOUTH = 2;
    static const int WEST = 3;

    /* Number of rows in the ice field.
     */
    int rows;

    /* Number of columns in the ice field
     */
    int cols;

    /* Initial row number of the zamboni, zero-indexed
     */
    int startRow;

    /* Initial column number of the zamboni, zero-indexed
     */
    int startCol;

    /* Number of times the zamboni moves and changes color.
     */
    int numMoves;

    /* Distance the zamboni should move in the next direction.
     */
    int stepSize;

    /* A 2D array that contains the colors of every square on the
     * ice field, with '.' representing white, A-Z representing colors,
     * and '@' representing the current location of the zamboni.
     */
    char** grid;

    /* An integer representing the color the zamboni is painting.
     * Always meets the condition 0 <= currentColor < NUMBER_OF_COLORS.
     * To guarantee this, it should always be modded by NUMBER_OF_COLORS
     * after incrementing.
     */
    int currentColor = 0;

    /* An integer representing the direction in which the zamboni is
     * moving. It should always have the value NORTH, EAST, SOUTH, or
     * WEST.
     */
    int currentDirection;

    /* Moves the zamboni in its current direction, coloring every square
     * it passes over, including the square it starts from, and not
     * including the square it finishes on. If it moves across one edge,
     * it wraps around to the opposite edge.
     */
    void moveZamboni(int distance);

    /* Turns the zamboni clockwise.
     */
    void turnZamboni();
};

// Closes #include guard.
#endif<commit_msg>Added constants for char representation of white ice and current zamboni location.<commit_after>// #include guards
#ifndef ICEFIELD_HPP
#define ICEFIELD_HPP

// Used for overloading << operator with an ostream
#include <iostream>

/* A class representing an ice rink that, like in Pac-Man and
 * Final Fantasy, has wraparound geography and finite dimensions.
 */
class IceField {
public:

    /* Creates a new IceField object
     * PARAMS
     **** rows: number of rows on the IceField
     **** cols: number of columns on the IceField
     **** startRow: initial row number of the zamboni, zero-indexed
     **** startCol: initial column number of the zamboni, zero-indexed
     **** numMoves: number of time the zamboni moves and changes color
     * RETURN
     **** IceField object created with the given parameters
     */
    IceField(int rows, int cols, int startRow, int startCol, int numMoves);

    /* Safely destroys the IceField object.
     */
    ~IceField();

    /* Cleans the ice according to the Pac-Man algorithm:
     * stepSize := 1
     * loop numMoves times
     *     Move stepSize steps in the current direction
     *     Rotate the direction of the zamboni 90 degrees clockwise
     *     Switch to the next color
     *     stepSize := stepSize + 1
     * end loop
     * The zamboni starts by facing up.
     */
    clean();

    /* Outputs a visual representation of the ice field, with
     * the letters A-Z representing the different colors, the
     * character '.' representing white ice, and the character
     * '@' representing the current location of the Zamboni.
     */
    friend std::ostream& operator<<(std::ostream& o, const IceField ice);

private:

    /* The number of colors the zamboni can paint. Since each
     * letter of the alphabet represents a different color,
     * there are 26 possible colors.
     */
    static const int NUMBER_OF_COLORS = 26;

    /* The character that represents the first color the zamboni
     * will paint. This is used to the field currentColor into
     * a character, since the expressions ZERO_COLOR + 0,
     * ZERO_COLOR + 1, and ZERO_COLOR + 2 will have the values
     * 'A', 'B', and 'C', respectively, and so on.
     */
    static const char ZERO_COLOR = 'A';

    /* The character that represents uncolored white ice.
     */
    static const char WHITE_ICE = '.';

    /* The character that represents the current location of the
     * zamboni on the ice.
     */
    static const char ZAMBONI = '@';

    /* Constants that represent the four directions in which the
     * zamboni can move.
     */
    static const int NORTH = 0;
    static const int EAST = 1;
    static const int SOUTH = 2;
    static const int WEST = 3;

    /* Number of rows in the ice field.
     */
    int rows;

    /* Number of columns in the ice field
     */
    int cols;

    /* Initial row number of the zamboni, zero-indexed
     */
    int startRow;

    /* Initial column number of the zamboni, zero-indexed
     */
    int startCol;

    /* Number of times the zamboni moves and changes color.
     */
    int numMoves;

    /* Distance the zamboni should move in the next direction.
     */
    int stepSize;

    /* A 2D array that contains the colors of every square on the
     * ice field, with '.' representing white, A-Z representing colors,
     * and '@' representing the current location of the zamboni.
     */
    char** grid;

    /* An integer representing the color the zamboni is painting.
     * Always meets the condition 0 <= currentColor < NUMBER_OF_COLORS.
     * To guarantee this, it should always be modded by NUMBER_OF_COLORS
     * after incrementing.
     */
    int currentColor = 0;

    /* An integer representing the direction in which the zamboni is
     * moving. It should always have the value NORTH, EAST, SOUTH, or
     * WEST.
     */
    int currentDirection;

    /* Moves the zamboni in its current direction, coloring every square
     * it passes over, including the square it starts from, and not
     * including the square it finishes on. If it moves across one edge,
     * it wraps around to the opposite edge.
     */
    void moveZamboni(int distance);

    /* Turns the zamboni clockwise.
     */
    void turnZamboni();
};

// Closes #include guard.
#endif<|endoftext|>