<commit_before>#include "config.h"

#include "network_manager.hpp"

#include "ipaddress.hpp"
#include "network_config.hpp"
#include "types.hpp"
#include "util.hpp"

#include <arpa/inet.h>
#include <dirent.h>
#include <net/if.h>

#include <algorithm>
#include <bitset>
#include <fstream>
#include <map>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <string>
#include <xyz/openbmc_project/Common/error.hpp>

constexpr char SYSTEMD_BUSNAME[] = "org.freedesktop.systemd1";
constexpr char SYSTEMD_PATH[] = "/org/freedesktop/systemd1";
constexpr char SYSTEMD_INTERFACE[] = "org.freedesktop.systemd1.Manager";

namespace phosphor
{
namespace network
{

extern std::unique_ptr<Timer> refreshObjectTimer;
extern std::unique_ptr<Timer> restartTimer;
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;

Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath,
                 const std::string& path) :
    details::VLANCreateIface(bus, objPath, true),
    bus(bus), objectPath(objPath)
{
    fs::path confDir(path);
    setConfDir(confDir);
}

bool Manager::createDefaultNetworkFiles(bool force)
{
    auto isCreated = false;
    try
    {
        // Directory would have created before with
        // setConfDir function.
        if (force)
        {
            // Factory Reset case
            // we need to forcefully write the files
            // so delete the existing ones.
            if (fs::is_directory(confDir))
            {
                for (const auto& file : fs::directory_iterator(confDir))
                {
                    fs::remove(file.path());
                }
            }
        }

        auto interfaceStrList = getInterfaces();
        for (const auto& interface : interfaceStrList)
        {
            // if the interface has '.' in the name, it means that this is a
            // VLAN - don't create the network file.
            if (interface.find(".") != std::string::npos)
            {
                continue;
            }

            auto fileName = systemd::config::networkFilePrefix + interface +
                            systemd::config::networkFileSuffix;

            fs::path filePath = confDir;
            filePath /= fileName;

            // create the interface specific network file
            // if not exist or we forcefully wants to write
            // the network file.

            if (force || !fs::is_regular_file(filePath.string()))
            {
                bmc::writeDHCPDefault(filePath.string(), interface);
                log<level::INFO>("Created the default network file.",
                                 entry("INTERFACE=%s", interface.c_str()));
                isCreated = true;
            }
        }
    }
    catch (std::exception& e)
    {
        log<level::ERR>("Unable to create the default network file");
    }
    return isCreated;
}

void Manager::setConfDir(const fs::path& dir)
{
    confDir = dir;

    if (!fs::exists(confDir))
    {
        if (!fs::create_directories(confDir))
        {
            log<level::ERR>("Unable to create the network conf dir",
                            entry("DIR=%s", confDir.c_str()));
            elog<InternalFailure>();
        }
    }
}

void Manager::createInterfaces()
{
    // clear all the interfaces first
    interfaces.clear();

    auto interfaceStrList = getInterfaces();

    for (auto& interface : interfaceStrList)
    {
        fs::path objPath = objectPath;
        auto index = interface.find(".");

        // interface can be of vlan type or normal ethernet interface.
        // vlan interface looks like "interface.vlanid",so here by looking
        // at the interface name we decide that we need
        // to create the vlaninterface or normal physical interface.
        if (index != std::string::npos)
        {
            // it is vlan interface
            auto interfaceName = interface.substr(0, index);
            auto vlanid = interface.substr(index + 1);
            uint32_t vlanInt = std::stoul(vlanid);

            interfaces[interfaceName]->loadVLAN(vlanInt);
            continue;
        }
        // normal ethernet interface
        objPath /= interface;

        auto dhcp = getDHCPValue(confDir, interface);

        auto intf = std::make_shared<phosphor::network::EthernetInterface>(
            bus, objPath.string(), dhcp, *this);

        intf->createIPAddressObjects();
        intf->createStaticNeighborObjects();
        intf->loadNameServers();

        this->interfaces.emplace(
            std::make_pair(std::move(interface), std::move(intf)));
    }
}

void Manager::createChildObjects()
{
    // creates the ethernet interface dbus object.
    createInterfaces();

    systemConf.reset(nullptr);
    dhcpConf.reset(nullptr);

    fs::path objPath = objectPath;
    objPath /= "config";

    // create the system conf object.
    systemConf = std::make_unique<phosphor::network::SystemConfiguration>(
        bus, objPath.string(), *this);
    // create the dhcp conf object.
    objPath /= "dhcp";
    dhcpConf = std::make_unique<phosphor::network::dhcp::Configuration>(
        bus, objPath.string(), *this);
}

ObjectPath Manager::vLAN(IntfName interfaceName, uint32_t id)
{
    return interfaces[interfaceName]->createVLAN(id);
}

void Manager::reset()
{
    if (!createDefaultNetworkFiles(true))
    {
        log<level::ERR>("Network Factory Reset failed.");
        return;
        // TODO: openbmc/openbmc#1721 - Log ResetFailed error here.
    }

    log<level::INFO>("Network Factory Reset done.");
}

// Need to merge the below function with the code which writes the
// config file during factory reset.
// TODO openbmc/openbmc#1751
void Manager::writeToConfigurationFile()
{
    // write all the static ip address in the systemd-network conf file
    for (const auto& intf : interfaces)
    {
        intf.second->writeConfigurationFile();
    }
    restartTimers();
}

void Manager::restartTimers()
{
    using namespace std::chrono;
    if (refreshObjectTimer && restartTimer)
    {
        restartTimer->restartOnce(restartTimeout);
        refreshObjectTimer->restartOnce(refreshTimeout);
    }
}

void Manager::restartSystemdUnit(const std::string& unit)
{
    try
    {
        auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                          SYSTEMD_INTERFACE, "ResetFailedUnit");
        method.append(unit);
        bus.call_noreply(method);
    }
    catch (const sdbusplus::exception::SdBusError& ex)
    {
        log<level::ERR>("Failed to reset failed unit",
                        entry("UNIT=%s", unit.c_str()),
                        entry("ERR=%s", ex.what()));
        elog<InternalFailure>();
    }

    try
    {
        auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                          SYSTEMD_INTERFACE, "RestartUnit");
        method.append(unit.c_str(), "replace");
        bus.call_noreply(method);
    }
    catch (const sdbusplus::exception::SdBusError& ex)
    {
        log<level::ERR>("Failed to restart nslcd service",
                        entry("ERR=%s", ex.what()));
        elog<InternalFailure>();
    }
}

} // namespace network
} // namespace phosphor
<commit_msg>Fix the error message<commit_after>#include "config.h"

#include "network_manager.hpp"

#include "ipaddress.hpp"
#include "network_config.hpp"
#include "types.hpp"
#include "util.hpp"

#include <arpa/inet.h>
#include <dirent.h>
#include <net/if.h>

#include <algorithm>
#include <bitset>
#include <fstream>
#include <map>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <string>
#include <xyz/openbmc_project/Common/error.hpp>

constexpr char SYSTEMD_BUSNAME[] = "org.freedesktop.systemd1";
constexpr char SYSTEMD_PATH[] = "/org/freedesktop/systemd1";
constexpr char SYSTEMD_INTERFACE[] = "org.freedesktop.systemd1.Manager";

