<commit_before>// Copyright (c) 2015 Baidu, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Authors: Zhangyi Chen (chenzhangyi01@baidu.com)

#include <algorithm>                                           // std::set_union
#include <gflags/gflags.h>
#include "butil/containers/flat_map.h"
#include "butil/errno.h"
#include "butil/strings/string_number_conversions.h"
#include "brpc/socket.h"
#include "brpc/policy/consistent_hashing_load_balancer.h"
#include "brpc/policy/hasher.h"

namespace brpc {
namespace policy {

// TODO: or 160?
DEFINE_int32(chash_num_replicas, 100,
             "default number of replicas per server in chash");

// Defined in hasher.cpp.
const char* GetHashName(HashFunc hasher);

class ReplicaPolicy {
public:
    virtual ~ReplicaPolicy() = default;

    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const = 0;
    virtual const char* name() const = 0;
};

class DefaultReplicaPolicy : public ReplicaPolicy {
public:
    DefaultReplicaPolicy(HashFunc hash) : _hash_func(hash) {}

    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;

    virtual const char* name() const { return GetHashName(_hash_func); }

private:
    HashFunc _hash_func;
};

bool DefaultReplicaPolicy::Build(ServerId server,
                                 size_t num_replicas,
                                 std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    for (size_t i = 0; i < num_replicas; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        ConsistentHashingLoadBalancer::Node node;
        node.hash = _hash_func(host, len);
        node.server_sock = server;
        node.server_addr = ptr->remote_side();
        replicas->push_back(node);
    }
    return true;
}

class KetamaReplicaPolicy : public ReplicaPolicy {
public:
    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;