namespace phosphor
{
namespace network
{

extern std::unique_ptr<Timer> refreshObjectTimer;
extern std::unique_ptr<Timer> restartTimer;
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;

Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath,
                 const std::string& path) :
    details::VLANCreateIface(bus, objPath, true),
    bus(bus), objectPath(objPath)
{
    fs::path confDir(path);
    setConfDir(confDir);
}

bool Manager::createDefaultNetworkFiles(bool force)
{
    auto isCreated = false;
    try
    {
        // Directory would have created before with
        // setConfDir function.
        if (force)
        {
            // Factory Reset case
            // we need to forcefully write the files
            // so delete the existing ones.
            if (fs::is_directory(confDir))
            {
                for (const auto& file : fs::directory_iterator(confDir))
                {
                    fs::remove(file.path());
                }
            }
        }

        auto interfaceStrList = getInterfaces();
        for (const auto& interface : interfaceStrList)
        {
            // if the interface has '.' in the name, it means that this is a
            // VLAN - don't create the network file.
            if (interface.find(".") != std::string::npos)
            {
                continue;
            }

            auto fileName = systemd::config::networkFilePrefix + interface +
                            systemd::config::networkFileSuffix;

            fs::path filePath = confDir;
            filePath /= fileName;

            // create the interface specific network file
            // if not exist or we forcefully wants to write
            // the network file.

            if (force || !fs::is_regular_file(filePath.string()))
            {
                bmc::writeDHCPDefault(filePath.string(), interface);
                log<level::INFO>("Created the default network file.",
                                 entry("INTERFACE=%s", interface.c_str()));
                isCreated = true;
            }
        }
    }
    catch (std::exception& e)
    {
        log<level::ERR>("Unable to create the default network file");
    }
    return isCreated;
}

void Manager::setConfDir(const fs::path& dir)
{
    confDir = dir;

    if (!fs::exists(confDir))
    {
        if (!fs::create_directories(confDir))
        {
            log<level::ERR>("Unable to create the network conf dir",
                            entry("DIR=%s", confDir.c_str()));
            elog<InternalFailure>();
        }
    }
}

void Manager::createInterfaces()
{
    // clear all the interfaces first
    interfaces.clear();

    auto interfaceStrList = getInterfaces();

    for (auto& interface : interfaceStrList)
    {
        fs::path objPath = objectPath;
        auto index = interface.find(".");

        // interface can be of vlan type or normal ethernet interface.
        // vlan interface looks like "interface.vlanid",so here by looking
        // at the interface name we decide that we need
        // to create the vlaninterface or normal physical interface.
        if (index != std::string::npos)
        {
            // it is vlan interface
            auto interfaceName = interface.substr(0, index);
            auto vlanid = interface.substr(index + 1);
            uint32_t vlanInt = std::stoul(vlanid);

            interfaces[interfaceName]->loadVLAN(vlanInt);
            continue;
        }
        // normal ethernet interface
        objPath /= interface;

        auto dhcp = getDHCPValue(confDir, interface);

        auto intf = std::make_shared<phosphor::network::EthernetInterface>(
            bus, objPath.string(), dhcp, *this);

        intf->createIPAddressObjects();
        intf->createStaticNeighborObjects();
        intf->loadNameServers();

        this->interfaces.emplace(
            std::make_pair(std::move(interface), std::move(intf)));
    }
}

void Manager::createChildObjects()
{
    // creates the ethernet interface dbus object.
    createInterfaces();

    systemConf.reset(nullptr);
    dhcpConf.reset(nullptr);

    fs::path objPath = objectPath;
    objPath /= "config";

    // create the system conf object.
    systemConf = std::make_unique<phosphor::network::SystemConfiguration>(
        bus, objPath.string(), *this);
    // create the dhcp conf object.
    objPath /= "dhcp";
    dhcpConf = std::make_unique<phosphor::network::dhcp::Configuration>(
        bus, objPath.string(), *this);
}

ObjectPath Manager::vLAN(IntfName interfaceName, uint32_t id)
{
    return interfaces[interfaceName]->createVLAN(id);
}

void Manager::reset()
{
    if (!createDefaultNetworkFiles(true))
    {
        log<level::ERR>("Network Factory Reset failed.");
        return;
        // TODO: openbmc/openbmc#1721 - Log ResetFailed error here.
    }

    log<level::INFO>("Network Factory Reset done.");
}

// Need to merge the below function with the code which writes the
// config file during factory reset.
// TODO openbmc/openbmc#1751
void Manager::writeToConfigurationFile()
{
    // write all the static ip address in the systemd-network conf file
    for (const auto& intf : interfaces)
    {
        intf.second->writeConfigurationFile();
    }
    restartTimers();
}

void Manager::restartTimers()
{
    using namespace std::chrono;
    if (refreshObjectTimer && restartTimer)
    {
        restartTimer->restartOnce(restartTimeout);
        refreshObjectTimer->restartOnce(refreshTimeout);
    }
}

void Manager::restartSystemdUnit(const std::string& unit)
{
    try
    {
        auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                          SYSTEMD_INTERFACE, "ResetFailedUnit");
        method.append(unit);
        bus.call_noreply(method);
    }
    catch (const sdbusplus::exception::SdBusError& ex)
    {
        log<level::ERR>("Failed to reset failed unit",
                        entry("UNIT=%s", unit.c_str()),
                        entry("ERR=%s", ex.what()));
        elog<InternalFailure>();
    }

    try
    {
        auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                          SYSTEMD_INTERFACE, "RestartUnit");
        method.append(unit.c_str(), "replace");
        bus.call_noreply(method);
    }
    catch (const sdbusplus::exception::SdBusError& ex)
    {
        log<level::ERR>("Failed to restart service", entry("ERR=%s", ex.what()),
                        entry("UNIT=%s", unit.c_str()));
        elog<InternalFailure>();
    }
}

} // namespace network
} // namespace phosphor
<|endoftext|>


<commit_before><commit_msg>WaE: array subscript is above array bounds<commit_after><|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 {

/*
Randomly select initial means from data set (Forgy method).
*/
template <typename T, size_t N>
std::vector<std::array<T, N>> random_sample(const std::vector<std::array<T, N>>& data, uint32_t k) {
	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());
	std::uniform_int_distribution<input_size_t> uniform_generator(0, data.size());
	for (uint32_t i = 0; i < k; ++i) {
		means.push_back(data[uniform_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).
TODO: formatting
*/
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).

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 [Forgy method](https://en.wikipedia.org/wiki/K-means_clustering#Initialization_methods)
used for initializing the means.
*/
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_sample(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>Modified k-means algorithm to use kmeans++ initialization.<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;
}

/*
Randomly select initial means from data set (Forgy method).
*/
template <typename T, size_t N>
std::vector<std::array<T, N>> random_sample(const std::vector<std::array<T, N>>& data, uint32_t k) {
	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());
	std::uniform_int_distribution<input_size_t> uniform_generator(0, data.size());
	for (uint32_t i = 0; i < k; ++i) {
		means.push_back(data[uniform_generator(rand_engine)]);
	}
	return means;
}

/*
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) {
	std::vector<T> distances(N);
	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());
		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);
		// 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).
TODO: formatting
*/
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).

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 [Forgy method](https://en.wikipedia.org/wiki/K-means_clustering#Initialization_methods)
used for initializing the means.

TODO: Implement kmeans++ to avoid converging on local minima
*/
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 */
<|endoftext|>


<commit_before>/*
 * RewriteLink.cc
 *
 * Copyright (C) 2017 Nil Geisweiller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <string>

#include <opencog/util/mt19937ar.h>
#include <opencog/util/random.h>
#include <opencog/util/Logger.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/TypeNode.h>
#include <opencog/atomutils/TypeUtils.h>
#include <opencog/atomutils/FindUtils.h>

#include "LambdaLink.h"
#include "RewriteLink.h"

using namespace opencog;

void RewriteLink::init(void)
{
	Type t = get_type();
	if (not classserver().isA(t, REWRITE_LINK))
	{
		const std::string& tname = classserver().getTypeName(t);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a RewriteLink, got %s", tname.c_str());
	}
}

RewriteLink::RewriteLink(const Handle& vars, const Handle& body)
	: ScopeLink(HandleSeq({vars, body}), REWRITE_LINK), _silent(false)
{
	init();
}

RewriteLink::RewriteLink(const HandleSeq& oset, Type t)
	: ScopeLink(oset, t), _silent(false)
{
	if (skip_init(t)) return;
	init();
}

RewriteLink::RewriteLink(const Link &l)
	: ScopeLink(l), _silent(false)
{
	if (skip_init(l.get_type())) return;
	init();
}

/* ================================================================= */

inline Handle append_rand_str(const Handle& var)
{
	std::string new_var_name = randstr(var->get_name() + "-");
	return createNode(VARIABLE_NODE, new_var_name);
}

inline HandleSeq append_rand_str(const HandleSeq& vars)
{
	HandleSeq new_vars;
	for (const Handle& h : vars)
		new_vars.push_back(append_rand_str(h));
	return new_vars;
}

Handle RewriteLink::alpha_convert() const
{
	HandleSeq vars = append_rand_str(_varlist.varseq);
	return alpha_convert(vars);
}

Handle RewriteLink::alpha_convert(const HandleSeq& vars) const
{
	// Perform alpha conversion
	HandleSeq hs;
	for (size_t i = 0; i < get_arity(); ++i)
		hs.push_back(_varlist.substitute_nocheck(getOutgoingAtom(i), vars, _silent));

	// Create the alpha converted scope link
	return createLink(hs, get_type());
}

Handle RewriteLink::alpha_convert(const HandleMap& vsmap) const
{
	HandleSeq vars;
	for (const Handle& var : _varlist.varseq) {
		auto it = vsmap.find(var);
		vars.push_back(it == vsmap.end() ? append_rand_str(var) : it->second);
	}
	return alpha_convert(vars);
}

/* ================================================================= */

Handle RewriteLink::beta_reduce(const HandleMap& vm) const
{
	// Perform substitution over the variable declaration
	Handle nvardecl = substitute_vardecl(vm);

	// Perform substitution over the bodies
	HandleSeq hs = substitute_bodies(nvardecl, vm);

	// Filter vardecl
	nvardecl = filter_vardecl(nvardecl, hs);

	// Insert vardecl in the outgoing set, if defined
	if (nvardecl)
	{
		hs.insert(hs.begin(), nvardecl);
	}
	else
	{
		// Its illegal to create a PutLink that is not in the
		// form of a redex, i.e. doesn't have variable declarations
		// in it. So we must not call createLink(), below.
		Type t = get_type();
		if (PUT_LINK == t or LAMBDA_LINK == t)
			return hs[0];
	}

	// Create the substituted scope.  I suspect that this is a bad
	// idea, when nvardecl==nullptr, I mean, its just gonna be weird,
	// and cause issues thhrought the code ... but ... whatever.
	return createLink(hs, get_type());
}

Handle RewriteLink::beta_reduce(const HandleSeq& vals) const
{
	const Variables& vars = get_variables();
	if (vals.size() != vars.size())
	{
		if (1 != vals.size() or LAMBDA_LINK != vals[0]->get_type())
		{
			if (_silent) return Handle::UNDEFINED;

			throw SyntaxException(TRACE_INFO,
				"RewriteLink has mismatched arity, expecting %lu == %lu",
				vars.size(), vals.size());
		}

		// Verify that eta reduction is possible...
		LambdaLinkPtr lam(LambdaLinkCast(vals[0]));
		const Handle& body = lam->get_body();
		if (body->get_arity() != vars.size())
		{
			if (_silent) return Handle::UNDEFINED;

			throw SyntaxException(TRACE_INFO,
				"RewriteLink has mismatched eta, expecting %lu == %lu",
				vars.size(), body->get_arity());
		}

	}

	if (vals.size() != vars.size() and
	    1 == vals.size() and
       LAMBDA_LINK == vals[0]->get_type())
	{
		// Perform a very simple-minded eta reduction.
		LambdaLinkPtr lam(LambdaLinkCast(vals[0]));
		const Handle& body = lam->get_body();
		const HandleSeq& eta = body->getOutgoingSet();
		HandleMap vm;

		for (size_t i=0; i<eta.size(); i++)
			vm.insert({vars.varseq[i], eta[i]});
		return beta_reduce(vm);
	}

	HandleMap vm;
	for (size_t i=0; i<vals.size(); i++)
	{
		vm.insert({vars.varseq[i], vals[i]});
	}
	return beta_reduce(vm);
}

HandleSeq RewriteLink::substitute_bodies(const Handle& nvardecl,
                                         const HandleMap& vm) const
{
	const Variables& variables = get_variables();
	return beta_reduce_bodies(nvardecl, variables.make_sequence(vm));
}

HandleSeq RewriteLink::beta_reduce_bodies(const Handle& nvardecl,
                                         const HandleSeq& values) const
{
	HandleSeq hs;
	for (size_t i = (get_vardecl() ? 1 : 0); i < get_arity(); ++i)
	{
		const Handle& h = getOutgoingAtom(i);
		hs.push_back(substitute_body(nvardecl, h, values));
	}
	return hs;
}

Handle RewriteLink::substitute_body(const Handle& nvardecl,
                                    const Handle& body,
                                    const HandleSeq& values) const
{
	Handle nbody = get_variables().substitute(body, values, _silent);
	nbody = consume_ill_quotations(nvardecl, nbody);
	return nbody;
}

Handle RewriteLink::substitute_vardecl(const HandleMap& vm) const
{
	if (not get_vardecl())
		return Handle::UNDEFINED;

	return substitute_vardecl(get_vardecl(), vm);
}

Handle RewriteLink::substitute_vardecl(const Handle& vardecl,
                                       const HandleMap& vm)
{
	Type t = vardecl->get_type();

	// Base cases

	if (t == VARIABLE_NODE)
	{
		auto it = vm.find(vardecl);

		// Only substitute if the variable is substituted by another variable
		if (it == vm.end())
			return vardecl;
		if (it->second->get_type() == VARIABLE_NODE)
			return it->second;
		return Handle::UNDEFINED;
	}

	// Recursive cases

	HandleSeq oset;

	if (t == VARIABLE_LIST)
	{
		for (const Handle& h : vardecl->getOutgoingSet())
		{
			Handle nh = substitute_vardecl(h, vm);
			if (nh)
				oset.push_back(nh);
		}
		if (oset.empty())
			return Handle::UNDEFINED;
	}
	else if (t == TYPED_VARIABLE_LINK)
	{
		Handle new_var = substitute_vardecl(vardecl->getOutgoingAtom(0), vm);
		if (new_var)
		{
			oset.push_back(new_var);
			oset.push_back(vardecl->getOutgoingAtom(1));
		}
		else
			return Handle::UNDEFINED;
	}
	else
	{
		OC_ASSERT(false, "Not implemented");
	}
	return createLink(oset, t);
}

Handle RewriteLink::consume_ill_quotations() const
{
	Handle vardecl = get_vardecl();
	const Variables& variables = get_variables();
	HandleSeq nouts;
	for (size_t i = (get_vardecl() ? 1 : 0); i < get_arity(); ++i)
	{
		Handle nbody = consume_ill_quotations(variables, getOutgoingAtom(i));
		nouts.push_back(nbody);
		// If the new body has terms with free variables but no
		// vardecl it means that some quotations are missing. Rather
		// than adding them we set vardecl to an empty VariableList.
		if (not vardecl and not get_free_variables(nbody).empty())
			vardecl = Handle(createVariableList(HandleSeq{}));
	}

	if (vardecl)
		nouts.insert(nouts.begin(), vardecl);

	// Recreate the scope
	return createLink(nouts, get_type());
}

Handle RewriteLink::consume_ill_quotations(const Handle& vardecl,
                                           const Handle& h)
{
	return consume_ill_quotations(gen_variables(h, vardecl), h);
}

Handle RewriteLink::consume_ill_quotations(const Variables& variables, Handle h,
                                           Quotation quotation, bool escape)
{
	// Base case
	if (h->is_node())
		return h;

	// Recursive cases
	Type t = h->get_type();
	if (quotation.consumable(t)) {
		if (t == QUOTE_LINK) {
			Handle qh = h->getOutgoingAtom(0);
			// If it's a scope, check whether its vardecl is bound to
			// itself rather than the ancestor scope, if so the Quote
			// is harmful, consume it. Otherwise, for other quoted
			// link types, do not consume the quote and the subsequent
			// unquotes.
			if (classserver().isA(qh->get_type(), SCOPE_LINK) and
			    not is_bound_to_ancestor(variables, qh))
			{
				quotation.update(t);
				return consume_ill_quotations(variables, qh, quotation);
			} else {
				escape = true;
			}
		} else if (t == UNQUOTE_LINK) {
			Handle uh = h->getOutgoingAtom(0);
			// Either remove subsequent unquote associated by a
			// removed quote, or useless unquote because there are no
			// free variables to unquote
			if (not escape or get_free_variables(uh).empty()) {
				quotation.update(t);
				return consume_ill_quotations(variables, h->getOutgoingAtom(0),
				                              quotation);
			}
		}
		// Ignore LocalQuotes as they supposedly used only to quote
		// pattern matcher connectors.
	}

	quotation.update(t);
	HandleSeq consumed;
	for (const Handle outh : h->getOutgoingSet())
		consumed.push_back(consume_ill_quotations(variables, outh, quotation,
		                                          escape));

	return createLink(consumed, t);
}

bool RewriteLink::is_bound_to_ancestor(const Variables& variables,
                                       const Handle& local_scope)
{
	Handle unquote = local_scope->getOutgoingAtom(0);
	if (unquote->get_type() == UNQUOTE_LINK) {
		Handle var = unquote->getOutgoingAtom(0);
		return variables.is_in_varset(var);
	}
	return false;
}

/* ================================================================= */

DEFINE_LINK_FACTORY(RewriteLink, REWRITE_LINK);

/* ===================== END OF FILE ===================== */
<commit_msg>Minor reorganization for clarity<commit_after>/*
 * RewriteLink.cc
 *
 * Copyright (C) 2017 Nil Geisweiller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <string>

#include <opencog/util/mt19937ar.h>
#include <opencog/util/random.h>
#include <opencog/util/Logger.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/TypeNode.h>
#include <opencog/atomutils/TypeUtils.h>
#include <opencog/atomutils/FindUtils.h>

#include "LambdaLink.h"
#include "RewriteLink.h"

using namespace opencog;

void RewriteLink::init(void)
{
	Type t = get_type();
	if (not classserver().isA(t, REWRITE_LINK))
	{
		const std::string& tname = classserver().getTypeName(t);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a RewriteLink, got %s", tname.c_str());
	}
}

RewriteLink::RewriteLink(const Handle& vars, const Handle& body)
	: ScopeLink(HandleSeq({vars, body}), REWRITE_LINK), _silent(false)
{
	init();
}

RewriteLink::RewriteLink(const HandleSeq& oset, Type t)
	: ScopeLink(oset, t), _silent(false)
{
	if (skip_init(t)) return;
	init();
}

RewriteLink::RewriteLink(const Link &l)
	: ScopeLink(l), _silent(false)
{
	if (skip_init(l.get_type())) return;
	init();
}

/* ================================================================= */

inline Handle append_rand_str(const Handle& var)
{
	std::string new_var_name = randstr(var->get_name() + "-");
	return createNode(VARIABLE_NODE, new_var_name);
}

inline HandleSeq append_rand_str(const HandleSeq& vars)
{
	HandleSeq new_vars;
	for (const Handle& h : vars)
		new_vars.push_back(append_rand_str(h));
	return new_vars;
}

Handle RewriteLink::alpha_convert() const
{
	HandleSeq vars = append_rand_str(_varlist.varseq);
	return alpha_convert(vars);
}

Handle RewriteLink::alpha_convert(const HandleSeq& vars) const
{
	// Perform alpha conversion
	HandleSeq hs;
	for (size_t i = 0; i < get_arity(); ++i)
		hs.push_back(_varlist.substitute_nocheck(getOutgoingAtom(i), vars, _silent));

	// Create the alpha converted scope link
	return createLink(hs, get_type());
}

Handle RewriteLink::alpha_convert(const HandleMap& vsmap) const
{
	HandleSeq vars;
	for (const Handle& var : _varlist.varseq) {
		auto it = vsmap.find(var);
		vars.push_back(it == vsmap.end() ? append_rand_str(var) : it->second);
	}
	return alpha_convert(vars);
}

/* ================================================================= */

Handle RewriteLink::beta_reduce(const HandleMap& vm) const
{
	// Perform substitution over the variable declaration
	Handle nvardecl = substitute_vardecl(vm);

	// Perform substitution over the bodies
	HandleSeq hs = substitute_bodies(nvardecl, vm);

	// Filter vardecl
	nvardecl = filter_vardecl(nvardecl, hs);

	// Insert vardecl in the outgoing set, if defined
	if (nvardecl)
	{
		hs.insert(hs.begin(), nvardecl);
	}
	else
	{
		// Its illegal to create a PutLink that is not in the
		// form of a redex, i.e. doesn't have variable declarations
		// in it. So we must not call createLink(), below.
		Type t = get_type();
		if (PUT_LINK == t or LAMBDA_LINK == t)
			return hs[0];
	}

	// Create the substituted scope.  I suspect that this is a bad
	// idea, when nvardecl==nullptr, I mean, its just gonna be weird,
	// and cause issues thhrought the code ... but ... whatever.
	return createLink(hs, get_type());
}

Handle RewriteLink::beta_reduce(const HandleSeq& vals) const
{
	const Variables& vars = get_variables();
	if (vals.size() != vars.size())
	{
		if (1 != vals.size() or LAMBDA_LINK != vals[0]->get_type())
		{
			if (_silent) return Handle::UNDEFINED;

			throw SyntaxException(TRACE_INFO,
				"RewriteLink has mismatched arity, expecting %lu == %lu",
				vars.size(), vals.size());
		}

		// Verify that eta reduction is possible...
		LambdaLinkPtr lam(LambdaLinkCast(vals[0]));
		const Handle& body = lam->get_body();
		if (body->get_arity() != vars.size())
		{
			if (_silent) return Handle::UNDEFINED;

			throw SyntaxException(TRACE_INFO,
				"RewriteLink has mismatched eta, expecting %lu == %lu",
				vars.size(), body->get_arity());
		}

		// Perform a very simple-minded eta reduction.
		// This will be incorrect under a variety of corner cases,
		// but gives approximately correct results for the simple case.
		const HandleSeq& eta = body->getOutgoingSet();
		HandleMap vm;

		for (size_t i=0; i<eta.size(); i++)
			vm.insert({vars.varseq[i], eta[i]});
		return beta_reduce(vm);
	}

	HandleMap vm;
	for (size_t i=0; i<vals.size(); i++)
	{
		vm.insert({vars.varseq[i], vals[i]});
	}
	return beta_reduce(vm);
}

HandleSeq RewriteLink::substitute_bodies(const Handle& nvardecl,
                                         const HandleMap& vm) const
{
	const Variables& variables = get_variables();
	return beta_reduce_bodies(nvardecl, variables.make_sequence(vm));
}

HandleSeq RewriteLink::beta_reduce_bodies(const Handle& nvardecl,
                                         const HandleSeq& values) const
{
	HandleSeq hs;
	for (size_t i = (get_vardecl() ? 1 : 0); i < get_arity(); ++i)
	{
		const Handle& h = getOutgoingAtom(i);
		hs.push_back(substitute_body(nvardecl, h, values));
	}
	return hs;
}

Handle RewriteLink::substitute_body(const Handle& nvardecl,
                                    const Handle& body,
                                    const HandleSeq& values) const
{
	Handle nbody = get_variables().substitute(body, values, _silent);
	nbody = consume_ill_quotations(nvardecl, nbody);
	return nbody;
}

Handle RewriteLink::substitute_vardecl(const HandleMap& vm) const
{
	if (not get_vardecl())
		return Handle::UNDEFINED;

	return substitute_vardecl(get_vardecl(), vm);
}

Handle RewriteLink::substitute_vardecl(const Handle& vardecl,
                                       const HandleMap& vm)
{
	Type t = vardecl->get_type();

	// Base cases

	if (t == VARIABLE_NODE)
	{
		auto it = vm.find(vardecl);

		// Only substitute if the variable is substituted by another variable
		if (it == vm.end())
			return vardecl;
		if (it->second->get_type() == VARIABLE_NODE)
			return it->second;
		return Handle::UNDEFINED;
	}

	// Recursive cases

	HandleSeq oset;

	if (t == VARIABLE_LIST)
	{
		for (const Handle& h : vardecl->getOutgoingSet())
		{
			Handle nh = substitute_vardecl(h, vm);
			if (nh)
				oset.push_back(nh);
		}
		if (oset.empty())
			return Handle::UNDEFINED;
	}
	else if (t == TYPED_VARIABLE_LINK)
	{
		Handle new_var = substitute_vardecl(vardecl->getOutgoingAtom(0), vm);
		if (new_var)
		{
			oset.push_back(new_var);
			oset.push_back(vardecl->getOutgoingAtom(1));
		}
		else
			return Handle::UNDEFINED;
	}
	else
	{
		OC_ASSERT(false, "Not implemented");
	}
	return createLink(oset, t);
}

Handle RewriteLink::consume_ill_quotations() const
{
	Handle vardecl = get_vardecl();
	const Variables& variables = get_variables();
	HandleSeq nouts;
	for (size_t i = (get_vardecl() ? 1 : 0); i < get_arity(); ++i)
	{
		Handle nbody = consume_ill_quotations(variables, getOutgoingAtom(i));
		nouts.push_back(nbody);
		// If the new body has terms with free variables but no
		// vardecl it means that some quotations are missing. Rather
		// than adding them we set vardecl to an empty VariableList.
		if (not vardecl and not get_free_variables(nbody).empty())
			vardecl = Handle(createVariableList(HandleSeq{}));
	}

	if (vardecl)
		nouts.insert(nouts.begin(), vardecl);

	// Recreate the scope
	return createLink(nouts, get_type());
}

Handle RewriteLink::consume_ill_quotations(const Handle& vardecl,
                                           const Handle& h)
{
	return consume_ill_quotations(gen_variables(h, vardecl), h);
}

Handle RewriteLink::consume_ill_quotations(const Variables& variables, Handle h,
                                           Quotation quotation, bool escape)
{
	// Base case
	if (h->is_node())
		return h;

	// Recursive cases
	Type t = h->get_type();
	if (quotation.consumable(t)) {
		if (t == QUOTE_LINK) {
			Handle qh = h->getOutgoingAtom(0);
			// If it's a scope, check whether its vardecl is bound to
			// itself rather than the ancestor scope, if so the Quote
			// is harmful, consume it. Otherwise, for other quoted
			// link types, do not consume the quote and the subsequent
			// unquotes.
			if (classserver().isA(qh->get_type(), SCOPE_LINK) and
			    not is_bound_to_ancestor(variables, qh))
			{
				quotation.update(t);
				return consume_ill_quotations(variables, qh, quotation);
			} else {
				escape = true;
			}
		} else if (t == UNQUOTE_LINK) {
			Handle uh = h->getOutgoingAtom(0);
			// Either remove subsequent unquote associated by a
			// removed quote, or useless unquote because there are no
			// free variables to unquote
			if (not escape or get_free_variables(uh).empty()) {
				quotation.update(t);
				return consume_ill_quotations(variables, h->getOutgoingAtom(0),
				                              quotation);
			}
		}
		// Ignore LocalQuotes as they supposedly used only to quote
		// pattern matcher connectors.
	}

	quotation.update(t);
	HandleSeq consumed;
	for (const Handle outh : h->getOutgoingSet())
		consumed.push_back(consume_ill_quotations(variables, outh, quotation,
		                                          escape));

	return createLink(consumed, t);
}

bool RewriteLink::is_bound_to_ancestor(const Variables& variables,
                                       const Handle& local_scope)
{
	Handle unquote = local_scope->getOutgoingAtom(0);
	if (unquote->get_type() == UNQUOTE_LINK) {
		Handle var = unquote->getOutgoingAtom(0);
		return variables.is_in_varset(var);
	}
	return false;
}

/* ================================================================= */

DEFINE_LINK_FACTORY(RewriteLink, REWRITE_LINK);

/* ===================== END OF FILE ===================== */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pointaction.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:20:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <pointaction.hxx>
#include <outdevstate.hxx>
#include <cppcanvas/canvas.hxx>

#ifndef _RTL_LOGFILE_HXX_
#include <rtl/logfile.hxx>
#endif
#ifndef _COM_SUN_STAR_RENDERING_XCANVAS_HPP_
#include <com/sun/star/rendering/XCanvas.hpp>
#endif

#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif
#ifndef _VCL_CANVASTOOLS_HXX
#include <vcl/canvastools.hxx>
#endif

#ifndef _BGFX_RANGE_B2DRANGE_HXX
#include <basegfx/range/b2drange.hxx>
#endif
#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
#include <basegfx/tools/canvastools.hxx>
#endif
#ifndef _CANVAS_CANVASTOOLS_HXX
#include <canvas/canvastools.hxx>
#endif

#include <boost/utility.hpp>

#include <mtftools.hxx>

using namespace ::com::sun::star;

namespace cppcanvas
{
    namespace internal
    {
        namespace
        {
            class PointAction : public Action, private ::boost::noncopyable
            {
            public:
                PointAction( const ::Point&,
                             const CanvasSharedPtr&,
                             const OutDevState& );
                PointAction( const ::Point&,
                             const CanvasSharedPtr&,
                             const OutDevState&,
                             const ::Color&     );

                virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
                virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
                                     const Subset&                  rSubset ) const;

                virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
                virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
                                                       const Subset&                    rSubset ) const;

                virtual sal_Int32 getActionCount() const;

            private:
                // default: disabled copy/assignment
                PointAction(const PointAction&);
                PointAction& operator = ( const PointAction& );

                ::Point                                     maPoint;
                CanvasSharedPtr                             mpCanvas;
                ::com::sun::star::rendering::RenderState    maState;
            };

            PointAction::PointAction( const ::Point&            rPoint,
                                      const CanvasSharedPtr&    rCanvas,
                                      const OutDevState&        rState ) :
                maPoint( rPoint ),
                mpCanvas( rCanvas ),
                maState()
            {
                tools::initRenderState(maState,rState);
                maState.DeviceColor = rState.lineColor;
            }

            PointAction::PointAction( const ::Point&            rPoint,
                                      const CanvasSharedPtr&    rCanvas,
                                      const OutDevState&        rState,
                                      const ::Color&            rAltColor ) :
                maPoint( rPoint ),
                mpCanvas( rCanvas ),
                maState()
            {
                tools::initRenderState(maState,rState);
                maState.DeviceColor = ::vcl::unotools::colorToDoubleSequence( rCanvas->getUNOCanvas()->getDevice(),
                                                                              rAltColor );
            }

            bool PointAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
            {
                RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PointAction::render()" );
                RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PointAction: 0x%X", this );

                rendering::RenderState aLocalState( maState );
                ::canvas::tools::prependToRenderState(aLocalState, rTransformation);

                mpCanvas->getUNOCanvas()->drawPoint( ::vcl::unotools::point2DFromPoint(maPoint),
                                                     mpCanvas->getViewState(),
                                                     aLocalState );

                return true;
            }

            bool PointAction::render( const ::basegfx::B2DHomMatrix&    rTransformation,
                                      const Subset&                     rSubset ) const
            {
                // point only contains a single action, fail if subset
                // requests different range
                if( rSubset.mnSubsetBegin != 0 ||
                    rSubset.mnSubsetEnd != 1 )
                    return false;

                return render( rTransformation );
            }

            ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix&  rTransformation ) const
            {
                rendering::RenderState aLocalState( maState );
                ::canvas::tools::prependToRenderState(aLocalState, rTransformation);

                return tools::calcDevicePixelBounds( ::basegfx::B2DRange( maPoint.X()-1,
                                                                          maPoint.Y()-1,
                                                                          maPoint.X()+1,
                                                                          maPoint.Y()+1 ),
                                                     mpCanvas->getViewState(),
                                                     aLocalState );
            }

            ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix&  rTransformation,
                                                        const Subset&                   rSubset ) const
            {
                // point only contains a single action, empty bounds
                // if subset requests different range
                if( rSubset.mnSubsetBegin != 0 ||
                    rSubset.mnSubsetEnd != 1 )
                    return ::basegfx::B2DRange();

                return getBounds( rTransformation );
            }

            sal_Int32 PointAction::getActionCount() const
            {
                return 1;
            }
        }

        ActionSharedPtr PointActionFactory::createPointAction( const ::Point&           rPoint,
                                                               const CanvasSharedPtr&   rCanvas,
                                                               const OutDevState&       rState )
        {
            return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState ) );
        }

        ActionSharedPtr PointActionFactory::createPointAction( const ::Point&           rPoint,
                                                               const CanvasSharedPtr&   rCanvas,
                                                               const OutDevState&       rState,
                                                               const ::Color&           rColor  )
        {
            return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState, rColor ) );
        }
    }
}
<commit_msg>INTEGRATION: CWS canvas02 (1.6.4); FILE MERGED 2005/10/09 09:13:43 thb 1.6.4.2: RESYNC: (1.6-1.7); FILE MERGED 2005/08/24 23:02:57 thb 1.6.4.1: #i52876# Added CachedPrimitiveBase base class for common XCachedPrimitive handling; removed external header guards from cxx files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pointaction.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2005-11-02 13:41:31 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <rtl/logfile.hxx>
#include <com/sun/star/rendering/XCanvas.hpp>