    virtual const char* name() const { return "ketama"; }
};

bool KetamaReplicaPolicy::Build(ServerId server,
                                size_t num_replicas,
                                std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    const size_t points_per_hash = 4;
    CHECK(num_replicas % points_per_hash == 0)
        << "Ketam hash replicas number(" << num_replicas << ") should be n*4";
    for (size_t i = 0; i < num_replicas / points_per_hash; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        unsigned char digest[16];
        MD5HashSignature(host, len, digest);
        for (size_t j = 0; j < points_per_hash; ++j) {
            ConsistentHashingLoadBalancer::Node node;
            node.server_sock = server;
            node.server_addr = ptr->remote_side();
            node.hash = ((uint32_t) (digest[3 + j * 4] & 0xFF) << 24)
                      | ((uint32_t) (digest[2 + j * 4] & 0xFF) << 16)
                      | ((uint32_t) (digest[1 + j * 4] & 0xFF) << 8)
                      | (digest[0 + j * 4] & 0xFF);
            replicas->push_back(node);
        }
    }
    return true;
}

namespace {

const std::array<const ReplicaPolicy*, CONS_HASH_LB_LAST> g_replica_policy = {
    new DefaultReplicaPolicy(MurmurHash32),
    new DefaultReplicaPolicy(MD5Hash32),
    new KetamaReplicaPolicy
};

inline const ReplicaPolicy* GetReplicaPolicy(ConsistentHashingLoadBalancerType type) {
    return g_replica_policy.at(type);
}

} // namespace

ConsistentHashingLoadBalancer::ConsistentHashingLoadBalancer(
    ConsistentHashingLoadBalancerType type)
    : _num_replicas(FLAGS_chash_num_replicas), _type(type) {
    _replicas_policy = GetReplicaPolicy(_type);
    CHECK(_replicas_policy)
        << "Fail to find replica policy for consistency lb type: '" << type << '\'';
}

size_t ConsistentHashingLoadBalancer::AddBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<Node> &servers, bool *executed) {
    if (*executed) {
        // Hack DBD
        return fg.size() - bg.size();
    }
    *executed = true;
    bg.resize(fg.size() + servers.size());
    bg.resize(std::set_union(fg.begin(), fg.end(),
                             servers.begin(), servers.end(), bg.begin())
              - bg.begin());
    return bg.size() - fg.size();
}

size_t ConsistentHashingLoadBalancer::RemoveBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<ServerId> &servers, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    if (servers.empty()) {
        bg = fg;
        return 0;
    }
    butil::FlatSet<ServerId> id_set;
    bool use_set = true;
    if (id_set.init(servers.size() * 2) == 0) {
        for (size_t i = 0; i < servers.size(); ++i) {
            if (id_set.insert(servers[i]) == NULL) {
                use_set = false;
                break;
            }
        }
    } else {
        use_set = false;
    }
    CHECK(use_set) << "Fail to construct id_set, " << berror();
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        const bool removed =
            use_set ? (id_set.seek(fg[i].server_sock) != NULL)
                    : (std::find(servers.begin(), servers.end(),
                                fg[i].server_sock) != servers.end());
        if (!removed) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

size_t ConsistentHashingLoadBalancer::Remove(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const ServerId& server, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        if (fg[i].server_sock != server) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

bool ConsistentHashingLoadBalancer::AddServer(const ServerId& server) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(_num_replicas);
    if (!_replicas_policy->Build(server, _num_replicas, &add_nodes)) {
        return false;
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(
                        AddBatch, add_nodes, &executed);
    CHECK(ret == 0 || ret == _num_replicas) << ret;
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::AddServersInBatch(
    const std::vector<ServerId> &servers) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(servers.size() * _num_replicas);
    std::vector<Node> replicas;
    replicas.reserve(_num_replicas);
    for (size_t i = 0; i < servers.size(); ++i) {
        replicas.clear();
        if (_replicas_policy->Build(servers[i], _num_replicas, &replicas)) {
            add_nodes.insert(add_nodes.end(), replicas.begin(), replicas.end());
        }
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(AddBatch, add_nodes, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to AddServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

bool ConsistentHashingLoadBalancer::RemoveServer(const ServerId& server) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(Remove, server, &executed);
    CHECK(ret == 0 || ret == _num_replicas);
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::RemoveServersInBatch(
    const std::vector<ServerId> &servers) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(RemoveBatch, servers, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to RemoveServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

LoadBalancer *ConsistentHashingLoadBalancer::New(const butil::StringPiece& params) const {
    ConsistentHashingLoadBalancer* lb =
        new (std::nothrow) ConsistentHashingLoadBalancer(_type);
    if (lb != nullptr && !lb->SetParameters(params)) {
        delete lb;
        lb = nullptr;
    }
    return lb;
}

void ConsistentHashingLoadBalancer::Destroy() {
    delete this;
}

int ConsistentHashingLoadBalancer::SelectServer(
    const SelectIn &in, SelectOut *out) {
    if (!in.has_request_code) {
        LOG(ERROR) << "Controller.set_request_code() is required";
        return EINVAL;
    }
    if (in.request_code > UINT_MAX) {
        LOG(ERROR) << "request_code must be 32-bit currently";
        return EINVAL;
    }
    butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
    if (_db_hash_ring.Read(&s) != 0) {
        return ENOMEM;
    }
    if (s->empty()) {
        return ENODATA;
    }
    std::vector<Node>::const_iterator choice =
        std::lower_bound(s->begin(), s->end(), (uint32_t)in.request_code);
    if (choice == s->end()) {
        choice = s->begin();
    }
    for (size_t i = 0; i < s->size(); ++i) {
        if (((i + 1) == s->size() // always take last chance
             || !ExcludedServers::IsExcluded(in.excluded, choice->server_sock.id))
            && Socket::Address(choice->server_sock.id, out->ptr) == 0
            && !(*out->ptr)->IsLogOff()) {
            return 0;
        } else {
            if (++choice == s->end()) {
                choice = s->begin();
            }
        }
    }
    return EHOSTDOWN;
}

void ConsistentHashingLoadBalancer::Describe(
    std::ostream &os, const DescribeOptions& options) {
    if (!options.verbose) {
        os << "c_hash";
        return;
    }
    os << "ConsistentHashingLoadBalancer {\n"
       << "  hash function: " << _replicas_policy->name() << '\n'
       << "  replica per host: " << _num_replicas << '\n';
    std::map<butil::EndPoint, double> load_map;
    GetLoads(&load_map);
    os << "  number of hosts: " << load_map.size() << '\n';
    os << "  load of hosts: {\n";
    double expected_load_per_server = 1.0 / load_map.size();
    double load_sum = 0;
    double load_sqr_sum = 0;
    for (std::map<butil::EndPoint, double>::iterator
            it = load_map.begin(); it!= load_map.end(); ++it) {
        os << "    " << it->first << ": " << it->second << '\n';
        double normalized_load = it->second / expected_load_per_server;
        load_sum += normalized_load;
        load_sqr_sum += normalized_load * normalized_load;
    }
    os << "  }\n";
    os << "deviation: "
       << sqrt(load_sqr_sum * load_map.size() - load_sum * load_sum)
          / load_map.size();
    os << "}\n";
}

void ConsistentHashingLoadBalancer::GetLoads(
    std::map<butil::EndPoint, double> *load_map) {
    load_map->clear();
    std::map<butil::EndPoint, uint32_t> count_map;
    do {
        butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
        if (_db_hash_ring.Read(&s) != 0) {
            break;
        }
        if (s->empty()) {
            break;
        }
        count_map[s->begin()->server_addr] +=
                s->begin()->hash + (UINT_MAX - (s->end() - 1)->hash);
        for (size_t i = 1; i < s->size(); ++i) {
            count_map[(*s.get())[i].server_addr] +=
                    (*s.get())[i].hash - (*s.get())[i - 1].hash;
        }
    } while (0);
    for (std::map<butil::EndPoint, uint32_t>::iterator
            it = count_map.begin(); it!= count_map.end(); ++it) {
        (*load_map)[it->first] = (double)it->second / UINT_MAX;
    }
}

bool ConsistentHashingLoadBalancer::SetParameters(const butil::StringPiece& params) {
    butil::StringPairs param_vec;
    if (!SplitLoadBalancerParameters(params, &param_vec)) {
        return false;
    }
    for (const std::pair<std::string, std::string>& param : param_vec) {
        if (param.first == "replicas") {
            size_t replicas = 0;
            if (butil::StringToSizeT(param.second, &replicas)) {
                _num_replicas = replicas;
            } else {
                return false;
            }
            continue;
        }
        LOG(ERROR) << "Failed to set this unknown parameters " << param.first << '=' << param.second;
    }

    return true;
}

}  // namespace policy
} // namespace brpc
<commit_msg>fix for ci comments<commit_after>// Copyright (c) 2015 Baidu, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Authors: Zhangyi Chen (chenzhangyi01@baidu.com)

#include <algorithm>                                           // std::set_union
#include <gflags/gflags.h>
#include "butil/containers/flat_map.h"
#include "butil/errno.h"
#include "butil/strings/string_number_conversions.h"
#include "brpc/socket.h"
#include "brpc/policy/consistent_hashing_load_balancer.h"
#include "brpc/policy/hasher.h"

namespace brpc {
namespace policy {

// TODO: or 160?
DEFINE_int32(chash_num_replicas, 100,
             "default number of replicas per server in chash");

// Defined in hasher.cpp.
const char* GetHashName(HashFunc hasher);

class ReplicaPolicy {
public:
    virtual ~ReplicaPolicy() = default;

    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const = 0;
    virtual const char* name() const = 0;
};

class DefaultReplicaPolicy : public ReplicaPolicy {
public:
    DefaultReplicaPolicy(HashFunc hash) : _hash_func(hash) {}

    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;

    virtual const char* name() const { return GetHashName(_hash_func); }

private:
    HashFunc _hash_func;
};

bool DefaultReplicaPolicy::Build(ServerId server,
                                 size_t num_replicas,
                                 std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    for (size_t i = 0; i < num_replicas; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        ConsistentHashingLoadBalancer::Node node;
        node.hash = _hash_func(host, len);
        node.server_sock = server;
        node.server_addr = ptr->remote_side();
        replicas->push_back(node);
    }
    return true;
}

class KetamaReplicaPolicy : public ReplicaPolicy {
public:
    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;

    virtual const char* name() const { return "ketama"; }
};

bool KetamaReplicaPolicy::Build(ServerId server,
                                size_t num_replicas,
                                std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    const size_t points_per_hash = 4;
    CHECK(num_replicas % points_per_hash == 0)
        << "Ketam hash replicas number(" << num_replicas << ") should be n*4";
    for (size_t i = 0; i < num_replicas / points_per_hash; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        unsigned char digest[16];
        MD5HashSignature(host, len, digest);
        for (size_t j = 0; j < points_per_hash; ++j) {
            ConsistentHashingLoadBalancer::Node node;
            node.server_sock = server;
            node.server_addr = ptr->remote_side();
            node.hash = ((uint32_t) (digest[3 + j * 4] & 0xFF) << 24)
                      | ((uint32_t) (digest[2 + j * 4] & 0xFF) << 16)
                      | ((uint32_t) (digest[1 + j * 4] & 0xFF) << 8)
                      | (digest[0 + j * 4] & 0xFF);
            replicas->push_back(node);
        }
    }
    return true;
}

namespace {

pthread_once_t s_replica_policy_once = PTHREAD_ONCE_INIT;
const std::array<const ReplicaPolicy*, CONS_HASH_LB_LAST>* g_replica_policy = nullptr;

void init_replica_policy() {
    g_replica_policy = new std::array<const ReplicaPolicy*, CONS_HASH_LB_LAST>({
        new DefaultReplicaPolicy(MurmurHash32),
        new DefaultReplicaPolicy(MD5Hash32),
        new KetamaReplicaPolicy
    });
}

inline const ReplicaPolicy* GetReplicaPolicy(ConsistentHashingLoadBalancerType type) {
    pthread_once(&s_replica_policy_once, init_replica_policy);
    return g_replica_policy->at(type);
}

} // namespace

ConsistentHashingLoadBalancer::ConsistentHashingLoadBalancer(
    ConsistentHashingLoadBalancerType type)
    : _num_replicas(FLAGS_chash_num_replicas), _type(type) {
    _replicas_policy = GetReplicaPolicy(_type);
    CHECK(_replicas_policy)
        << "Fail to find replica policy for consistency lb type: '" << type << '\'';
}

size_t ConsistentHashingLoadBalancer::AddBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<Node> &servers, bool *executed) {
    if (*executed) {
        // Hack DBD
        return fg.size() - bg.size();
    }
    *executed = true;
    bg.resize(fg.size() + servers.size());
    bg.resize(std::set_union(fg.begin(), fg.end(),
                             servers.begin(), servers.end(), bg.begin())
              - bg.begin());
    return bg.size() - fg.size();
}

size_t ConsistentHashingLoadBalancer::RemoveBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<ServerId> &servers, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    if (servers.empty()) {
        bg = fg;
        return 0;
    }
    butil::FlatSet<ServerId> id_set;
    bool use_set = true;
    if (id_set.init(servers.size() * 2) == 0) {
        for (size_t i = 0; i < servers.size(); ++i) {
            if (id_set.insert(servers[i]) == NULL) {
                use_set = false;
                break;
            }
        }
    } else {
        use_set = false;
    }
    CHECK(use_set) << "Fail to construct id_set, " << berror();
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        const bool removed =
            use_set ? (id_set.seek(fg[i].server_sock) != NULL)
                    : (std::find(servers.begin(), servers.end(),
                                fg[i].server_sock) != servers.end());
        if (!removed) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

size_t ConsistentHashingLoadBalancer::Remove(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const ServerId& server, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        if (fg[i].server_sock != server) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

bool ConsistentHashingLoadBalancer::AddServer(const ServerId& server) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(_num_replicas);
    if (!_replicas_policy->Build(server, _num_replicas, &add_nodes)) {
        return false;
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(
                        AddBatch, add_nodes, &executed);
    CHECK(ret == 0 || ret == _num_replicas) << ret;
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::AddServersInBatch(
    const std::vector<ServerId> &servers) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(servers.size() * _num_replicas);
    std::vector<Node> replicas;
    replicas.reserve(_num_replicas);
    for (size_t i = 0; i < servers.size(); ++i) {
        replicas.clear();
        if (_replicas_policy->Build(servers[i], _num_replicas, &replicas)) {
            add_nodes.insert(add_nodes.end(), replicas.begin(), replicas.end());
        }
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(AddBatch, add_nodes, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to AddServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

bool ConsistentHashingLoadBalancer::RemoveServer(const ServerId& server) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(Remove, server, &executed);
    CHECK(ret == 0 || ret == _num_replicas);
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::RemoveServersInBatch(
    const std::vector<ServerId> &servers) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(RemoveBatch, servers, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to RemoveServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

LoadBalancer *ConsistentHashingLoadBalancer::New(const butil::StringPiece& params) const {
    ConsistentHashingLoadBalancer* lb =
        new (std::nothrow) ConsistentHashingLoadBalancer(_type);
    if (lb != nullptr && !lb->SetParameters(params)) {
        delete lb;
        lb = nullptr;
    }
    return lb;
}

void ConsistentHashingLoadBalancer::Destroy() {
    delete this;
}

int ConsistentHashingLoadBalancer::SelectServer(
    const SelectIn &in, SelectOut *out) {
    if (!in.has_request_code) {
        LOG(ERROR) << "Controller.set_request_code() is required";
        return EINVAL;
    }
    if (in.request_code > UINT_MAX) {
        LOG(ERROR) << "request_code must be 32-bit currently";
        return EINVAL;
    }
    butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
    if (_db_hash_ring.Read(&s) != 0) {
        return ENOMEM;
    }
    if (s->empty()) {
        return ENODATA;
    }
    std::vector<Node>::const_iterator choice =
        std::lower_bound(s->begin(), s->end(), (uint32_t)in.request_code);
    if (choice == s->end()) {
        choice = s->begin();
    }
    for (size_t i = 0; i < s->size(); ++i) {
        if (((i + 1) == s->size() // always take last chance
             || !ExcludedServers::IsExcluded(in.excluded, choice->server_sock.id))
            && Socket::Address(choice->server_sock.id, out->ptr) == 0
            && !(*out->ptr)->IsLogOff()) {
            return 0;
        } else {
            if (++choice == s->end()) {
                choice = s->begin();
            }
        }
    }
    return EHOSTDOWN;
}

void ConsistentHashingLoadBalancer::Describe(
    std::ostream &os, const DescribeOptions& options) {
    if (!options.verbose) {
        os << "c_hash";
        return;
    }
    os << "ConsistentHashingLoadBalancer {\n"
       << "  hash function: " << _replicas_policy->name() << '\n'
       << "  replica per host: " << _num_replicas << '\n';
    std::map<butil::EndPoint, double> load_map;
    GetLoads(&load_map);
    os << "  number of hosts: " << load_map.size() << '\n';
    os << "  load of hosts: {\n";
    double expected_load_per_server = 1.0 / load_map.size();
    double load_sum = 0;
    double load_sqr_sum = 0;
    for (std::map<butil::EndPoint, double>::iterator
            it = load_map.begin(); it!= load_map.end(); ++it) {
        os << "    " << it->first << ": " << it->second << '\n';
        double normalized_load = it->second / expected_load_per_server;
        load_sum += normalized_load;
        load_sqr_sum += normalized_load * normalized_load;
    }
    os << "  }\n";
    os << "deviation: "
       << sqrt(load_sqr_sum * load_map.size() - load_sum * load_sum)
          / load_map.size();
    os << "}\n";
}

void ConsistentHashingLoadBalancer::GetLoads(
    std::map<butil::EndPoint, double> *load_map) {
    load_map->clear();
    std::map<butil::EndPoint, uint32_t> count_map;
    do {
        butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
        if (_db_hash_ring.Read(&s) != 0) {
            break;
        }
        if (s->empty()) {
            break;
        }
        count_map[s->begin()->server_addr] +=
                s->begin()->hash + (UINT_MAX - (s->end() - 1)->hash);
        for (size_t i = 1; i < s->size(); ++i) {
            count_map[(*s.get())[i].server_addr] +=
                    (*s.get())[i].hash - (*s.get())[i - 1].hash;
        }
    } while (0);
    for (std::map<butil::EndPoint, uint32_t>::iterator
            it = count_map.begin(); it!= count_map.end(); ++it) {
        (*load_map)[it->first] = (double)it->second / UINT_MAX;
    }
}

bool ConsistentHashingLoadBalancer::SetParameters(const butil::StringPiece& params) {
    butil::StringPairs param_vec;
    if (!SplitLoadBalancerParameters(params, &param_vec)) {
        return false;
    }
    for (const std::pair<std::string, std::string>& param : param_vec) {
        if (param.first == "replicas") {
            size_t replicas = 0;
            if (butil::StringToSizeT(param.second, &replicas)) {
                _num_replicas = replicas;
            } else {
                return false;
            }
            continue;
        }
        LOG(ERROR) << "Failed to set this unknown parameters " << param.first << '=' << param.second;
    }

    return true;
}

}  // namespace policy
} // namespace brpc
<|endoftext|>


<commit_before>
// Halide tutorial lesson 10: AOT compilation part 1

// This lesson demonstrates how to use Halide as an more traditional
// ahead-of-time (AOT) compiler.

// This lesson is split across two files. The first (this one), builds
// a Halide pipeline and compiles it to a static library and
// header. The second (lesson_10_aot_compilation_run.cpp), uses that
// static library to actually run the pipeline. This means that
// compiling this code is a multi-step process.

// On linux, you can compile and run it like so:
// g++ lesson_10*generate.cpp -g -std=c++11 -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_10_generate
// LD_LIBRARY_PATH=../bin ./lesson_10_generate
// g++ lesson_10*run.cpp lesson_10_halide.a -lpthread -ldl -o lesson_10_run
// ./lesson_10_run

// On os x:
// g++ lesson_10*generate.cpp -g -std=c++11 -I ../include -L ../bin -lHalide -o lesson_10_generate
// DYLD_LIBRARY_PATH=../bin ./lesson_10_generate
// g++ lesson_10*run.cpp lesson_10_halide.a -o lesson_10_run
// ./lesson_10_run

// The benefits of this approach are that the final program:
// - Doesn't do any jit compilation at runtime, so it's fast.
// - Doesn't depend on libHalide at all, so it's a small, easy-to-deploy binary.

// If you have the entire Halide source tree, you can also build it by
// running:
//    make tutorial_lesson_10_aot_compilation_run
// in a shell with the current directory at the top of the halide
// source tree.

#include "Halide.h"
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {

    // We'll define a simple one-stage pipeline:
    Func brighter;
    Var x, y;

    // The pipeline will depend on one scalar parameter.
    Param<uint8_t> offset;

    // And take one grayscale 8-bit input buffer. The first
    // constructor argument gives the type of a pixel, and the second
    // specifies the number of dimensions (not the number of
    // channels!). For a grayscale image this is two; for a color
    // image it's three. Currently, four dimensions is the maximum for
    // inputs and outputs.
    ImageParam input(type_of<uint8_t>(), 2);

    // If we were jit-compiling, these would just be an int and an
    // Image, but because we want to compile the pipeline once and
    // have it work for any value of the parameter, we need to make a
    // Param object, which can be used like an Expr, and an ImageParam
    // object, which can be used like an Image.

    // Define the Func.
    brighter(x, y) = input(x, y) + offset;

    // Schedule it.
    brighter.vectorize(x, 16).parallel(y);

    // This time, instead of calling brighter.realize(...), which
    // would compile and run the pipeline immediately, we'll call a
    // method that compiles the pipeline to a static library and header.
    //
    // For AOT-compiled code, we need to explicitly declare the
    // arguments to the routine. This routine takes two. Arguments are
    // usually Params or ImageParams.
    std::vector<Argument> args = {input, offset};
    brighter.compile_to_static_library("lesson_10_halide", args, "brighter");

    // If you're using C++11, you can just say:
    // brighter.compile_to_static_library("lesson_10_halide", {input, offset}, "brighter");

    printf("Halide pipeline compiled, but not yet run.\n");

    // To continue this lesson, look in the file lesson_10_aot_compilation_run.cpp

    return 0;
}
<commit_msg>Remove "If you have C++11 comment" in lesson 10, since we've required C++11 for a long time<commit_after>
// Halide tutorial lesson 10: AOT compilation part 1

// This lesson demonstrates how to use Halide as an more traditional
// ahead-of-time (AOT) compiler.

// This lesson is split across two files. The first (this one), builds
// a Halide pipeline and compiles it to a static library and
// header. The second (lesson_10_aot_compilation_run.cpp), uses that
// static library to actually run the pipeline. This means that
// compiling this code is a multi-step process.

// On linux, you can compile and run it like so:
// g++ lesson_10*generate.cpp -g -std=c++11 -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_10_generate
// LD_LIBRARY_PATH=../bin ./lesson_10_generate
// g++ lesson_10*run.cpp lesson_10_halide.a -lpthread -ldl -o lesson_10_run
// ./lesson_10_run

// On os x:
// g++ lesson_10*generate.cpp -g -std=c++11 -I ../include -L ../bin -lHalide -o lesson_10_generate
// DYLD_LIBRARY_PATH=../bin ./lesson_10_generate
// g++ lesson_10*run.cpp lesson_10_halide.a -o lesson_10_run
// ./lesson_10_run

// The benefits of this approach are that the final program:
// - Doesn't do any jit compilation at runtime, so it's fast.
// - Doesn't depend on libHalide at all, so it's a small, easy-to-deploy binary.

// If you have the entire Halide source tree, you can also build it by
// running:
//    make tutorial_lesson_10_aot_compilation_run
// in a shell with the current directory at the top of the halide
// source tree.

#include "Halide.h"
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {

    // We'll define a simple one-stage pipeline:
    Func brighter;
    Var x, y;

    // The pipeline will depend on one scalar parameter.
    Param<uint8_t> offset;

    // And take one grayscale 8-bit input buffer. The first
    // constructor argument gives the type of a pixel, and the second
    // specifies the number of dimensions (not the number of
    // channels!). For a grayscale image this is two; for a color
    // image it's three. Currently, four dimensions is the maximum for
    // inputs and outputs.
    ImageParam input(type_of<uint8_t>(), 2);

    // If we were jit-compiling, these would just be an int and an
    // Image, but because we want to compile the pipeline once and
    // have it work for any value of the parameter, we need to make a
    // Param object, which can be used like an Expr, and an ImageParam
    // object, which can be used like an Image.

    // Define the Func.
    brighter(x, y) = input(x, y) + offset;

    // Schedule it.
    brighter.vectorize(x, 16).parallel(y);

    // This time, instead of calling brighter.realize(...), which
    // would compile and run the pipeline immediately, we'll call a
    // method that compiles the pipeline to a static library and header.
    //
    // For AOT-compiled code, we need to explicitly declare the
    // arguments to the routine. This routine takes two. Arguments are
    // usually Params or ImageParams.
    brighter.compile_to_static_library("lesson_10_halide", {input, offset}, "brighter");

    printf("Halide pipeline compiled, but not yet run.\n");

    // To continue this lesson, look in the file lesson_10_aot_compilation_run.cpp

    return 0;
}
<|endoftext|>


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

/*
 * Author:
 */

//============================================================================
// INCLUDES
//============================================================================
#include "VisibleObject.h"
#include "Exception.h"
#include "PropertyInt.h"
#include "PropertyStr.h"
#include "PropertyObj.h"
#include "PropertyStrArray.h"
#include "PropertyDblArray.h"
#include "Geometry.h"

using namespace OpenSim;
using namespace std;

//============================================================================
// CONSTANTS
//============================================================================

//=============================================================================
// CONSTRUCTOR(S)
//=============================================================================
//_____________________________________________________________________________
/**
 * Destructor.
 */
VisibleObject::~VisibleObject()
{
}

//_____________________________________________________________________________
/**
 * Default constructor.
 */
VisibleObject::VisibleObject():
_geometryFileNames(_propGeometryFileNames.getValueStrArray()),
_allGeometry(0),
_propVisibleProp(PropertyObj("", VisibleProperties())),
_visibleProp((VisibleProperties&)_propVisibleProp.getValueObj()),
_scaleFactors(_propScaleFactors.getValueDblArray()),
_dependents(0)
{
	// NULL STATES
	setNull();

	// MEMBER VARIABLES
	setType("VisibleObject");
	setName("");
}

//_____________________________________________________________________________
/**
 * Construct an object from file.
 *
 * The object is constructed from the root element of the XML document.
 * The type of object is the tag name of the XML root element.
 *
 * @param aFileName File name of the document.
 */
VisibleObject::VisibleObject(const string &aFileName):
Object(aFileName, false),
_geometryFileNames(_propGeometryFileNames.getValueStrArray()),
_allGeometry(0),
_propVisibleProp(PropertyObj("", VisibleProperties())),
_visibleProp((VisibleProperties&)_propVisibleProp.getValueObj()),
_scaleFactors(_propScaleFactors.getValueDblArray()),
_dependents(0)
{
	// NULL STATES
	setNull();

	updateFromXMLNode();
}
//_____________________________________________________________________________
/**
 * Copy constructor.
 *
 * Copy constructors for all VisibleObject's only copy the non-XML variable
 * members of the object; that is, the object's DOMnode and XMLDocument
 * are not copied but set to NULL.  The reason for this is that for the
 * object and all its derived classes to establish the correct connection
 * to the XML document nodes, the the object would need to reconstruct based
 * on the XML document not the values of the object's member variables.
 *
 * There are three proper ways to generate an XML document for an VisibleObject:
 *
 * 1) Construction based on XML file (@see VisibleObject(const char *aFileName)).
 * In this case, the XML document is created by parsing the XML file.
 *
 * 2) Construction by VisibleObject(const XMLDocument *aDocument).
 * This constructor explictly requests construction based on an
 * XML document.  In this way the proper connection between an object's node
 * and the corresponding node within the XML document is established.
 * This constructor is a copy constructor of sorts because all essential
 * VisibleObject member variables should be held within the XML document.
 * The advantage of this style of construction is that nodes
 * within the XML document, such as comments that may not have any
 * associated VisibleObject member variable, are preserved.
 *
 * 3) A call to generateXMLDocument().
 * This method generates an XML document for the VisibleObject from scratch.
 * Only the essential document nodes are created (that is, nodes that
 * correspond directly to member variables.).
 *
 * @param aObject Object to be copied.
 * @see VisibleObject(const XMLDocument *aDocument)
 * @see VisibleObject(const char *aFileName)
 * @see generateXMLDocument()
 */
VisibleObject::VisibleObject(const VisibleObject &aObject):
Object(aObject),
_geometryFileNames(_propGeometryFileNames.getValueStrArray()),
_allGeometry(0),
_propVisibleProp(PropertyObj("", VisibleProperties())),
_visibleProp((VisibleProperties&)_propVisibleProp.getValueObj()),
_scaleFactors(_propScaleFactors.getValueDblArray()),
_dependents(0)
{
	// NULL MEMBER VARIABLES
	setNull();

	// COPY TYPE AND NAME
	*this = aObject;
}

//=============================================================================
// CONSTRUCTION METHODS
//=============================================================================
//_____________________________________________________________________________
/**
 * Set all member variables to their null or default values.
 */
void VisibleObject::
setNull()
{
	setupProperties();

	Array<double> unit3(1.0, 3);
	_scaleFactors = unit3;

	_owner = 0;
	_dependents.setMemoryOwner(false);

}
/**
 * virtual copy constructor
 */
Object* VisibleObject::
copy() const
{

	VisibleObject *object = new VisibleObject(*this);
	return(object);
}
//_____________________________________________________________________________
/**
 * Connect properties to local pointers.
 */
void VisibleObject::setupProperties()
{

	_propGeometryFileNames.setName("geometry_files");
	Array<string> filenames("");
	_propGeometryFileNames.setValue(filenames);
	_propertySet.append(&_propGeometryFileNames);

	_propVisibleProp.setName("visible_properties");
	_propertySet.append(&_propVisibleProp);

	_propScaleFactors.setName("scale_factors");
	_propScaleFactors.setAllowableArraySize(3);
	_propertySet.append(&_propScaleFactors);
}

//=============================================================================
// OPERATORS
//=============================================================================
//-----------------------------------------------------------------------------
// ASSIGNMENT
//-----------------------------------------------------------------------------
//_____________________________________________________________________________
/**
 * Assign this object to the values of another.
 *
 * @return Reference to this object.
 */
VisibleObject& VisibleObject::
operator=(const VisibleObject &aObject)
{
	// BASE CLASS
	Object::operator=(aObject);

	setNumGeometryFiles(aObject.getNumGeometryFiles());
	for(int i=0; i < aObject.getNumGeometryFiles(); i++)
		setGeometryFileName(i, aObject.getGeometryFileName(i));

	_transform = aObject._transform;
	_visibleProp = aObject._visibleProp;

	_scaleFactors = aObject._scaleFactors;
	return(*this);
}

//-----------------------------------------------------------------------------
// EQUALITY
//-----------------------------------------------------------------------------
//_____________________________________________________________________________
/**
 * Determine if two objects are equal.
 *
 * @return True if the two objects are equal, false otherwise.
 */
bool VisibleObject::
operator==(const VisibleObject &aObject)
{
	return(Object::operator==(aObject));
}

//=============================================================================
// GET AND SET
//=============================================================================
//------------- Geometry files mgmt. -------------------------------------------
/**
 * set the number of geometry files associated with visible object
 */
void VisibleObject::
setNumGeometryFiles(int n)
{
	_geometryFileNames.setSize(n);
}
/**
 * Get the number of geometry files associated with visible object
 */
const int VisibleObject::
getNumGeometryFiles() const
{
	return (_geometryFileNames.getSize());
}
/**
 * set the name of ith geometry files associated with visible object
 */
void VisibleObject::
setGeometryFileName(int i, const string &aGeometryFileName)
{
	_geometryFileNames.set(i,aGeometryFileName);
}
/**
 * Get the name of ith geometry files associated with visible object
 */

const std::string& VisibleObject::
getGeometryFileName(int i) const
{
	return _geometryFileNames[i];
}

/**
 * set the visible properties of a visible object
 */
//------------- Properties: Shading, Color, etc. -------------------------------
void VisibleObject::
setVisibleProperties(const VisibleProperties &aVisibleProperties)
{
	_visibleProp = aVisibleProperties;
}
/**
 * Retrieve the visible properties of a visible object
 */
VisibleProperties& VisibleObject::
getVisibleProperties()
{
	return (_visibleProp);
}
//_____________________________________________________________________________
/**
 * Set Scale factors for geometry.
 *
 */
void VisibleObject::
setScaleFactors(const double aScaleFactors[3])
{
	_propScaleFactors.setUseDefault(false);
	for(int i=0; i < 3; i++)
		_scaleFactors[i]=(aScaleFactors[i]);
}
//_____________________________________________________________________________
/**
 * Get Scale factors for geometry.
 *
 */
void VisibleObject::
getScaleFactors(double aScaleFactors[3]) const
{
	for(int i=0; i < 3; i++)
		aScaleFactors[i] = _scaleFactors[i];
}
//------------- Transform -----------------------------------------------------
/**
 * Set the transform of a visible object
 */
void VisibleObject::
setTransform(const Transform &aTransform)
{
	_transform = aTransform;
	setChanged();
}
/**
 * Retrieve the transform of a visible object
 */

Transform& VisibleObject::
getTransform()
{
	return _transform;
}
//------------- Transform -----------------------------------------------------
// More interfaces for transform as other interfaces (Angles based) are needed
// Rotations in Radians
// three rotation angles, assumed order XYZ
/**
 * Rotate a visible object by 3 angles in radians around XYZ in order
 */
void VisibleObject::
rotateRadians(const double rR[3])
{
	getTransform().rotate(rR, Transform::Radians, Transform::XYZ);
}

/**
 * Rotate a visible object by 3 angles in radians with user specified order
 */
void VisibleObject::
rotateRadians(const double rR[3], const Transform::RotationOrder order)
{
	getTransform().rotate(rR, Transform::Radians, order);
}
/**
 * Rotate a visible object by an angle in radians around X axis
 */
void VisibleObject::
rotateRadiansX(const double rR)
{
	getTransform().rotateX(rR, Transform::Radians);
}
/**
 * Rotate a visible object by an angle in radians around Y axis
 */
void VisibleObject::
rotateRadiansY(const double rR)
{
	getTransform().rotateY(rR, Transform::Radians);
}
/**
 * Rotate a visible object by an angle in radians around Z axis
 */
void VisibleObject::
rotateRadiansZ(const double rR)
{
	getTransform().rotateZ(rR, Transform::Radians);
}
/**
 * Rotate a visible object by an angle in radians around an axis
 */
void VisibleObject::
rotateRadiansAxis(const double rR, const double axis[3])
{
	getTransform().rotateAxis(rR, Transform::Radians, axis);
}

/**
 * Rotate a visible object by three euler angle in degrees around in XYZ order
 */

void VisibleObject::
rotateDegrees(const double rD[3])
{
	getTransform().rotate(rD, Transform::Degrees, Transform::XYZ);
}
/**
 * Rotate a visible object by three euler angle in degrees around in specified order
 */
void VisibleObject::
rotateDegrees(const double rD[3], const Transform::RotationOrder order)
{
	getTransform().rotate(rD, Transform::Degrees, order);
}
/**
 * Rotate a visible object by an angle in degrees around X axis
 */
void VisibleObject::
rotateDegreesX(const double rD)
{
	getTransform().rotateX(rD, Transform::Degrees);
}
/**
 * Rotate a visible object by an angle in degrees around Y axis
 */
void VisibleObject::
rotateDegreesY(const double rD)
{
	getTransform().rotateY(rD, Transform::Degrees);
}
/**
 * Rotate a visible object by an angle in degrees around Z axis
 */
void VisibleObject::
rotateDegreesZ(const double rD)
{
	getTransform().rotateZ(rD, Transform::Degrees);
}
/**
 * Rotate a visible object by an angle in degrees around an axis
 */
void VisibleObject::
rotateDegreesAxis(const double rD, const double axis[3])
{
	getTransform().rotateAxis(rD, Transform::Degrees, axis);
}
/**
 * Translate a visible object by a translation vector
 */
void VisibleObject::
translate(const double t[3])
{
	getTransform().translate(t);
}

<commit_msg>Delete all geometry stuff on destruction of VisibleObjects.<commit_after>// VisibleObject.cpp
// Author: Ayman Habib
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
* Copyright (c) 2005, Stanford University. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*  - Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*  - Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*  - Neither the name of the Stanford University nor the names of its
*    contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

/*
 * Author:
 */

//============================================================================
// INCLUDES
//============================================================================
#include "VisibleObject.h"
#include "Exception.h"
#include "PropertyInt.h"
#include "PropertyStr.h"
#include "PropertyObj.h"
#include "PropertyStrArray.h"
#include "PropertyDblArray.h"
#include "Geometry.h"

using namespace OpenSim;
using namespace std;

//============================================================================
// CONSTANTS
//============================================================================

//=============================================================================
// CONSTRUCTOR(S)
//=============================================================================
//_____________________________________________________________________________
/**
 * Destructor.
 */
VisibleObject::~VisibleObject()
{
	freeGeometry();
	_owner = NULL;
	_dependents.setSize(0);
}

//_____________________________________________________________________________
/**
 * Default constructor.
 */
VisibleObject::VisibleObject():
_geometryFileNames(_propGeometryFileNames.getValueStrArray()),
_allGeometry(0),
_propVisibleProp(PropertyObj("", VisibleProperties())),
_visibleProp((VisibleProperties&)_propVisibleProp.getValueObj()),
_scaleFactors(_propScaleFactors.getValueDblArray()),
_dependents(0)
{
	// NULL STATES
	setNull();

	// MEMBER VARIABLES
	setType("VisibleObject");
	setName("");
}

//_____________________________________________________________________________
/**
 * Construct an object from file.
 *
 * The object is constructed from the root element of the XML document.
 * The type of object is the tag name of the XML root element.
 *
 * @param aFileName File name of the document.
 */
VisibleObject::VisibleObject(const string &aFileName):
Object(aFileName, false),
_geometryFileNames(_propGeometryFileNames.getValueStrArray()),
_allGeometry(0),
_propVisibleProp(PropertyObj("", VisibleProperties())),
_visibleProp((VisibleProperties&)_propVisibleProp.getValueObj()),
_scaleFactors(_propScaleFactors.getValueDblArray()),
_dependents(0)
{
	// NULL STATES
	setNull();

	updateFromXMLNode();
}
//_____________________________________________________________________________
/**
 * Copy constructor.
 *
 * Copy constructors for all VisibleObject's only copy the non-XML variable
 * members of the object; that is, the object's DOMnode and XMLDocument
 * are not copied but set to NULL.  The reason for this is that for the
 * object and all its derived classes to establish the correct connection
 * to the XML document nodes, the the object would need to reconstruct based
 * on the XML document not the values of the object's member variables.
 *
 * There are three proper ways to generate an XML document for an VisibleObject:
 *
 * 1) Construction based on XML file (@see VisibleObject(const char *aFileName)).
 * In this case, the XML document is created by parsing the XML file.
 *
 * 2) Construction by VisibleObject(const XMLDocument *aDocument).
 * This constructor explictly requests construction based on an
 * XML document.  In this way the proper connection between an object's node
 * and the corresponding node within the XML document is established.
 * This constructor is a copy constructor of sorts because all essential
 * VisibleObject member variables should be held within the XML document.
 * The advantage of this style of construction is that nodes
 * within the XML document, such as comments that may not have any
 * associated VisibleObject member variable, are preserved.
 *
 * 3) A call to generateXMLDocument().
 * This method generates an XML document for the VisibleObject from scratch.
 * Only the essential document nodes are created (that is, nodes that
 * correspond directly to member variables.).
 *
 * @param aObject Object to be copied.
 * @see VisibleObject(const XMLDocument *aDocument)
 * @see VisibleObject(const char *aFileName)
 * @see generateXMLDocument()
 */
VisibleObject::VisibleObject(const VisibleObject &aObject):
Object(aObject),
_geometryFileNames(_propGeometryFileNames.getValueStrArray()),
_allGeometry(0),
_propVisibleProp(PropertyObj("", VisibleProperties())),
_visibleProp((VisibleProperties&)_propVisibleProp.getValueObj()),
_scaleFactors(_propScaleFactors.getValueDblArray()),
_dependents(0)
{
	// NULL MEMBER VARIABLES
	setNull();

	// COPY TYPE AND NAME
	*this = aObject;
}

//=============================================================================
// CONSTRUCTION METHODS
//=============================================================================
//_____________________________________________________________________________
/**
 * Set all member variables to their null or default values.
 */
void VisibleObject::
setNull()
{
	setupProperties();

	Array<double> unit3(1.0, 3);
	_scaleFactors = unit3;

	_owner = 0;
	_dependents.setMemoryOwner(false);

}
/**
 * virtual copy constructor
 */
Object* VisibleObject::
copy() const
{

	VisibleObject *object = new VisibleObject(*this);
	return(object);
}
//_____________________________________________________________________________
/**
 * Connect properties to local pointers.
 */
void VisibleObject::setupProperties()
{

	_propGeometryFileNames.setName("geometry_files");
	Array<string> filenames("");
	_propGeometryFileNames.setValue(filenames);
	_propertySet.append(&_propGeometryFileNames);

	_propVisibleProp.setName("visible_properties");
	_propertySet.append(&_propVisibleProp);

	_propScaleFactors.setName("scale_factors");
	_propScaleFactors.setAllowableArraySize(3);
	_propertySet.append(&_propScaleFactors);
}

//=============================================================================
// OPERATORS
//=============================================================================
//-----------------------------------------------------------------------------
// ASSIGNMENT
//-----------------------------------------------------------------------------
//_____________________________________________________________________________
/**
 * Assign this object to the values of another.
 *
 * @return Reference to this object.
 */
VisibleObject& VisibleObject::
operator=(const VisibleObject &aObject)
{
	// BASE CLASS
	Object::operator=(aObject);

	setNumGeometryFiles(aObject.getNumGeometryFiles());
	for(int i=0; i < aObject.getNumGeometryFiles(); i++)
		setGeometryFileName(i, aObject.getGeometryFileName(i));

	_transform = aObject._transform;
	_visibleProp = aObject._visibleProp;

	_scaleFactors = aObject._scaleFactors;
	return(*this);
}

//-----------------------------------------------------------------------------
// EQUALITY
//-----------------------------------------------------------------------------
//_____________________________________________________________________________
/**
 * Determine if two objects are equal.
 *
 * @return True if the two objects are equal, false otherwise.
 */
bool VisibleObject::
operator==(const VisibleObject &aObject)
{
	return(Object::operator==(aObject));
}

//=============================================================================
// GET AND SET
//=============================================================================
//------------- Geometry files mgmt. -------------------------------------------
/**
 * set the number of geometry files associated with visible object
 */
void VisibleObject::
setNumGeometryFiles(int n)
{
	_geometryFileNames.setSize(n);
}
/**
 * Get the number of geometry files associated with visible object
 */
const int VisibleObject::
getNumGeometryFiles() const
{
	return (_geometryFileNames.getSize());
}
/**
 * set the name of ith geometry files associated with visible object
 */
void VisibleObject::
setGeometryFileName(int i, const string &aGeometryFileName)
{
	_geometryFileNames.set(i,aGeometryFileName);
}
/**
 * Get the name of ith geometry files associated with visible object
 */

const std::string& VisibleObject::
getGeometryFileName(int i) const
{
	return _geometryFileNames[i];
}

/**
 * set the visible properties of a visible object
 */
//------------- Properties: Shading, Color, etc. -------------------------------
void VisibleObject::
setVisibleProperties(const VisibleProperties &aVisibleProperties)
{
	_visibleProp = aVisibleProperties;
}
/**
 * Retrieve the visible properties of a visible object
 */
VisibleProperties& VisibleObject::
getVisibleProperties()
{
	return (_visibleProp);
}
//_____________________________________________________________________________
/**
 * Set Scale factors for geometry.
 *
 */
void VisibleObject::
setScaleFactors(const double aScaleFactors[3])
{
	_propScaleFactors.setUseDefault(false);
	for(int i=0; i < 3; i++)
		_scaleFactors[i]=(aScaleFactors[i]);
}
//_____________________________________________________________________________
/**
 * Get Scale factors for geometry.
 *
 */
void VisibleObject::
getScaleFactors(double aScaleFactors[3]) const
{
	for(int i=0; i < 3; i++)
		aScaleFactors[i] = _scaleFactors[i];
}
//------------- Transform -----------------------------------------------------
/**
 * Set the transform of a visible object
 */
void VisibleObject::
setTransform(const Transform &aTransform)
{
	_transform = aTransform;
	setChanged();
}
/**
 * Retrieve the transform of a visible object
 */

Transform& VisibleObject::
getTransform()
{
	return _transform;
}
//------------- Transform -----------------------------------------------------
// More interfaces for transform as other interfaces (Angles based) are needed
// Rotations in Radians
// three rotation angles, assumed order XYZ
/**
 * Rotate a visible object by 3 angles in radians around XYZ in order
 */
void VisibleObject::
rotateRadians(const double rR[3])
{
	getTransform().rotate(rR, Transform::Radians, Transform::XYZ);
}

/**
 * Rotate a visible object by 3 angles in radians with user specified order
 */
void VisibleObject::
rotateRadians(const double rR[3], const Transform::RotationOrder order)
{
	getTransform().rotate(rR, Transform::Radians, order);
}
/**
 * Rotate a visible object by an angle in radians around X axis
 */
void VisibleObject::
rotateRadiansX(const double rR)
{
	getTransform().rotateX(rR, Transform::Radians);
}
/**
 * Rotate a visible object by an angle in radians around Y axis
 */
void VisibleObject::
rotateRadiansY(const double rR)
{
	getTransform().rotateY(rR, Transform::Radians);
}
/**
 * Rotate a visible object by an angle in radians around Z axis
 */
void VisibleObject::
rotateRadiansZ(const double rR)
{
	getTransform().rotateZ(rR, Transform::Radians);
}
/**
 * Rotate a visible object by an angle in radians around an axis
 */
void VisibleObject::
rotateRadiansAxis(const double rR, const double axis[3])
{
	getTransform().rotateAxis(rR, Transform::Radians, axis);
}

/**
 * Rotate a visible object by three euler angle in degrees around in XYZ order
 */

void VisibleObject::
rotateDegrees(const double rD[3])
{
	getTransform().rotate(rD, Transform::Degrees, Transform::XYZ);
}
/**
 * Rotate a visible object by three euler angle in degrees around in specified order
 */
void VisibleObject::
rotateDegrees(const double rD[3], const Transform::RotationOrder order)
{
	getTransform().rotate(rD, Transform::Degrees, order);
}
/**
 * Rotate a visible object by an angle in degrees around X axis
 */
void VisibleObject::
rotateDegreesX(const double rD)
{
	getTransform().rotateX(rD, Transform::Degrees);
}
/**
 * Rotate a visible object by an angle in degrees around Y axis
 */
void VisibleObject::
rotateDegreesY(const double rD)
{
	getTransform().rotateY(rD, Transform::Degrees);
}
/**
 * Rotate a visible object by an angle in degrees around Z axis
 */
void VisibleObject::
rotateDegreesZ(const double rD)
{
	getTransform().rotateZ(rD, Transform::Degrees);
}
/**
 * Rotate a visible object by an angle in degrees around an axis
 */
void VisibleObject::
rotateDegreesAxis(const double rD, const double axis[3])
{
	getTransform().rotateAxis(rD, Transform::Degrees, axis);
}
/**
 * Translate a visible object by a translation vector
 */
void VisibleObject::
translate(const double t[3])
{
	getTransform().translate(t);
}

<|endoftext|>


<commit_before>//
//  Shader.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/02/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#ifndef Shader_hpp
#define Shader_hpp

#include "OpenGL.hpp"

namespace OpenGL {
  class Shader {
	public:
		enum {
			VertexShaderCompilationError,
			FragmentShaderCompilationError,
			ProgramLinkageError
		};

		struct AttributeBinding {
			const GLchar *name;
			GLuint index;
		};

		/*!
			Attempts to compile a shader, throwing @c VertexShaderCompilationError, @c FragmentShaderCompilationError or @c ProgramLinkageError upon failure.
			@param vertex_shader The vertex shader source code.
			@param fragment_shader The fragment shader source code.
			@param attribute_bindings Either @c nullptr or an array terminated by an entry with a @c nullptr-name of attribute bindings.
		*/
		Shader(const char *vertex_shader, const char *fragment_shader, const AttributeBinding *attribute_bindings);
		~Shader();

		/*!
			Performs an @c glUseProgram to make this the active shader.
		*/
		void bind();

		/*!
			Performs a @c glGetAttribLocation call.
			@param name The name of the attribute to locate.
			@returns The location of the requested attribute.
		*/
		GLint get_attrib_location(const GLchar *name);

		/*!
			Performs a @c glGetUniformLocation call.
			@param name The name of the uniform to locate.
			@returns The location of the requested uniform.
		*/
		GLint get_uniform_location(const GLchar *name);

	private:
		GLuint compile_shader(const char *source, GLenum type);
		GLuint _shader_program;
  };
}

#endif /* Shader_hpp */
<commit_msg>Standardised indentation and added one extra piece of documentation.<commit_after>//
//  Shader.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/02/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#ifndef Shader_hpp
#define Shader_hpp

#include "OpenGL.hpp"

namespace OpenGL {

/*!
	A @c Shader compiles and holds a shader object, based on a single
	vertex program and a single fragment program. Attribute bindings
	may be supplied if desired.
*/
class Shader {
public:
	enum {
		VertexShaderCompilationError,
		FragmentShaderCompilationError,
		ProgramLinkageError
	};

	struct AttributeBinding {
		const GLchar *name;
		GLuint index;
	};

	/*!
		Attempts to compile a shader, throwing @c VertexShaderCompilationError, @c FragmentShaderCompilationError or @c ProgramLinkageError upon failure.
		@param vertex_shader The vertex shader source code.
		@param fragment_shader The fragment shader source code.
		@param attribute_bindings Either @c nullptr or an array terminated by an entry with a @c nullptr-name of attribute bindings.
	*/
	Shader(const char *vertex_shader, const char *fragment_shader, const AttributeBinding *attribute_bindings);
	~Shader();

	/*!
		Performs an @c glUseProgram to make this the active shader.
	*/
	void bind();

	/*!
		Performs a @c glGetAttribLocation call.
		@param name The name of the attribute to locate.
		@returns The location of the requested attribute.
	*/
	GLint get_attrib_location(const GLchar *name);

	/*!
		Performs a @c glGetUniformLocation call.
		@param name The name of the uniform to locate.
		@returns The location of the requested uniform.
	*/
	GLint get_uniform_location(const GLchar *name);

private:
	GLuint compile_shader(const char *source, GLenum type);
	GLuint _shader_program;
};

}

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


<commit_before>#include "WireFitQLearn.h"

using namespace net;

WireFitQLearn::WireFitQLearn(NeuralNet *modelNetwork, Backpropagation backprop_, double learningRate_, double devaluationFactor_, int actionDimensions_, int numberOfWires_) {
    backprop = backprop_;
    learningRate = learningRate_;
    devaluationFactor = devaluationFactor_;
    actionDimensions = actionDimensions_;
    numberOfWires = numberOfWires_;
    lastAction = std::vector<double>(actionDimensions);
    network = modelNetwork;
    scalingFactorToMillis = 0.5;
}

WireFitQLearn::WireFitQLearn(std::string filename) {
    std::ifstream input(filename);
    if(input.is_open()) {
        input >> learningRate >> devaluationFactor >> scalingFactorToMillis;
        input >> actionDimensions >> numberOfWires;

        lastAction = std::vector<double>(actionDimensions);
        for(int a = 0; a < actionDimensions; a++) {
            double temp;
            input >> temp;
            lastAction[a] = temp;

        }

        backprop = Backpropagation(input);
        network = new NeuralNet(input);

        input.close();
    } else {
        std::cout << "Could not retrieve neural network from file\n";
        throw 1;
    }
}

WireFitQLearn::WireFitQLearn() { }

std::vector<double> WireFitQLearn::chooseBestAction(std::vector<double> currentState) {
    std::vector<double> action = bestAction(currentState);
    lastAction = action;
    lastState = currentState;
    return action;
}

std::vector<double> WireFitQLearn::chooseBoltzmanAction(std::vector<double> currentState, double explorationConstant) {
    double determiner = (double)rand() / (double)RAND_MAX;
    std::vector<double> exponentTerms;
    double sumOfExponentTerms = 0;
    std::vector<Wire> wires = getWires(currentState);

    for(int a = 0; a < wires.size(); a++) {
        double exponentTerm = exp(wires[a].reward / explorationConstant);
        exponentTerms.push_back(exponentTerm);
        sumOfExponentTerms += exponentTerm;
    }

    double sumOfProbabilities = 0;
    for(int a = 0; a < wires.size(); a++) {
        sumOfProbabilities += (exponentTerms[a] / sumOfExponentTerms);
        if(sumOfProbabilities >= determiner) {
            lastAction = wires[a].action;
            lastState = currentState;
            return wires[a].action;
        }
    }

    throw 1;

}

void WireFitQLearn::applyReinforcementToLastAction(double reward, std::vector<double> newState, double elapsedTimeMillis) {

}

void WireFitQLearn::storeWireFitQLearn(std::string filename) {
    std::ofstream output(filename);
    if(output.is_open()) {
        output << learningRate << " " << devaluationFactor << " " << scalingFactorToMillis << "\n";
        output << actionDimensions << " " << numberOfWires << "\n";

        for(int a = 0; a < lastAction.size(); a++) output << lastAction[a] << " ";
        output << "\n";

        backprop.storeBackpropagationWithStream(output);
        network->storeNetWithStream(output);

        output.close();
    } else {
        std::cout << "Could not retrieve neural network from file\n";
        throw 1;
    }
}

std::vector<Wire> WireFitQLearn::getWires(std::vector<double> state) {
    std::vector<Wire> wires(numberOfWires);
    std::vector<double> rawOutput = network->getOutput(state);

    for(int a = 0; a < numberOfWires; a++) {
        int currentIndex = a * (actionDimensions + 1);
        Wire wire;
        wire.action = std::vector<double>(actionDimensions);
        for(int b = 0; b < actionDimensions; b++) wire.action[a] = rawOutput[currentIndex + b];

        wire.reward = rawOutput[currentIndex + actionDimensions];

        wires[a] = wire;
    }

    return wires;
}

std::vector<double> WireFitQLearn::getRawOutput(std::vector<Wire> wires) {
    std::vector<double> rawOutput(wires.size() * (actionDimensions + 1));

    for(int a = 0; a < wires.size(); a++) {
        int currentIndex = a * (actionDimensions + 1);
        Wire wire = wires[a];
        for(int b = 0; b < wire.action.size(); b++) rawOutput[currentIndex + b] = wire.action[b];

        rawOutput[currentIndex + wire.action.size()] = wire.reward;
    }

    return rawOutput;
}

double WireFitQLearn::highestReward(std::vector<double> state) {
    std::vector<Wire> wires = getWires(state);
    double bestReward = -99999;

    for(int a = 0; a < wires.size(); a++) if(wires[a].reward > bestReward) bestReward = wires[a].reward;

    return bestReward;
}

std::vector<double> WireFitQLearn::bestAction(std::vector<double> state) {
    std::vector<Wire> wires = getWires(state);
    double bestReward = -99999;
    std::vector<double> bestAction;

    for(int a = 0; a < wires.size(); a++) {
        if(wires[a].reward > bestReward) {
            bestAction = wires[a].action;
            bestReward = wires[a].reward;
        }
    }

    return bestAction;
}

double WireFitQLearn::wireFitting(std::vector<double> state, std::vector<Wire> wires, std::vector<double> action) {
    return weightedsum(state, wires, action) / normalize(state, wires, action);
}

double WireFitQLearn::distance(std::vector<double> &state, Wire &wire, std::vector<double> &action, double maxRewardFromWires) {
    double c = 1;

    double euclideanNorm = 0;
    for(int a = 0; a < action.size(); a++) euclideanNorm += pow(action[a] - wire.action[a], 2);

    return (euclideanNorm * euclideanNorm) + c*(maxRewardFromWires - wire.reward) + M_E;
}
double WireFitQLearn::weightedsum(std::vector<double> &state, std::vector<Wire> &wires, std::vector<double> &action) {
    double maxRewardFromWires = -9999999;
    for(auto a = wires.begin(); a != wires.end(); ++a) if(a->reward > maxRewardFromWires) maxRewardFromWires = a->reward;

    double answer = 0;
    for(auto a = wires.begin(); a != wires.end(); ++a) {
        answer += a->reward / distance(state, *a, action, maxRewardFromWires);
    }

    return answer;
}
double WireFitQLearn::normalize(std::vector<double> &state, std::vector<Wire> &wires, std::vector<double> &action) {
    double maxRewardFromWires = -9999999;
    for(auto a = wires.begin(); a != wires.end(); ++a) if(a->reward > maxRewardFromWires) maxRewardFromWires = a->reward;

    double answer = 0;
    for(auto a = wires.begin(); a != wires.end(); ++a) {
        answer += 1.0 / distance(state, *a, action, maxRewardFromWires);
    }

    return answer;
}
<commit_msg>Calculated new Q estimate<commit_after>#include "WireFitQLearn.h"

using namespace net;

WireFitQLearn::WireFitQLearn(NeuralNet *modelNetwork, Backpropagation backprop_, double learningRate_, double devaluationFactor_, int actionDimensions_, int numberOfWires_) {
    backprop = backprop_;
    learningRate = learningRate_;
    devaluationFactor = devaluationFactor_;
    actionDimensions = actionDimensions_;
    numberOfWires = numberOfWires_;
    lastAction = std::vector<double>(actionDimensions);
    network = modelNetwork;
    scalingFactorToMillis = 0.5;
}

WireFitQLearn::WireFitQLearn(std::string filename) {
    std::ifstream input(filename);
    if(input.is_open()) {
        input >> learningRate >> devaluationFactor >> scalingFactorToMillis;
        input >> actionDimensions >> numberOfWires;

        lastAction = std::vector<double>(actionDimensions);
        for(int a = 0; a < actionDimensions; a++) {
            double temp;
            input >> temp;
            lastAction[a] = temp;

        }

        backprop = Backpropagation(input);
        network = new NeuralNet(input);

        input.close();
    } else {
        std::cout << "Could not retrieve neural network from file\n";
        throw 1;
    }
}

WireFitQLearn::WireFitQLearn() { }

std::vector<double> WireFitQLearn::chooseBestAction(std::vector<double> currentState) {
    std::vector<double> action = bestAction(currentState);
    lastAction = action;
    lastState = currentState;
    return action;
}

std::vector<double> WireFitQLearn::chooseBoltzmanAction(std::vector<double> currentState, double explorationConstant) {
    double determiner = (double)rand() / (double)RAND_MAX;
    std::vector<double> exponentTerms;
    double sumOfExponentTerms = 0;
    std::vector<Wire> wires = getWires(currentState);

    for(int a = 0; a < wires.size(); a++) {
        double exponentTerm = exp(wires[a].reward / explorationConstant);
        exponentTerms.push_back(exponentTerm);
        sumOfExponentTerms += exponentTerm;
    }

    double sumOfProbabilities = 0;
    for(int a = 0; a < wires.size(); a++) {
        sumOfProbabilities += (exponentTerms[a] / sumOfExponentTerms);
        if(sumOfProbabilities >= determiner) {
            lastAction = wires[a].action;
            lastState = currentState;
            return wires[a].action;
        }
    }

    throw 1;

}

void WireFitQLearn::applyReinforcementToLastAction(double reward, std::vector<double> newState, double elapsedTimeMillis) {
    std::vector<Wire> wires = getWires(lastState);
    double scalingFactor = scalingFactorToMillis * elapsedTimeMillis;

    /// Update Q value according to adaptive learning
    double oldValue = wireFitting(lastState, wires, lastAction);
    double feedback = ((1/scalingFactor)*(reward + (pow(devaluationFactor, scalingFactor)*highestReward(newState)))) + (1 - 1/scalingFactor) * highestReward(lastState);
    double newQ = ((1 - learningRate) * oldValue) + (learningRate*feedback);

}

void WireFitQLearn::storeWireFitQLearn(std::string filename) {
    std::ofstream output(filename);
    if(output.is_open()) {
        output << learningRate << " " << devaluationFactor << " " << scalingFactorToMillis << "\n";
        output << actionDimensions << " " << numberOfWires << "\n";

        for(int a = 0; a < lastAction.size(); a++) output << lastAction[a] << " ";
        output << "\n";

        backprop.storeBackpropagationWithStream(output);
        network->storeNetWithStream(output);

        output.close();
    } else {
        std::cout << "Could not retrieve neural network from file\n";
        throw 1;
    }
}

std::vector<Wire> WireFitQLearn::getWires(std::vector<double> state) {
    std::vector<Wire> wires(numberOfWires);
    std::vector<double> rawOutput = network->getOutput(state);

    for(int a = 0; a < numberOfWires; a++) {
        int currentIndex = a * (actionDimensions + 1);
        Wire wire;
        wire.action = std::vector<double>(actionDimensions);
        for(int b = 0; b < actionDimensions; b++) wire.action[a] = rawOutput[currentIndex + b];

        wire.reward = rawOutput[currentIndex + actionDimensions];

        wires[a] = wire;
    }

    return wires;
}

std::vector<double> WireFitQLearn::getRawOutput(std::vector<Wire> wires) {
    std::vector<double> rawOutput(wires.size() * (actionDimensions + 1));

    for(int a = 0; a < wires.size(); a++) {
        int currentIndex = a * (actionDimensions + 1);
        Wire wire = wires[a];
        for(int b = 0; b < wire.action.size(); b++) rawOutput[currentIndex + b] = wire.action[b];

        rawOutput[currentIndex + wire.action.size()] = wire.reward;
    }

    return rawOutput;
}

double WireFitQLearn::highestReward(std::vector<double> state) {
    std::vector<Wire> wires = getWires(state);
    double bestReward = -99999;

    for(int a = 0; a < wires.size(); a++) if(wires[a].reward > bestReward) bestReward = wires[a].reward;

    return bestReward;
}

std::vector<double> WireFitQLearn::bestAction(std::vector<double> state) {
    std::vector<Wire> wires = getWires(state);
    double bestReward = -99999;
    std::vector<double> bestAction;

    for(int a = 0; a < wires.size(); a++) {
        if(wires[a].reward > bestReward) {
            bestAction = wires[a].action;
            bestReward = wires[a].reward;
        }
    }

    return bestAction;
}

double WireFitQLearn::wireFitting(std::vector<double> state, std::vector<Wire> wires, std::vector<double> action) {
    return weightedsum(state, wires, action) / normalize(state, wires, action);
}

double WireFitQLearn::distance(std::vector<double> &state, Wire &wire, std::vector<double> &action, double maxRewardFromWires) {
    double c = 1;

    double euclideanNorm = 0;
    for(int a = 0; a < action.size(); a++) euclideanNorm += pow(action[a] - wire.action[a], 2);

    return (euclideanNorm * euclideanNorm) + c*(maxRewardFromWires - wire.reward) + M_E;
}
double WireFitQLearn::weightedsum(std::vector<double> &state, std::vector<Wire> &wires, std::vector<double> &action) {
    double maxRewardFromWires = -9999999;
    for(auto a = wires.begin(); a != wires.end(); ++a) if(a->reward > maxRewardFromWires) maxRewardFromWires = a->reward;

    double answer = 0;
    for(auto a = wires.begin(); a != wires.end(); ++a) {
        answer += a->reward / distance(state, *a, action, maxRewardFromWires);
    }

    return answer;
}
double WireFitQLearn::normalize(std::vector<double> &state, std::vector<Wire> &wires, std::vector<double> &action) {
    double maxRewardFromWires = -9999999;
    for(auto a = wires.begin(); a != wires.end(); ++a) if(a->reward > maxRewardFromWires) maxRewardFromWires = a->reward;

    double answer = 0;
    for(auto a = wires.begin(); a != wires.end(); ++a) {
        answer += 1.0 / distance(state, *a, action, maxRewardFromWires);
    }

    return answer;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Daniel Warner <contact@danrw.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Tle.h"

#include <locale>

namespace
{
    static const unsigned int TLE1_COL_NORADNUM = 2;
    static const unsigned int TLE1_LEN_NORADNUM = 5;
    static const unsigned int TLE1_COL_INTLDESC_A = 9;
    static const unsigned int TLE1_LEN_INTLDESC_A = 2;
    static const unsigned int TLE1_COL_INTLDESC_B = 11;
    static const unsigned int TLE1_LEN_INTLDESC_B = 3;
    static const unsigned int TLE1_COL_INTLDESC_C = 14;
    static const unsigned int TLE1_LEN_INTLDESC_C = 3;
    static const unsigned int TLE1_COL_EPOCH_A = 18;
    static const unsigned int TLE1_LEN_EPOCH_A = 2;
    static const unsigned int TLE1_COL_EPOCH_B = 20;
    static const unsigned int TLE1_LEN_EPOCH_B = 12;
    static const unsigned int TLE1_COL_MEANMOTIONDT2 = 33;
    static const unsigned int TLE1_LEN_MEANMOTIONDT2 = 10;
    static const unsigned int TLE1_COL_MEANMOTIONDDT6 = 44;
    static const unsigned int TLE1_LEN_MEANMOTIONDDT6 = 8;
    static const unsigned int TLE1_COL_BSTAR = 53;
    static const unsigned int TLE1_LEN_BSTAR = 8;
    static const unsigned int TLE1_COL_EPHEMTYPE = 62;
    static const unsigned int TLE1_LEN_EPHEMTYPE = 1;
    static const unsigned int TLE1_COL_ELNUM = 64;
    static const unsigned int TLE1_LEN_ELNUM = 4;

    static const unsigned int TLE2_COL_NORADNUM = 2;
    static const unsigned int TLE2_LEN_NORADNUM = 5;
    static const unsigned int TLE2_COL_INCLINATION = 8;
    static const unsigned int TLE2_LEN_INCLINATION = 8;
    static const unsigned int TLE2_COL_RAASCENDNODE = 17;
    static const unsigned int TLE2_LEN_RAASCENDNODE = 8;
    static const unsigned int TLE2_COL_ECCENTRICITY = 26;
    static const unsigned int TLE2_LEN_ECCENTRICITY = 7;
    static const unsigned int TLE2_COL_ARGPERIGEE = 34;
    static const unsigned int TLE2_LEN_ARGPERIGEE = 8;
    static const unsigned int TLE2_COL_MEANANOMALY = 43;
    static const unsigned int TLE2_LEN_MEANANOMALY = 8;
    static const unsigned int TLE2_COL_MEANMOTION = 52;
    static const unsigned int TLE2_LEN_MEANMOTION = 11;
    static const unsigned int TLE2_COL_REVATEPOCH = 63;
    static const unsigned int TLE2_LEN_REVATEPOCH = 5;
}

/**
 * Initialise the tle object.
 * @exception TleException
 */
void Tle::Initialize()
{
    if (!IsValidLineLength(line_one_))
    {
        throw TleException("Invalid length for line one");
    }

    if (!IsValidLineLength(line_two_))
    {
        throw TleException("Invalid length for line two");
    }

    if (line_one_[0] != '1')
    {
        throw TleException("Invalid line beginning for line one");
    }

    if (line_two_[0] != '2')
    {
        throw TleException("Invalid line beginning for line two");
    }

    unsigned int sat_number_1;
    unsigned int sat_number_2;

    ExtractInteger(line_one_.substr(TLE1_COL_NORADNUM,
                TLE1_LEN_NORADNUM), sat_number_1);
    ExtractInteger(line_two_.substr(TLE2_COL_NORADNUM,
                TLE2_LEN_NORADNUM), sat_number_2);

    if (sat_number_1 != sat_number_2)
    {
        throw TleException("Satellite numbers do not match");
    }

    norad_number_ = sat_number_1;

    if (name_.empty())
    {
        name_ = line_one_.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM);
    }

    int_designator_ = line_one_.substr(TLE1_COL_INTLDESC_A,
            TLE1_LEN_INTLDESC_A + TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);

    unsigned int year = 0;
    double day = 0.0;

    ExtractInteger(line_one_.substr(TLE1_COL_EPOCH_A,
                TLE1_LEN_EPOCH_A), year);
    ExtractDouble(line_one_.substr(TLE1_COL_EPOCH_B,
                TLE1_LEN_EPOCH_B), 4, day);
    ExtractDouble(line_one_.substr(TLE1_COL_MEANMOTIONDT2,
                TLE1_LEN_MEANMOTIONDT2), 2, mean_motion_dt2_);
    ExtractExponential(line_one_.substr(TLE1_COL_MEANMOTIONDDT6,
                TLE1_LEN_MEANMOTIONDDT6), mean_motion_ddt6_);
    ExtractExponential(line_one_.substr(TLE1_COL_BSTAR,
                TLE1_LEN_BSTAR), bstar_);

    /*
     * line 2
     */
    ExtractDouble(line_two_.substr(TLE2_COL_INCLINATION,
                TLE2_LEN_INCLINATION), 4, inclination_);
    ExtractDouble(line_two_.substr(TLE2_COL_RAASCENDNODE,
                TLE2_LEN_RAASCENDNODE), 4, right_ascending_node_);
    ExtractDouble(line_two_.substr(TLE2_COL_ECCENTRICITY,
                TLE2_LEN_ECCENTRICITY), -1, eccentricity_);
    ExtractDouble(line_two_.substr(TLE2_COL_ARGPERIGEE,
                TLE2_LEN_ARGPERIGEE), 4, argument_perigee_);
    ExtractDouble(line_two_.substr(TLE2_COL_MEANANOMALY,
                TLE2_LEN_MEANANOMALY), 4, mean_anomaly_);
    ExtractDouble(line_two_.substr(TLE2_COL_MEANMOTION,
                TLE2_LEN_MEANMOTION), 3, mean_motion_);
    ExtractInteger(line_two_.substr(TLE2_COL_REVATEPOCH,
                TLE2_LEN_REVATEPOCH), orbit_number_);

    if (year < 57)
        year += 2000;
    else
        year += 1900;
    epoch_ = DateTime(year, day);
}

/**
 * Check
 * @param str The string to check
 * @returns Whether true of the string has a valid length
 */
bool Tle::IsValidLineLength(const std::string& str)
{
    return str.length() == LineLength() ? true : false;
}

/**
 * Convert a string containing an integer
 * @param[in] str The string to convert
 * @param[out] val The result
 * @exception TleException on conversion error
 */
void Tle::ExtractInteger(const std::string& str, unsigned int& val)
{
    std::string temp;
    bool found_digit = false;

    for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
    {
        if (isdigit(*i))
        {
            found_digit = true;
            temp += *i;
        }
        else if (found_digit)
        {
            throw TleException("Unexpected non digit");
        }
        else if (*i != ' ')
        {
            throw TleException("Invalid character");
        }
    }

    if (temp.length() == 0)
    {
        temp += '0';
    }

    if (!Util::FromString<unsigned int>(temp, val))
    {
        throw TleException("Failed to convert value to integer");
    }
}

/**
 * Convert a string containing an double
 * @param[in] str The string to convert
 * @param[in] point_pos The position of the decimal point. (-1 if none)
 * @param[out] val The result
 * @exception TleException on conversion error
 */
void Tle::ExtractDouble(const std::string& str, int point_pos, double& val)
{
    std::string temp;
    bool found_digit = false;

    for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
    {
        /*
         * integer part
         */
        if (i < str.begin() + point_pos - 1)
        {
            bool done = false;

            if (i == str.begin())
            {
                if(*i == '-' || *i == '+')
                {
                    /*
                     * first character could be signed
                     */
                    temp += *i;
                    done = true;
                }
            }

            if (!done)
            {
                if (isdigit(*i))
                {
                    found_digit = true;
                    temp += *i;
                }
                else if (found_digit)
                {
                    throw TleException("Unexpected non digit");
                }
                else if (*i != ' ')
                {
                    throw TleException("Invalid character");
                }
            }
        }
        /*
         * decimal point
         */
        else if (i == str.begin() + point_pos - 1)
        {
            if (temp.length() == 0)
            {
                /*
                 * integer part is blank, so add a '0'
                 */
                temp += '0';
            }

            if (*i == '.')
            {
                /*
                 * decimal point found
                 */
                temp += *i;
            }
            else
            {
                throw TleException("Failed to find decimal point");
            }
        }
        /*
         * fraction part
         */
        else
        {
            if (i == str.begin() && point_pos == -1)
            {
                /*
                 * no decimal point expected, add 0. beginning
                 */
                temp += '0';
                temp += '.';
            }

            /*
             * should be a digit
             */
            if (isdigit(*i))
            {
                temp += *i;
            }
            else
            {
                throw TleException("Invalid digit");
            }
        }
    }

    if (!Util::FromString<double>(temp, val))
    {
        throw TleException("Failed to convert value to double");
    }
}

/**
 * Convert a string containing an exponential
 * @param[in] str The string to convert
 * @param[out] val The result
 * @exception TleException on conversion error
 */
void Tle::ExtractExponential(const std::string& str, double& val)
{
    std::string temp;

    for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
    {
        if (i == str.begin())
        {
            if (*i == '-' || *i == '+' || *i == ' ')
            {
                if (*i == '-')
                {
                    temp += *i;
                }
                temp += '0';
                temp += '.';
            }
            else
            {
                throw TleException("Invalid sign");
            }
        }
        else if (i == str.begin() + str.length() - 2)
        {
            if (*i == '-' || *i == '+')
            {
                temp += 'e';
                temp += *i;
            }
            else
            {
                throw TleException("Invalid exponential sign");
            }
        }
        else
        {
            if (isdigit(*i))
            {
                temp += *i;
            }
            else
            {
                throw TleException("Invalid digit");
            }
        }
    }

    if (!Util::FromString<double>(temp, val))
    {
        throw TleException("Failed to convert value to double");
    }
}
<commit_msg>Change year to signed in Tle.cpp.<commit_after>/*
 * Copyright 2013 Daniel Warner <contact@danrw.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Tle.h"

#include <locale>

namespace
{
    static const unsigned int TLE1_COL_NORADNUM = 2;
    static const unsigned int TLE1_LEN_NORADNUM = 5;
    static const unsigned int TLE1_COL_INTLDESC_A = 9;
    static const unsigned int TLE1_LEN_INTLDESC_A = 2;
    static const unsigned int TLE1_COL_INTLDESC_B = 11;
    static const unsigned int TLE1_LEN_INTLDESC_B = 3;
    static const unsigned int TLE1_COL_INTLDESC_C = 14;
    static const unsigned int TLE1_LEN_INTLDESC_C = 3;
    static const unsigned int TLE1_COL_EPOCH_A = 18;
    static const unsigned int TLE1_LEN_EPOCH_A = 2;
    static const unsigned int TLE1_COL_EPOCH_B = 20;
    static const unsigned int TLE1_LEN_EPOCH_B = 12;
    static const unsigned int TLE1_COL_MEANMOTIONDT2 = 33;
    static const unsigned int TLE1_LEN_MEANMOTIONDT2 = 10;
    static const unsigned int TLE1_COL_MEANMOTIONDDT6 = 44;
    static const unsigned int TLE1_LEN_MEANMOTIONDDT6 = 8;
    static const unsigned int TLE1_COL_BSTAR = 53;
    static const unsigned int TLE1_LEN_BSTAR = 8;
    static const unsigned int TLE1_COL_EPHEMTYPE = 62;
    static const unsigned int TLE1_LEN_EPHEMTYPE = 1;
    static const unsigned int TLE1_COL_ELNUM = 64;
    static const unsigned int TLE1_LEN_ELNUM = 4;

    static const unsigned int TLE2_COL_NORADNUM = 2;
    static const unsigned int TLE2_LEN_NORADNUM = 5;
    static const unsigned int TLE2_COL_INCLINATION = 8;
    static const unsigned int TLE2_LEN_INCLINATION = 8;
    static const unsigned int TLE2_COL_RAASCENDNODE = 17;
    static const unsigned int TLE2_LEN_RAASCENDNODE = 8;
    static const unsigned int TLE2_COL_ECCENTRICITY = 26;
    static const unsigned int TLE2_LEN_ECCENTRICITY = 7;
    static const unsigned int TLE2_COL_ARGPERIGEE = 34;
    static const unsigned int TLE2_LEN_ARGPERIGEE = 8;
    static const unsigned int TLE2_COL_MEANANOMALY = 43;
    static const unsigned int TLE2_LEN_MEANANOMALY = 8;
    static const unsigned int TLE2_COL_MEANMOTION = 52;
    static const unsigned int TLE2_LEN_MEANMOTION = 11;
    static const unsigned int TLE2_COL_REVATEPOCH = 63;
    static const unsigned int TLE2_LEN_REVATEPOCH = 5;
}

/**
 * Initialise the tle object.
 * @exception TleException
 */
void Tle::Initialize()
{
    if (!IsValidLineLength(line_one_))
    {
        throw TleException("Invalid length for line one");
    }

    if (!IsValidLineLength(line_two_))
    {
        throw TleException("Invalid length for line two");
    }

    if (line_one_[0] != '1')
    {
        throw TleException("Invalid line beginning for line one");
    }

    if (line_two_[0] != '2')
    {
        throw TleException("Invalid line beginning for line two");
    }

    unsigned int sat_number_1;
    unsigned int sat_number_2;

    ExtractInteger(line_one_.substr(TLE1_COL_NORADNUM,
                TLE1_LEN_NORADNUM), sat_number_1);
    ExtractInteger(line_two_.substr(TLE2_COL_NORADNUM,
                TLE2_LEN_NORADNUM), sat_number_2);

    if (sat_number_1 != sat_number_2)
    {
        throw TleException("Satellite numbers do not match");
    }

    norad_number_ = sat_number_1;

    if (name_.empty())
    {
        name_ = line_one_.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM);
    }

    int_designator_ = line_one_.substr(TLE1_COL_INTLDESC_A,
            TLE1_LEN_INTLDESC_A + TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);

    int year = 0;
    double day = 0.0;

    ExtractInteger(line_one_.substr(TLE1_COL_EPOCH_A,
                TLE1_LEN_EPOCH_A), year);
    ExtractDouble(line_one_.substr(TLE1_COL_EPOCH_B,
                TLE1_LEN_EPOCH_B), 4, day);
    ExtractDouble(line_one_.substr(TLE1_COL_MEANMOTIONDT2,
                TLE1_LEN_MEANMOTIONDT2), 2, mean_motion_dt2_);
    ExtractExponential(line_one_.substr(TLE1_COL_MEANMOTIONDDT6,
                TLE1_LEN_MEANMOTIONDDT6), mean_motion_ddt6_);
    ExtractExponential(line_one_.substr(TLE1_COL_BSTAR,
                TLE1_LEN_BSTAR), bstar_);

    /*
     * line 2
     */
    ExtractDouble(line_two_.substr(TLE2_COL_INCLINATION,
                TLE2_LEN_INCLINATION), 4, inclination_);
    ExtractDouble(line_two_.substr(TLE2_COL_RAASCENDNODE,
                TLE2_LEN_RAASCENDNODE), 4, right_ascending_node_);
    ExtractDouble(line_two_.substr(TLE2_COL_ECCENTRICITY,
                TLE2_LEN_ECCENTRICITY), -1, eccentricity_);
    ExtractDouble(line_two_.substr(TLE2_COL_ARGPERIGEE,
                TLE2_LEN_ARGPERIGEE), 4, argument_perigee_);
    ExtractDouble(line_two_.substr(TLE2_COL_MEANANOMALY,
                TLE2_LEN_MEANANOMALY), 4, mean_anomaly_);
    ExtractDouble(line_two_.substr(TLE2_COL_MEANMOTION,
                TLE2_LEN_MEANMOTION), 3, mean_motion_);
    ExtractInteger(line_two_.substr(TLE2_COL_REVATEPOCH,
                TLE2_LEN_REVATEPOCH), orbit_number_);

    if (year < 57)
        year += 2000;
    else
        year += 1900;
    epoch_ = DateTime(year, day);
}

/**
 * Check
 * @param str The string to check
 * @returns Whether true of the string has a valid length
 */
bool Tle::IsValidLineLength(const std::string& str)
{
    return str.length() == LineLength() ? true : false;
}

/**
 * Convert a string containing an integer
 * @param[in] str The string to convert
 * @param[out] val The result
 * @exception TleException on conversion error
 */
void Tle::ExtractInteger(const std::string& str, unsigned int& val)
{
    std::string temp;
    bool found_digit = false;

    for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
    {
        if (isdigit(*i))
        {
            found_digit = true;
            temp += *i;
        }
        else if (found_digit)
        {
            throw TleException("Unexpected non digit");
        }
        else if (*i != ' ')
        {
            throw TleException("Invalid character");
        }
    }

    if (temp.length() == 0)
    {
        temp += '0';
    }

    if (!Util::FromString<unsigned int>(temp, val))
    {
        throw TleException("Failed to convert value to integer");
    }
}

/**
 * Convert a string containing an double
 * @param[in] str The string to convert
 * @param[in] point_pos The position of the decimal point. (-1 if none)
 * @param[out] val The result
 * @exception TleException on conversion error
 */
void Tle::ExtractDouble(const std::string& str, int point_pos, double& val)
{
    std::string temp;
    bool found_digit = false;

    for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
    {
        /*
         * integer part
         */
        if (i < str.begin() + point_pos - 1)
        {
            bool done = false;

            if (i == str.begin())
            {
                if(*i == '-' || *i == '+')
                {
                    /*
                     * first character could be signed
                     */
                    temp += *i;
                    done = true;
                }
            }

            if (!done)
            {
                if (isdigit(*i))
                {
                    found_digit = true;
                    temp += *i;
                }
                else if (found_digit)
                {
                    throw TleException("Unexpected non digit");
                }
                else if (*i != ' ')
                {
                    throw TleException("Invalid character");
                }
            }
        }
        /*
         * decimal point
         */
        else if (i == str.begin() + point_pos - 1)
        {
            if (temp.length() == 0)
            {
                /*
                 * integer part is blank, so add a '0'
                 */
                temp += '0';
            }

            if (*i == '.')
            {
                /*
                 * decimal point found
                 */
                temp += *i;
            }
            else
            {
                throw TleException("Failed to find decimal point");
            }
        }
        /*
         * fraction part
         */
        else
        {
            if (i == str.begin() && point_pos == -1)
            {
                /*
                 * no decimal point expected, add 0. beginning
                 */
                temp += '0';
                temp += '.';
            }

            /*
             * should be a digit
             */
            if (isdigit(*i))
            {
                temp += *i;
            }
            else
            {
                throw TleException("Invalid digit");
            }
        }
    }

    if (!Util::FromString<double>(temp, val))
    {
        throw TleException("Failed to convert value to double");
    }
}

/**
 * Convert a string containing an exponential
 * @param[in] str The string to convert
 * @param[out] val The result
 * @exception TleException on conversion error
 */
void Tle::ExtractExponential(const std::string& str, double& val)
{
    std::string temp;

    for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
    {
        if (i == str.begin())
        {
            if (*i == '-' || *i == '+' || *i == ' ')
            {
                if (*i == '-')
                {
                    temp += *i;
                }
                temp += '0';
                temp += '.';
            }
            else
            {
                throw TleException("Invalid sign");
            }
        }
        else if (i == str.begin() + str.length() - 2)
        {
            if (*i == '-' || *i == '+')
            {
                temp += 'e';
                temp += *i;
            }
            else
            {
                throw TleException("Invalid exponential sign");
            }
        }
        else
        {
            if (isdigit(*i))
            {
                temp += *i;
            }
            else
            {
                throw TleException("Invalid digit");
            }
        }
    }

    if (!Util::FromString<double>(temp, val))
    {
        throw TleException("Failed to convert value to double");
    }
}
<|endoftext|>