#include <tools/gen.hxx>
#include <vcl/canvastools.hxx>

#include <basegfx/range/b2drange.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <canvas/canvastools.hxx>

#include <boost/utility.hpp>

#include "pointaction.hxx"
#include "outdevstate.hxx"
#include "cppcanvas/canvas.hxx"
#include "mtftools.hxx"

using namespace ::com::sun::star;

namespace cppcanvas
{
    namespace internal
    {
        namespace
        {
            class PointAction : public Action, private ::boost::noncopyable
            {
            public:
                PointAction( const ::Point&,
                             const CanvasSharedPtr&,
                             const OutDevState& );
                PointAction( const ::Point&,
                             const CanvasSharedPtr&,
                             const OutDevState&,
                             const ::Color&     );

                virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
                virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
                                     const Subset&                  rSubset ) const;

                virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
                virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
                                                       const Subset&                    rSubset ) const;

                virtual sal_Int32 getActionCount() const;

            private:
                // default: disabled copy/assignment
                PointAction(const PointAction&);
                PointAction& operator = ( const PointAction& );

                ::Point                                     maPoint;
                CanvasSharedPtr                             mpCanvas;
                ::com::sun::star::rendering::RenderState    maState;
            };

            PointAction::PointAction( const ::Point&            rPoint,
                                      const CanvasSharedPtr&    rCanvas,
                                      const OutDevState&        rState ) :
                maPoint( rPoint ),
                mpCanvas( rCanvas ),
                maState()
            {
                tools::initRenderState(maState,rState);
                maState.DeviceColor = rState.lineColor;
            }

            PointAction::PointAction( const ::Point&            rPoint,
                                      const CanvasSharedPtr&    rCanvas,
                                      const OutDevState&        rState,
                                      const ::Color&            rAltColor ) :
                maPoint( rPoint ),
                mpCanvas( rCanvas ),
                maState()
            {
                tools::initRenderState(maState,rState);
                maState.DeviceColor = ::vcl::unotools::colorToDoubleSequence( rCanvas->getUNOCanvas()->getDevice(),
                                                                              rAltColor );
            }

            bool PointAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
            {
                RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PointAction::render()" );
                RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PointAction: 0x%X", this );

                rendering::RenderState aLocalState( maState );
                ::canvas::tools::prependToRenderState(aLocalState, rTransformation);

                mpCanvas->getUNOCanvas()->drawPoint( ::vcl::unotools::point2DFromPoint(maPoint),
                                                     mpCanvas->getViewState(),
                                                     aLocalState );

                return true;
            }

            bool PointAction::render( const ::basegfx::B2DHomMatrix&    rTransformation,
                                      const Subset&                     rSubset ) const
            {
                // point only contains a single action, fail if subset
                // requests different range
                if( rSubset.mnSubsetBegin != 0 ||
                    rSubset.mnSubsetEnd != 1 )
                    return false;

                return render( rTransformation );
            }

            ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix&  rTransformation ) const
            {
                rendering::RenderState aLocalState( maState );
                ::canvas::tools::prependToRenderState(aLocalState, rTransformation);

                return tools::calcDevicePixelBounds( ::basegfx::B2DRange( maPoint.X()-1,
                                                                          maPoint.Y()-1,
                                                                          maPoint.X()+1,
                                                                          maPoint.Y()+1 ),
                                                     mpCanvas->getViewState(),
                                                     aLocalState );
            }

            ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix&  rTransformation,
                                                        const Subset&                   rSubset ) const
            {
                // point only contains a single action, empty bounds
                // if subset requests different range
                if( rSubset.mnSubsetBegin != 0 ||
                    rSubset.mnSubsetEnd != 1 )
                    return ::basegfx::B2DRange();

                return getBounds( rTransformation );
            }

            sal_Int32 PointAction::getActionCount() const
            {
                return 1;
            }
        }

        ActionSharedPtr PointActionFactory::createPointAction( const ::Point&           rPoint,
                                                               const CanvasSharedPtr&   rCanvas,
                                                               const OutDevState&       rState )
        {
            return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState ) );
        }

        ActionSharedPtr PointActionFactory::createPointAction( const ::Point&           rPoint,
                                                               const CanvasSharedPtr&   rCanvas,
                                                               const OutDevState&       rState,
                                                               const ::Color&           rColor  )
        {
            return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState, rColor ) );
        }
    }
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <exception>
#include <sstream>

#include <boost/format.hpp>
#include "Rinternals.h"

#include "Bee/Client.h"

using namespace apache::thrift;
using namespace apache::hive::service::cli::thrift;

typedef struct {
  unsigned char bytes[4];
} Quad;

static Quad big_endian(int i) {
  return Quad {
    .bytes = {
      static_cast<unsigned char>((i & 0xff000000) >> 24),
      static_cast<unsigned char>((i & 0x00ff0000) >> 16),
      static_cast<unsigned char>((i & 0x0000ff00) >>  8),
      static_cast<unsigned char>((i & 0x000000ff) >>  0)
    }
  };
}

Bee::Client::Client(const std::string &hostname, int port, const std::string &user, const std::string &pass) :
  user_(user),
  pass_(pass),
  socket_(new transport::TSocket(hostname, port)),
  transport_(new transport::TFramedTransport(socket_)),
  protocol_(new protocol::TBinaryProtocol(transport_)),
  client_(new apache::hive::service::cli::thrift::TCLIServiceClient(protocol_)),
  session_handle_(),
  operation_handle_() {
    this->transport_->open();
    this->perform_sasl_handshake();
    this->open_session();
}

void Bee::Client::disconnect() {
  if (this->transport_->isOpen()) {
    this->transport_->close();
  }
}

void Bee::Client::execute(const std::string &sql) {
  this->ensure_connected();

  TExecuteStatementReq request;
  TExecuteStatementResp response;
  request.sessionHandle = this->session_handle_;
  request.statement = sql;

  this->client_->ExecuteStatement(response, request);
  this->operation_handle_ = response.operationHandle;
}

Rcpp::List Bee::Client::fetch(int num_rows) {
  this->ensure_connected();

  if (num_rows < 1) {
    throw std::runtime_error("num_rows must be > 1");
  }

  TFetchResultsReq result_request;
  TFetchResultsResp result_response;
  TGetResultSetMetadataReq metadata_request;
  TGetResultSetMetadataResp metadata_response;

  result_request.operationHandle = this->operation_handle_;
  result_request.orientation = TFetchOrientation::FETCH_NEXT;
  result_request.maxRows = num_rows;
  this->client_->FetchResults(result_response, result_request);

  // TFetchResultsResp.hasMoreRows is currently broken, so just keep going until
  // we fall short.
  this->has_more_rows_ = result_response.results.rows.size() >= num_rows;

  metadata_request.operationHandle = this->operation_handle_;
  this->client_->GetResultSetMetadata(metadata_response, metadata_request);

  return build_data_frame(metadata_response.schema, result_response.results);
}

bool Bee::Client::has_more_rows() const {
  return this->has_more_rows_;
}

std::string Bee::Client::inspect() {
  std::ostringstream out;
  out << "Bee::Client[" <<
    "hostname=" << this->socket_->getHost() <<
    ", port=" << this->socket_->getPort() <<
    ", user=" << this->user_ <<
    ", pass=" << this->pass_ <<
    (this->transport_->isOpen() ? ", connected" : "") <<
    (this->has_session_handle() ? ", in session" : "") <<
    (this->has_operation_handle() ? ", in operation" : "") <<
    "]";
  return out.str();
}

void Bee::Client::write_frame(const std::string &bytes) {
  Quad length = big_endian(bytes.size());
  this->socket_->write(length.bytes, 4);
  this->socket_->write(reinterpret_cast<const unsigned char *>(bytes.c_str()), bytes.size());
}

boost::shared_ptr<std::string> Bee::Client::read_frame() {
  unsigned int length = 0;
  unsigned char length_buffer[5];
  this->socket_->read(length_buffer, 4);
  length_buffer[4] = '\0';
  for (int i = 0; i < 4; ++i) {
    length += static_cast<int>(length_buffer[1 + i]) << i;
  }

  if (length == 0) {
    return boost::shared_ptr<std::string>(new std::string(""));
  } else {
    char message[length];
    this->socket_->read(reinterpret_cast<unsigned char *>(message), length);
    return boost::shared_ptr<std::string>(new std::string(message, length));
  }
}

void Bee::Client::perform_sasl_handshake() {
  // START PLAIN
  {
    unsigned char code = 0x01;
    this->socket_->write(&code, 1);
    this->write_frame("PLAIN");
  }

  // OK PLAIN user pass
  {
    unsigned char code = 0x02;
    this->socket_->write(&code, 1);
    std::ostringstream frame("[PLAIN]\x00");
    frame << user_ << '\0' << pass_;
    this->write_frame(frame.str());
  }

  this->socket_->flush();

  unsigned char status;
  this->socket_->read(&status, 1);

  switch (status) {
  case 3: // bad
  case 4: // error
      throw std::runtime_error(*this->read_frame());

  case 5: // complete
      this->read_frame();  // challenge -- ignored
      break;

  case 2: // ok
    {
      boost::shared_ptr<std::string> message(this->read_frame());
      throw std::runtime_error(std::string("ERROR: auth failed: ") + *message);
      break;
    }

  default:
    throw std::runtime_error("unexpected response from sasl handshake");
  }
}

void Bee::Client::open_session() {
  TOpenSessionReq request;
  TOpenSessionResp response;
  request.client_protocol = TProtocolVersion::HIVE_CLI_SERVICE_PROTOCOL_V3;

  client_->OpenSession(response, request);
  this->session_handle_ = response.sessionHandle;
}

void Bee::Client::ensure_connected() const {
  if (!this->transport_->isOpen())
    throw std::runtime_error("not connected");
}

bool Bee::Client::has_session_handle() const {
  return !this->session_handle_.sessionId.guid.empty();
}

bool Bee::Client::has_operation_handle() const {
  return !this->operation_handle_.operationId.guid.empty();
}

Rcpp::List Bee::Client::build_data_frame(const TTableSchema schema, const TRowSet &row_set) const {
  const unsigned int num_columns = schema.columns.size();
  const unsigned int num_rows = row_set.rows.size();

  Rcpp::List result(num_columns);
  result.attr("class") = "data.frame";
  result.attr("row.names") = Rcpp::IntegerVector::create(NA_INTEGER, -num_rows);

  Rcpp::StringVector names(num_columns, NA_STRING);
  for (unsigned int c = 0; c < num_columns; ++c) {
    names[c] = schema.columns[c].columnName;
  }
  result.attr("names") = names;

  for (unsigned int c = 0; c < num_columns; ++c) {
    if (schema.columns[c].typeDesc.types.size() < 1) {
      throw std::runtime_error("BUG: empty type");
    }

    if (!schema.columns[c].typeDesc.types[0].__isset.primitiveEntry) {
      throw std::runtime_error("ERROR: only primitive types currently supported");
    }

    switch (schema.columns[c].typeDesc.types[0].primitiveEntry.type) {
    case TTypeId::BOOLEAN_TYPE:
      result[c] = build_logical_column_from_bool_value(row_set, c);
      break;

    case TTypeId::TINYINT_TYPE:
      result[c] = build_int_column_from_byte_value(row_set, c);
      break;

    case TTypeId::SMALLINT_TYPE:
      result[c] = build_int_column_from_i16_value(row_set, c);
      break;

    case TTypeId::INT_TYPE:
      result[c] = build_int_column_from_i32_value(row_set, c);
      break;

    case TTypeId::BIGINT_TYPE:
      result[c] = build_int_column_from_i64_value(row_set, c);
      break;

    case TTypeId::FLOAT_TYPE:
    case TTypeId::DOUBLE_TYPE:
      result[c] = build_double_column_from_double_value(row_set, c);
      break;

    case TTypeId::STRING_TYPE:
    case TTypeId::VARCHAR_TYPE:
    case TTypeId::CHAR_TYPE:
    case TTypeId::BINARY_TYPE:
    case TTypeId::TIMESTAMP_TYPE:
    case TTypeId::DATE_TYPE:
      result[c] = build_string_column_from_string_value(row_set, c);
      break;

    case TTypeId::DECIMAL_TYPE:
      result[c] = build_double_column_from_string_value(row_set, c);
      break;

    case TTypeId::NULL_TYPE:  // for "select null"
      result[c] = build_null_column_from_null_value(row_set);
      break;

    case TTypeId::ARRAY_TYPE:
    case TTypeId::MAP_TYPE:
    case TTypeId::STRUCT_TYPE:
    case TTypeId::UNION_TYPE:
    case TTypeId::USER_DEFINED_TYPE:
    default:
      TTypeId::type type_id = schema.columns[c].typeDesc.types[0].primitiveEntry.type;
      boost::format format("ERROR: unsupported column type id: %1%");
      throw std::runtime_error(boost::str(format % type_id));
      build_error_column(row_set, "unsupported column type");
    }
  }

  return result;
}

Rcpp::LogicalVector Bee::Client::build_logical_column_from_bool_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::LogicalVector result(num_rows, NA_LOGICAL);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].boolVal.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_byte_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].byteVal.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_i16_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].i16Val.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_i32_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].i32Val.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_i64_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].i64Val.value;
  }
  return result;
}

Rcpp::StringVector Bee::Client::build_string_column_from_string_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::StringVector result(num_rows, NA_STRING);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].stringVal.value;
  }
  return result;
}

Rcpp::DoubleVector Bee::Client::build_double_column_from_double_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::DoubleVector result(num_rows, NA_REAL);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].doubleVal.value;
  }
  return result;
}

Rcpp::DoubleVector Bee::Client::build_double_column_from_string_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::DoubleVector result(num_rows, NA_REAL);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = atof(row_set.rows[i].colVals[column_index].stringVal.value.c_str());
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_null_column_from_null_value(const TRowSet &row_set) const {
  return Rcpp::IntegerVector(row_set.rows.size(), NA_INTEGER);
}

Rcpp::StringVector Bee::Client::build_error_column(const TRowSet &row_set, const char *error) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::StringVector result(num_rows, NA_STRING);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = error;
  }
  return result;
}
<commit_msg>Clean up some noise.<commit_after>#include <stdlib.h>
#include <exception>
#include <sstream>

#include <boost/format.hpp>
#include "Rinternals.h"

#include "Bee/Client.h"

using namespace apache::thrift;
using namespace apache::hive::service::cli::thrift;

typedef struct {
  unsigned char bytes[4];
} Quad;

static Quad big_endian(int i) {
  return Quad {
    .bytes = {
      static_cast<unsigned char>((i & 0xff000000) >> 24),
      static_cast<unsigned char>((i & 0x00ff0000) >> 16),
      static_cast<unsigned char>((i & 0x0000ff00) >>  8),
      static_cast<unsigned char>((i & 0x000000ff) >>  0)
    }
  };
}

Bee::Client::Client(const std::string &hostname, int port, const std::string &user, const std::string &pass) :
  user_(user),
  pass_(pass),
  socket_(new transport::TSocket(hostname, port)),
  transport_(new transport::TFramedTransport(socket_)),
  protocol_(new protocol::TBinaryProtocol(transport_)),
  client_(new apache::hive::service::cli::thrift::TCLIServiceClient(protocol_)),
  session_handle_(),
  operation_handle_() {
    transport_->open();
    perform_sasl_handshake();
    open_session();
}

void Bee::Client::disconnect() {
  if (transport_->isOpen()) {
    transport_->close();
  }
}

void Bee::Client::execute(const std::string &sql) {
  ensure_connected();

  TExecuteStatementReq request;
  TExecuteStatementResp response;
  request.sessionHandle = session_handle_;
  request.statement = sql;

  client_->ExecuteStatement(response, request);
  operation_handle_ = response.operationHandle;
}

Rcpp::List Bee::Client::fetch(int num_rows) {
  ensure_connected();

  if (num_rows < 1) {
    throw std::runtime_error("num_rows must be > 1");
  }

  TFetchResultsReq result_request;
  TFetchResultsResp result_response;
  TGetResultSetMetadataReq metadata_request;
  TGetResultSetMetadataResp metadata_response;

  result_request.operationHandle = operation_handle_;
  result_request.orientation = TFetchOrientation::FETCH_NEXT;
  result_request.maxRows = num_rows;
  client_->FetchResults(result_response, result_request);

  // TFetchResultsResp.hasMoreRows is currently broken, so just keep going until
  // we fall short.
  has_more_rows_ = result_response.results.rows.size() >= num_rows;

  metadata_request.operationHandle = operation_handle_;
  client_->GetResultSetMetadata(metadata_response, metadata_request);

  return build_data_frame(metadata_response.schema, result_response.results);
}

bool Bee::Client::has_more_rows() const {
  return has_more_rows_;
}

std::string Bee::Client::inspect() {
  std::ostringstream out;
  out << "Bee::Client[" <<
    "hostname=" << socket_->getHost() <<
    ", port=" << socket_->getPort() <<
    ", user=" << user_ <<
    ", pass=" << pass_ <<
    (transport_->isOpen() ? ", connected" : "") <<
    (has_session_handle() ? ", in session" : "") <<
    (has_operation_handle() ? ", in operation" : "") <<
    "]";
  return out.str();
}

void Bee::Client::write_frame(const std::string &bytes) {
  Quad length = big_endian(bytes.size());
  socket_->write(length.bytes, 4);
  socket_->write(reinterpret_cast<const unsigned char *>(bytes.c_str()), bytes.size());
}

boost::shared_ptr<std::string> Bee::Client::read_frame() {
  unsigned int length = 0;
  unsigned char length_buffer[5];
  socket_->read(length_buffer, 4);
  length_buffer[4] = '\0';
  for (int i = 0; i < 4; ++i) {
    length += static_cast<int>(length_buffer[1 + i]) << i;
  }

  if (length == 0) {
    return boost::shared_ptr<std::string>(new std::string(""));
  } else {
    char message[length];
    socket_->read(reinterpret_cast<unsigned char *>(message), length);
    return boost::shared_ptr<std::string>(new std::string(message, length));
  }
}

void Bee::Client::perform_sasl_handshake() {
  // START PLAIN
  {
    unsigned char code = 0x01;
    socket_->write(&code, 1);
    write_frame("PLAIN");
  }

  // OK PLAIN user pass
  {
    unsigned char code = 0x02;
    socket_->write(&code, 1);
    std::ostringstream frame("[PLAIN]\x00");
    frame << user_ << '\0' << pass_;
    write_frame(frame.str());
  }

  socket_->flush();

  unsigned char status;
  socket_->read(&status, 1);

  switch (status) {
  case 3: // bad
  case 4: // error
      throw std::runtime_error(*read_frame());

  case 5: // complete
      read_frame();  // challenge -- ignored
      break;

  case 2: // ok
    {
      boost::shared_ptr<std::string> message(read_frame());
      throw std::runtime_error(std::string("ERROR: auth failed: ") + *message);
      break;
    }

  default:
    throw std::runtime_error("unexpected response from sasl handshake");
  }
}

void Bee::Client::open_session() {
  TOpenSessionReq request;
  TOpenSessionResp response;
  request.client_protocol = TProtocolVersion::HIVE_CLI_SERVICE_PROTOCOL_V3;

  client_->OpenSession(response, request);
  session_handle_ = response.sessionHandle;
}

void Bee::Client::ensure_connected() const {
  if (!transport_->isOpen())
    throw std::runtime_error("not connected");
}

bool Bee::Client::has_session_handle() const {
  return !session_handle_.sessionId.guid.empty();
}

bool Bee::Client::has_operation_handle() const {
  return !operation_handle_.operationId.guid.empty();
}

Rcpp::List Bee::Client::build_data_frame(const TTableSchema schema, const TRowSet &row_set) const {
  const unsigned int num_columns = schema.columns.size();
  const unsigned int num_rows = row_set.rows.size();

  Rcpp::List result(num_columns);
  result.attr("class") = "data.frame";
  result.attr("row.names") = Rcpp::IntegerVector::create(NA_INTEGER, -num_rows);

  Rcpp::StringVector names(num_columns, NA_STRING);
  for (unsigned int c = 0; c < num_columns; ++c) {
    names[c] = schema.columns[c].columnName;
  }
  result.attr("names") = names;

  for (unsigned int c = 0; c < num_columns; ++c) {
    if (schema.columns[c].typeDesc.types.size() < 1) {
      throw std::runtime_error("BUG: empty type");
    }

    if (!schema.columns[c].typeDesc.types[0].__isset.primitiveEntry) {
      throw std::runtime_error("ERROR: only primitive types currently supported");
    }

    switch (schema.columns[c].typeDesc.types[0].primitiveEntry.type) {
    case TTypeId::BOOLEAN_TYPE:
      result[c] = build_logical_column_from_bool_value(row_set, c);
      break;

    case TTypeId::TINYINT_TYPE:
      result[c] = build_int_column_from_byte_value(row_set, c);
      break;

    case TTypeId::SMALLINT_TYPE:
      result[c] = build_int_column_from_i16_value(row_set, c);
      break;

    case TTypeId::INT_TYPE:
      result[c] = build_int_column_from_i32_value(row_set, c);
      break;

    case TTypeId::BIGINT_TYPE:
      result[c] = build_int_column_from_i64_value(row_set, c);
      break;

    case TTypeId::FLOAT_TYPE:
    case TTypeId::DOUBLE_TYPE:
      result[c] = build_double_column_from_double_value(row_set, c);
      break;

    case TTypeId::STRING_TYPE:
    case TTypeId::VARCHAR_TYPE:
    case TTypeId::CHAR_TYPE:
    case TTypeId::BINARY_TYPE:
    case TTypeId::TIMESTAMP_TYPE:
    case TTypeId::DATE_TYPE:
      result[c] = build_string_column_from_string_value(row_set, c);
      break;

    case TTypeId::DECIMAL_TYPE:
      result[c] = build_double_column_from_string_value(row_set, c);
      break;

    case TTypeId::NULL_TYPE:  // for "select null"
      result[c] = build_null_column_from_null_value(row_set);
      break;

    case TTypeId::ARRAY_TYPE:
    case TTypeId::MAP_TYPE:
    case TTypeId::STRUCT_TYPE:
    case TTypeId::UNION_TYPE:
    case TTypeId::USER_DEFINED_TYPE:
    default:
      TTypeId::type type_id = schema.columns[c].typeDesc.types[0].primitiveEntry.type;
      boost::format format("ERROR: unsupported column type id: %1%");
      throw std::runtime_error(boost::str(format % type_id));
      build_error_column(row_set, "unsupported column type");
    }
  }

  return result;
}

Rcpp::LogicalVector Bee::Client::build_logical_column_from_bool_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::LogicalVector result(num_rows, NA_LOGICAL);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].boolVal.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_byte_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].byteVal.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_i16_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].i16Val.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_i32_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].i32Val.value;
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_int_column_from_i64_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::IntegerVector result(num_rows, NA_INTEGER);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].i64Val.value;
  }
  return result;
}

Rcpp::StringVector Bee::Client::build_string_column_from_string_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::StringVector result(num_rows, NA_STRING);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].stringVal.value;
  }
  return result;
}

Rcpp::DoubleVector Bee::Client::build_double_column_from_double_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::DoubleVector result(num_rows, NA_REAL);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = row_set.rows[i].colVals[column_index].doubleVal.value;
  }
  return result;
}

Rcpp::DoubleVector Bee::Client::build_double_column_from_string_value(const TRowSet &row_set, unsigned int column_index) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::DoubleVector result(num_rows, NA_REAL);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = atof(row_set.rows[i].colVals[column_index].stringVal.value.c_str());
  }
  return result;
}

Rcpp::IntegerVector Bee::Client::build_null_column_from_null_value(const TRowSet &row_set) const {
  return Rcpp::IntegerVector(row_set.rows.size(), NA_INTEGER);
}

Rcpp::StringVector Bee::Client::build_error_column(const TRowSet &row_set, const char *error) const {
  unsigned int num_rows = row_set.rows.size();
  Rcpp::StringVector result(num_rows, NA_STRING);
  for (unsigned int i = 0; i < num_rows; ++i) {
    result[i] = error;
  }
  return result;
}
<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */

// BFS
class Solution {
public:
    /**
     * @param graph: A list of Directed graph node
     * @param s: the starting Directed graph node
     * @param t: the terminal Directed graph node
     * @return: a boolean value
     */
    bool hasRoute(vector<DirectedGraphNode*> graph,
                  DirectedGraphNode* s, DirectedGraphNode* t) {
        unordered_set<DirectedGraphNode *> visited_node;
        visited_node.insert(s);
        return BFS(s, t, visited_node);
    }
    bool BFS(DirectedGraphNode* s, const DirectedGraphNode* t,
             unordered_set<DirectedGraphNode *> &visited_node) {
        queue<DirectedGraphNode *> q;
        q.emplace(s);
        while (!q.empty()) {
            s = q.front();
            q.pop();

            if (s == t) {
                return true;
            }

            // Add neighbors which are not visited into the queue
            for (const auto& node: s->neighbors) {
                if (visited_node.insert(node).second) {
                    q.emplace(node);
                }
            }
        }

        return false;
    }
};

// DFS
class Solution2 {
public:
    /**
     * @param graph: A list of Directed graph node
     * @param s: the starting Directed graph node
     * @param t: the terminal Directed graph node
     * @return: a boolean value
     */
    bool hasRoute(vector<DirectedGraphNode*> graph,
                  DirectedGraphNode* s, DirectedGraphNode* t) {
        unordered_set<DirectedGraphNode *> visited_node;
        visited_node.insert(s);
        return DFS(s, t, visited_node);
    }
    bool DFS(DirectedGraphNode* s, const DirectedGraphNode* t,
             unordered_set<DirectedGraphNode *> &visited_node) {
        if (s == t) {
            return true;
        }

        // Search neighbors which are not visted
        for (const auto& node: s->neighbors) {
            if (visited_node.insert(node).second) {
                if (DFS(node, t, visited_node)) {
                    return true;
                }
                //visited_node.erase(node);
            }
        }
        return false;
    }
};

<commit_msg>Update route-between-two-nodes-in-graph.cpp<commit_after>// Time:  O(n)
// Space: O(n)

/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */

// BFS
class Solution {
public:
    /**
     * @param graph: A list of Directed graph node
     * @param s: the starting Directed graph node
     * @param t: the terminal Directed graph node
     * @return: a boolean value
     */
    bool hasRoute(vector<DirectedGraphNode*> graph,
                  DirectedGraphNode* s, DirectedGraphNode* t) {
        unordered_set<DirectedGraphNode *> visited_node;
        visited_node.insert(s);
        return BFS(s, t, visited_node);
    }
    bool BFS(DirectedGraphNode* s, const DirectedGraphNode* t,
             unordered_set<DirectedGraphNode *> &visited_node) {
        queue<DirectedGraphNode *> q;
        q.emplace(s);
        while (!q.empty()) {
            s = q.front();
            q.pop();

            if (s == t) {
                return true;
            }

            // Add neighbors which are not visited into the queue
            for (const auto& node: s->neighbors) {
                if (visited_node.insert(node).second) {
                    q.emplace(node);
                }
            }
        }

        return false;
    }
};

// DFS
class Solution2 {
public:
    /**
     * @param graph: A list of Directed graph node
     * @param s: the starting Directed graph node
     * @param t: the terminal Directed graph node
     * @return: a boolean value
     */
    bool hasRoute(vector<DirectedGraphNode*> graph,
                  DirectedGraphNode* s, DirectedGraphNode* t) {
        unordered_set<DirectedGraphNode *> visited_node;
        visited_node.insert(s);
        return DFS(s, t, visited_node);
    }
    bool DFS(DirectedGraphNode* s, const DirectedGraphNode* t,
             unordered_set<DirectedGraphNode *> &visited_node) {
        if (s == t) {
            return true;
        }

        // Search neighbors which are not visted
        for (const auto& node: s->neighbors) {
            if (visited_node.insert(node).second) {
                if (DFS(node, t, visited_node)) {
                    return true;
                }
                //visited_node.erase(node);
            }
        }
        return false;
    }
};

<|endoftext|>