text:
/**
 * Copyright (c) 2020 libnuls developers (see AUTHORS)
 *
 * This file is part of libnuls.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <nuls/system/wallet/encrypted_keys.hpp>

#include <cstdint>
#include <cstddef>
#include <algorithm>
#include <stdexcept>
#include <boost/locale.hpp>
#include <nuls/system/define.hpp>
#include <nuls/system/math/checksum.hpp>
#include <nuls/system/math/crypto.hpp>
#include <nuls/system/math/hash.hpp>
#include <nuls/system/math/elliptic_curve.hpp>
#include <nuls/system/unicode/unicode.hpp>
#include <nuls/system/utility/assert.hpp>
#include <nuls/system/utility/data.hpp>
#include <nuls/system/utility/endian.hpp>
#include <nuls/system/wallet/ec_private.hpp>
#include <nuls/system/wallet/ec_public.hpp>
#include "parse_encrypted_keys/parse_encrypted_key.hpp"
#include "parse_encrypted_keys/parse_encrypted_prefix.hpp"
#include "parse_encrypted_keys/parse_encrypted_private.hpp"
#include "parse_encrypted_keys/parse_encrypted_public.hpp"
#include "parse_encrypted_keys/parse_encrypted_token.hpp"

namespace libnuls {
namespace system {
namespace wallet {

// Alias commonly-used constants for brevity.
static constexpr auto half = half_hash_size;
static constexpr auto quarter = quarter_hash_size;

// Ensure that hash sizes are aligned with AES block size.
static_assert(2 * quarter == aes256_block_size, "oops!");

// address_
// ----------------------------------------------------------------------------

static hash_digest address_hash(const payment_address& address)
{
    return bitcoin_hash(to_chunk(address.encoded()));
}

static bool address_salt(ek_salt& salt, const payment_address& address)
{
    salt = slice<0, ek_salt_size>(address_hash(address));
    return true;
}

static bool address_salt(ek_salt& salt, const ec_compressed& point,
    uint8_t version, bool compressed)
{
    payment_address address({ point, compressed }, version);
    return address ? address_salt(salt, address) : false;
}

#ifdef WITH_ICU

static bool address_salt(ek_salt& salt, const ec_secret& secret,
    uint8_t version, bool compressed)
{
    payment_address address({ secret, version, compressed });
    return address ? address_salt(salt, address) : false;
}

static bool address_validate(const ek_salt& salt,
    const payment_address& address)
{
    const auto hash = address_hash(address);
    return std::equal(hash.begin(), hash.begin() + salt.size(), salt.begin());
}

static bool address_validate(const ek_salt& salt, const ec_compressed& point,
    uint8_t version, bool compressed)
{
    payment_address address({ point, compressed }, version);
    return address ? address_validate(salt, address) : false;
}

static bool address_validate(const ek_salt& salt, const ec_secret& secret,
    uint8_t version, bool compressed)
{
    payment_address address({ secret, version, compressed });
    return address ? address_validate(salt, address) : false;
}

#endif

// point_
// ----------------------------------------------------------------------------

static hash_digest point_hash(const ec_compressed& point)
{
    return slice<1, ec_compressed_size>(point);
}

static one_byte point_sign(uint8_t byte, const hash_digest& hash)
{
    static constexpr uint8_t low_bit_mask = 0x01;
    const uint8_t last_byte = hash.back();
    const uint8_t last_byte_odd_field = last_byte & low_bit_mask;
    const uint8_t sign_byte = byte ^ last_byte_odd_field;
    return to_array(sign_byte);
}

#ifdef WITH_ICU

static one_byte point_sign(const one_byte& single, const hash_digest& hash)
{
    return point_sign(single.front(), hash);
}

#endif

// scrypt_
// ----------------------------------------------------------------------------

#ifdef WITH_ICU

static hash_digest scrypt_token(const data_slice& data, const data_slice& salt)
{
    // Arbitrary scrypt parameters from BIP38.
    return scrypt<hash_size>(data, salt, 16384u, 8u, 8u);
}

#endif

static long_hash scrypt_pair(const data_slice& data, const data_slice& salt)
{
    // Arbitrary scrypt parameters from BIP38.
    return scrypt<long_hash_size>(data, salt, 1024u, 1u, 1u);
}

#ifdef WITH_ICU

static long_hash scrypt_private(const data_slice& data, const data_slice& salt)
{
    // Arbitrary scrypt parameters from BIP38.
    return scrypt<long_hash_size>(data, salt, 16384u, 8u, 8u);
}

#endif

// set_flags
// ----------------------------------------------------------------------------

static one_byte set_flags(bool compressed, bool lot_sequence, bool multiplied)
{
    uint8_t byte = 0;

    if (compressed)
        byte |= ek_flag::ec_compressed_key;

    if (lot_sequence)
        byte |= ek_flag::lot_sequence_key;

    if (!multiplied)
        byte |= ek_flag::ec_non_multiplied;

    return to_array(byte);
}

#ifdef WITH_ICU

static one_byte set_flags(bool compressed, bool lot_sequence)
{
    return set_flags(compressed, lot_sequence, false);
}

static one_byte set_flags(bool compressed)
{
    return set_flags(compressed, false);
}

#endif

// create_key_pair
// ----------------------------------------------------------------------------

static void create_private_key(encrypted_private& out_private,
    const one_byte& flags, const ek_salt& salt, const ek_entropy& entropy,
    const hash_digest& derived1, const hash_digest& derived2,
    const ek_seed& seed, uint8_t version)
{
    const auto prefix = parse_encrypted_private::prefix_factory(version, true);

    auto encrypt1 = xor_data<half>(seed, derived1);
    aes256_encrypt(derived2, encrypt1);
    const auto combined = splice(slice<quarter, half>(encrypt1),
        slice<half, half + quarter>(seed));

    auto encrypt2 = xor_data<half>(combined, derived1, 0, half);
    aes256_encrypt(derived2, encrypt2);
    const auto quarter1 = slice<0, quarter>(encrypt1);

    build_checked_array(out_private,
    {
        prefix,
        flags,
        salt,
        entropy,
        quarter1,
        encrypt2
    });
}

static bool create_public_key(encrypted_public& out_public,
    const one_byte& flags, const ek_salt& salt, const ek_entropy& entropy,
    const hash_digest& derived1, const hash_digest& derived2,
    const ec_secret& secret, uint8_t version)
{
    ec_compressed point;
    if (!secret_to_public(point, secret))
        return false;

    const auto prefix = parse_encrypted_public::prefix_factory(version);
    const auto hash = point_hash(point);

    auto encrypted1 = xor_data<half>(hash, derived1);
    aes256_encrypt(derived2, encrypted1);

    auto encrypted2 = xor_data<half>(hash, derived1, half);
    aes256_encrypt(derived2, encrypted2);

    const auto sign = point_sign(point.front(), derived2);
    return build_checked_array(out_public,
    {
        prefix,
        flags,
        salt,
        entropy,
        sign,
        encrypted1,
        encrypted2
    });
}

// There is no scenario requiring a public key, we support it for completeness.
bool create_key_pair(encrypted_private& out_private,
    encrypted_public& out_public, ec_compressed& out_point,
    const encrypted_token& token, const ek_seed& seed, uint8_t version,
    bool compressed)
{
    const parse_encrypted_token parse(token);
    if (!parse.valid())
        return false;

    const auto point = splice(parse.sign(), parse.data());
    auto point_copy = point;
    const auto factor = bitcoin_hash(seed);
    if (!ec_multiply(point_copy, factor))
        return false;

    ek_salt salt;
    if (!address_salt(salt, point_copy, version, compressed))
        return false;

    const auto salt_entropy = splice(salt, parse.entropy());
    const auto derived = split(scrypt_pair(point, salt_entropy));
    const auto flags = set_flags(compressed, parse.lot_sequence(), true);

    if (!create_public_key(out_public, flags, salt, parse.entropy(),
        derived.left, derived.right, factor, version))
        return false;

    create_private_key(out_private, flags, salt, parse.entropy(), derived.left,
        derived.right, seed, version);

    out_point = point_copy;
    return true;
}

bool create_key_pair(encrypted_private& out_private, ec_compressed& out_point,
    const encrypted_token& token, const ek_seed& seed, uint8_t version,
    bool compressed)
{
    encrypted_public out_public;
    return create_key_pair(out_private, out_public, out_point, token, seed,
        version, compressed);
}

#ifdef WITH_ICU

// create_token
// ----------------------------------------------------------------------------

// This call requires an ICU build, the other excluded calls are dependencies.
static data_chunk normal(const std::string& passphrase)
{
    return to_chunk(to_normal_nfc_form(passphrase));
}

static bool create_token(encrypted_token& out_token,
    const std::string& passphrase, const data_slice& owner_salt,
    const ek_entropy& owner_entropy,
    const byte_array<parse_encrypted_token::prefix_size>& prefix)
{
    BITCOIN_ASSERT(owner_salt.size() == ek_salt_size ||
        owner_salt.size() == ek_entropy_size);

    const auto lot_sequence = owner_salt.size() == ek_salt_size;
    auto factor = scrypt_token(normal(passphrase), owner_salt);

    if (lot_sequence)
        factor = bitcoin_hash(splice(factor, owner_entropy));

    ec_compressed point;
    if (!secret_to_public(point, factor))
        return false;

    return build_checked_array(out_token,
    {
        prefix,
        owner_entropy,
        point
    });
}

// The salt here is owner-supplied random bits, not the address hash.
bool create_token(encrypted_token& out_token, const std::string& passphrase,
    const ek_entropy& entropy)
{
    // BIP38: If lot and sequence numbers are not being included, then
    // owner_salt is 8 random bytes instead of 4, lot_sequence is omitted and
    // owner_entropy becomes an alias for owner_salt.
    const auto prefix = parse_encrypted_token::prefix_factory(false);
    return create_token(out_token, passphrase, entropy, entropy, prefix);
}

// The salt here is owner-supplied random bits, not the address hash.
bool create_token(encrypted_token& out_token, const std::string& passphrase,
    const ek_salt& salt, uint32_t lot, uint32_t sequence)
{
    if (lot > ek_max_lot || sequence > ek_max_sequence)
        return false;

    static constexpr size_t max_sequence_bits = 12;
    const uint32_t lot_sequence = (lot << max_sequence_bits) || sequence;
    const auto entropy = splice(salt, to_big_endian(lot_sequence));
    const auto prefix = parse_encrypted_token::prefix_factory(true);
    create_token(out_token, passphrase, salt, entropy, prefix);
    return true;
}

// encrypt
// ----------------------------------------------------------------------------

bool encrypt(encrypted_private& out_private, const ec_secret& secret,
    const std::string& passphrase, uint8_t version, bool compressed)
{
    ek_salt salt;
    if (!address_salt(salt, secret, version, compressed))
        return false;

    const auto derived = split(scrypt_private(normal(passphrase), salt));
    const auto prefix = parse_encrypted_private::prefix_factory(version,
        false);

    auto encrypted1 = xor_data<half>(secret, derived.left);
    aes256_encrypt(derived.right, encrypted1);

    auto encrypted2 = xor_data<half>(secret, derived.left, half);
    aes256_encrypt(derived.right, encrypted2);

    return build_checked_array(out_private,
    {
        prefix,
        set_flags(compressed),
        salt,
        encrypted1,
        encrypted2
    });
}

// decrypt private_key
// ----------------------------------------------------------------------------

static bool decrypt_multiplied(ec_secret& out_secret,
    const parse_encrypted_private& parse, const std::string& passphrase)
{
    auto secret = scrypt_token(normal(passphrase), parse.owner_salt());

    if (parse.lot_sequence())
        secret = bitcoin_hash(splice(secret, parse.entropy()));

    ec_compressed point;
    if (!secret_to_public(point, secret))
        return false;

    const auto salt_entropy = splice(parse.salt(), parse.entropy());
    const auto derived = split(scrypt_pair(point, salt_entropy));

    auto encrypt1 = parse.data1();
    auto encrypt2 = parse.data2();

    aes256_decrypt(derived.right, encrypt2);
    const auto decrypt2 = xor_data<half>(encrypt2, derived.left, 0, half);
    auto part = split(decrypt2);
    auto extended = splice(encrypt1, part.left);

    aes256_decrypt(derived.right, extended);
    const auto decrypt1 = xor_data<half>(extended, derived.left);
    const auto factor = bitcoin_hash(splice(decrypt1, part.right));
    if (!ec_multiply(secret, factor))
        return false;

    const auto compressed = parse.compressed();
    const auto address_version = parse.address_version();
    if (!address_validate(parse.salt(), secret, address_version, compressed))
        return false;

    out_secret = secret;
    return true;
}

static bool decrypt_secret(ec_secret& out_secret,
    const parse_encrypted_private& parse, const std::string& passphrase)
{
    auto encrypt1 = splice(parse.entropy(), parse.data1());
    auto encrypt2 = parse.data2();
    const auto derived = split(scrypt_private(normal(passphrase),
        parse.salt()));

    aes256_decrypt(derived.right, encrypt1);
    aes256_decrypt(derived.right, encrypt2);

    const auto encrypted = splice(encrypt1, encrypt2);
    const auto secret = xor_data<hash_size>(encrypted, derived.left);

    const auto compressed = parse.compressed();
    const auto address_version = parse.address_version();
    if (!address_validate(parse.salt(), secret, address_version, compressed))
        return false;

    out_secret = secret;
    return true;
}

bool decrypt(ec_secret& out_secret, uint8_t& out_version, bool& out_compressed,
    const encrypted_private& key, const std::string& passphrase)
{
    const parse_encrypted_private parse(key);
    if (!parse.valid())
        return false;

    const auto success = parse.multiplied() ?
        decrypt_multiplied(out_secret, parse, passphrase) :
        decrypt_secret(out_secret, parse, passphrase);

    if (success)
    {
        out_compressed = parse.compressed();
        out_version = parse.address_version();
    }

    return success;
}

// decrypt public_key
// ----------------------------------------------------------------------------

bool decrypt(ec_compressed& out_point, uint8_t& out_version,
    bool& out_compressed, const encrypted_public& key,
    const std::string& passphrase)
{
    const parse_encrypted_public parse(key);
    if (!parse.valid())
        return false;

    const auto version = parse.address_version();
    const auto lot_sequence = parse.lot_sequence();
    auto factor = scrypt_token(normal(passphrase), parse.owner_salt());

    if (lot_sequence)
        factor = bitcoin_hash(splice(factor, parse.entropy()));

    ec_compressed point;
    if (!secret_to_public(point, factor))
        return false;

    const auto salt_entropy = splice(parse.salt(), parse.entropy());
    auto derived = split(scrypt_pair(point, salt_entropy));
    auto encrypt = split(parse.data());

    aes256_decrypt(derived.right, encrypt.left);
    const auto decrypt1 = xor_data<half>(encrypt.left, derived.left);

    aes256_decrypt(derived.right, encrypt.right);
    const auto decrypt2 = xor_data<half>(encrypt.right, derived.left, 0, half);

    const auto sign_byte = point_sign(parse.sign(), derived.right);
    auto product = splice(sign_byte, decrypt1, decrypt2);
    if (!ec_multiply(product, factor))
        return false;

    if (!address_validate(parse.salt(), product, version, parse.compressed()))
        return false;

    out_point = product;
    out_version = version;
    out_compressed = parse.compressed();
    return true;
}

#endif // WITH_ICU

} // namespace wallet
} // namespace system
} // namespace libnuls

max_issues_repo_name: CCC-NULS/nuls-cplusplus-sdk

max_forks_repo_name: CCC-NULS/nuls-cplusplus-sdk


text:
// Shasta.
#include "ReadGraph.hpp"
#include "deduplicate.hpp"
#include "orderPairs.hpp"
using namespace shasta;

// Boost libraries.
#include <boost/pending/disjoint_sets.hpp>

// Standard library.
#include "fstream.hpp"
#include <map>
#include <queue>

const uint32_t ReadGraph::infiniteDistance = std::numeric_limits<uint32_t>::max();

void ReadGraph::unreserve() {
    if (edges.isOpenWithWriteAccess) {
        edges.unreserve();
    }
    if (connectivity.isOpenWithWriteAccess()) {
        connectivity.unreserve();
    }
}

void ReadGraph::remove()
{
    if (edges.isOpen) {
        edges.remove();
    }
    if (connectivity.isOpen()) {
        connectivity.remove();
    }

}

// The edges are stored with reverse complemented pairs at
// consecutive positions. That way, to get the reverse complement of
// an edge id we just reverse its lowest significant bit.
uint64_t ReadGraph::getReverseComplementEdgeId(uint64_t edgeId) const
{
    const uint64_t reverseComplementEdgeId = edgeId ^ 1ULL;

    // Sanity check.
    const ReadGraphEdge& edge = edges[edgeId];
    array<OrientedReadId, 2> orientedReadIds = edge.orientedReadIds;
    orientedReadIds[0].flipStrand();
    orientedReadIds[1].flipStrand();
    const ReadGraphEdge& reverseComplementEdge = edges[reverseComplementEdgeId];
    SHASTA_ASSERT(orientedReadIds == reverseComplementEdge.orientedReadIds);

    return reverseComplementEdgeId;
}

// Compute a shortest path, disregarding edges flagged as cross-strand edges.
void ReadGraph::computeShortPath(
    OrientedReadId orientedReadId0,
    OrientedReadId orientedReadId1,
    size_t maxDistance,

    // Edge ids of the shortest path starting at orientedReadId0 and
    // ending at orientedReadId1.
    vector<uint32_t>& path,

    // Work areas.
    vector<uint32_t>& distance, // One per vertex, equals infiniteDistance before and after.
    vector<OrientedReadId>& reachedVertices,   // For which distance is not infiniteDistance.
    vector<uint32_t>& parentEdges  // One per vertex
    )
{
    const bool debug = false;
    if(debug) {
        cout << "Looking for a shortest path between " << orientedReadId0 <<
            " " << orientedReadId1 << endl;
    }

    path.clear();

    // Initialize the BFS.
    std::queue<OrientedReadId> queuedVertices;
    queuedVertices.push(orientedReadId0);
    distance[orientedReadId0.getValue()] = 0;
    reachedVertices.clear();
    reachedVertices.push_back(orientedReadId0);

    // Do the BFS.
    while(!queuedVertices.empty()) {

        // Dequeue a vertex.
        const OrientedReadId vertex0 = queuedVertices.front();
        queuedVertices.pop();
        const uint32_t distance0 = distance[vertex0.getValue()];
        const uint32_t distance1 = distance0 + 1;
        if(debug) {
            cout << "Dequeued " << vertex0 << " at distance " << distance0 << endl;
        }

        // Loop over adjacent vertices.
        bool pathFound = false;
        for(const uint32_t edgeId: connectivity[vertex0.getValue()]) {
            const ReadGraphEdge& edge = edges[edgeId];
            if(edge.crossesStrands) {
                continue;
            }
            const OrientedReadId vertex1 = edge.getOther(vertex0);

            // If we did not encounter this vertex before, process it.
            if(distance[vertex1.getValue()] == infiniteDistance) {
                distance[vertex1.getValue()] = distance1;
                reachedVertices.push_back(vertex1);
                parentEdges[vertex1.getValue()] = edgeId;
                if(distance1 < maxDistance) {
                    if(debug) {
                        cout << "Enqueued " << vertex1 << endl;
                    }
                    queuedVertices.push(vertex1);
                }
            }

            // If we reached orientedReadId1, construct the path.
            if(vertex1 == orientedReadId1) {
                pathFound = true;
                // We have already cleared the path above.
                OrientedReadId vertex = vertex1;
                while(vertex != orientedReadId0) {
                    const uint32_t edgeId = parentEdges[vertex.getValue()];
                    path.push_back(edgeId);
                    vertex = edges[edgeId].getOther(vertex);
                }
                std::reverse(path.begin(), path.end());
                break;
            }

        }
        if(pathFound) {
            break;
        }

    }

    // Clean up.
    for(const OrientedReadId orientedReadId: reachedVertices) {
        distance[orientedReadId.getValue()] = infiniteDistance;
    }
    reachedVertices.clear();
}

// Find neighbors to distance 1.
// The neighbors are returned sorted and do not include orientedReadId0.
void ReadGraph::findNeighbors(
    OrientedReadId orientedReadId0,
    vector<OrientedReadId>& neighbors) const
{
    neighbors.clear();
    for(const uint32_t edgeId: connectivity[orientedReadId0.getValue()]) {
        const ReadGraphEdge& edge = edges[edgeId];
        const OrientedReadId orientedReadId1 = edge.getOther(orientedReadId0);
        neighbors.push_back(orientedReadId1);
    }
    sort(neighbors.begin(), neighbors.end());
}

// Find neighbors to specified maximum distance.
// The neighbors are returned sorted and do not include orientedReadId0.
void ReadGraph::findNeighbors(
    OrientedReadId orientedReadId,
    uint64_t maxDistance,
    vector<OrientedReadId>& neighbors) const
{
    // Initialize the BFS.
    std::queue<OrientedReadId> q;
    q.push(orientedReadId);
    std::map<OrientedReadId, uint64_t> distanceMap;
    distanceMap.insert(make_pair(orientedReadId, 0));

    // Do the BFS to the specified maximum distance.
    neighbors.clear();
    while(not q.empty()) {

        // Dequeue a vertex.
        const OrientedReadId orientedReadId0 = q.front();
        q.pop();
        const auto it0 = distanceMap.find(orientedReadId0);
        SHASTA_ASSERT(it0 != distanceMap.end());
        const uint64_t distance0 = it0->second;
        const uint64_t distance1 = distance0 + 1;
        SHASTA_ASSERT(distance1 <= maxDistance);

        // Loop over its neighbors.
        const span<const uint32_t> adjacentEdges = connectivity[orientedReadId0.getValue()];
        for(const uint32_t edgeId: adjacentEdges) {
            const ReadGraphEdge& edge = edges[edgeId];
            const OrientedReadId orientedReadId1 = edge.getOther(orientedReadId0);
            if(distanceMap.find(orientedReadId1) != distanceMap.end()) {
                // We already found orientedReadId1.
                continue;
            }
            neighbors.push_back(orientedReadId1);
            distanceMap.insert(make_pair(orientedReadId1, distance1));
            if(distance1 < maxDistance) {
                q.push(orientedReadId1);
            }
        }
    }

    // Sort the neighbors.
    sort(neighbors.begin(), neighbors.end());
}

// Find "bridges" from the read graph.
// Takes as input a vector<bool> that says, for each alignmentId,
// whether that alignment is used in the read graph.
// Updates that vector to set to false the entries corresponding
// to read graph "bridges".
void ReadGraph::findBridges(vector<bool>& keepAlignment, uint64_t maxDistance)
{

    // Vector to flag edges that will be removed.
    vector<bool> isToBeRemoved(edges.size(), false);

    // Work vectors to contain neighbors and
    // the corresponding edge ids.
    vector<OrientedReadId> neighbors;
    vector<uint32_t> neighborEdges;

    vector<uint64_t> rank;
    vector<uint64_t> parent;

    // Loop over reads. We only consider vertices corresponding
    // reads on strand 0, then for each edge to be removed
    // also flag its reverse complement.
    const uint32_t orientedReadCount = uint32_t(connectivity.size());
    SHASTA_ASSERT((orientedReadCount % 2) == 0);
    const uint32_t readCount = orientedReadCount / 2;
    for(ReadId readId0=0; readId0<readCount; readId0++) {
        const OrientedReadId orientedReadId0(readId0, 0);
        // cout << "Working on " << orientedReadId0 << endl;

        // Find neighbors within the specified distance.
        findNeighbors(orientedReadId0, maxDistance, neighbors);
        const uint64_t n = neighbors.size();
        if(n == 0) {
            continue;
        }

        /*
        cout << "Neighbors:" << endl;
        for(uint64_t i1=0; i1<n; i1++) {
            cout << i1 << " " << neighbors[i1] << endl;
        }
        */

        // Initialize the disjoint set data structure.
        rank.resize(n);
        parent.resize(n);
        boost::disjoint_sets<uint64_t*, uint64_t*> disjointSets(&rank[0], &parent[0]);
        for(uint64_t i=0; i<n; i++) {
            disjointSets.make_set(i);
        }

        // Compute connected components of the subgraph formed by the neighbors.
        for(uint64_t i1=0; i1<n; i1++) {
            const OrientedReadId orientedReadId1 = neighbors[i1];
            for(const uint32_t edgeId12: connectivity[orientedReadId1.getValue()]) {
                const ReadGraphEdge& edge12 = edges[edgeId12];
                const OrientedReadId orientedReadId2 = edge12.getOther(orientedReadId1);
                SHASTA_ASSERT(orientedReadId1 != orientedReadId2);

                // Only consider each edge once.
                if(orientedReadId2 < orientedReadId1) {
                    continue;
                }

                // Look up the other oriented read in our vector of neighbors.
                const auto it2 = lower_bound(neighbors.begin(), neighbors.end(), orientedReadId2);
                if((it2 == neighbors.end()) or (*it2 != orientedReadId2)) {
                    // Not a neighbor. Ignore.
                    continue;
                }
                SHASTA_ASSERT(*it2 == orientedReadId2);
                const uint64_t i2 = it2 - neighbors.begin();

                // Update our disjoint set data structure.
                // cout << "Updating: " << i1 << " " << i2 << endl;
                disjointSets.union_set(i1, i2);
            }
        }

        /*
        for(uint64_t i1=0; i1<n; i1++) {
            cout << i1 << " " << neighbors[i1] << " " << disjointSets.find_set(i1) << endl;
        }
        */

        // Gather connected components.
        vector< vector<uint64_t> > components(n);
        for(uint64_t i1=0; i1<n; i1++) {
            const uint64_t componentId = disjointSets.find_set(i1);
            components[componentId].push_back(i1);
        }

        // Sort them by size.
        vector<pair<uint64_t, uint64_t> > componentTable; // pair(componentId, size).
        for(uint64_t componentId=0; componentId<n;componentId++) {
            const auto& component = components[componentId];
            const uint64_t componentSize = component.size();
            if(componentSize > 0) {
                componentTable.push_back(make_pair(componentId, componentSize));
            }
        }
        sort(componentTable.begin(), componentTable.end(),
            OrderPairsBySecondOnlyGreater<uint64_t, uint64_t>());
        const uint64_t largestComponentId = componentTable.front().first;
        const vector<uint64_t>& largestComponent = components[largestComponentId];
        SHASTA_ASSERT(largestComponent.size() == componentTable.front().second);

        /*
        cout << "Largest component:" << endl;
        for(const uint64_t i1: largestComponent) {
            cout << i1 << " " << neighbors[i1] << endl;
        }
        */

        vector<bool> keep(n, false);
        for(const uint64_t i1: largestComponent) {
            keep[i1] = true;
        }

        /*
        for (uint64_t i1=0; i1<n; i1++) {
            if(not keep[i1]) {
                cout << "Remove " << orientedReadId0 << " " << neighbors[i1] << endl;
            }
        }
        */

        for (uint64_t i1=0; i1<n; i1++) {
            if(not keep[i1]) {
                const uint32_t edgeId = connectivity[orientedReadId0.getValue()][i1];
                const ReadGraphEdge& edge = edges[edgeId];
                keepAlignment[edge.alignmentId] = false;
            }
        }
    }

}

// Quick and dirty label propagation, without attempting to keep the clustering
// invariant under reverse complementing.
void ReadGraph::clustering(
    std::mt19937& randomSource,
    // The cluster that each vertex is assigned to.
    // Indexed by OrientedReadId::getValue().
    vector<ReadId>& cluster,
    bool debug) const
{
    // Initialize each vertex to its own cluster.
    const ReadId vertexCount = ReadId(connectivity.size());
    cluster.resize(vertexCount);
    for(ReadId i=0; i<vertexCount; i++) {
        cluster[i] = i;
    }

    // Random number generator.
    std::uniform_int_distribution<ReadId> uniformDistribution(0, vertexCount-1);

    // Iterate.
    const uint64_t sweepCount = 100;
    const uint64_t iterationCount = sweepCount * vertexCount;
    vector<ReadId> neighborLabels;
    vector<ReadId> labelFrequencies;
    for(uint64_t iteration=0; iteration<iterationCount; iteration++) {

        // Randomly pick a vertex to update.
        const ReadId vertexId0 = uniformDistribution(randomSource);
        const OrientedReadId orientedReadId0 = OrientedReadId::fromValue(vertexId0);

        // Get the clusters of its neighbors.
        neighborLabels.clear();
        for(const uint32_t edgeId: connectivity[vertexId0]) {
            const ReadGraphEdge& edge = edges[edgeId];
            const OrientedReadId orientedReadId1 = edge.getOther(orientedReadId0);
            const ReadId vertexId1 = orientedReadId1.getValue();
            const ReadId label1 = cluster[vertexId1];
            neighborLabels.push_back(label1);
        }

        if(neighborLabels.empty()) {
            continue;
        }

        // Count the occurrences of each label.
        deduplicateAndCount(neighborLabels, labelFrequencies);

        // Find the most frequent label.
        ReadId bestLabel = neighborLabels.front();
        ReadId bestLabelFrequency = labelFrequencies.front();
        for(uint64_t i=1; i<neighborLabels.size(); i++) {
            if(labelFrequencies[i] > bestLabelFrequency) {
                bestLabel = neighborLabels[i];
                bestLabelFrequency = labelFrequencies[i];
            }
        }

        // Assign to this vertex the most frequent cluster in its neighbors.
        cluster[vertexId0] = bestLabel;

    }

    if(not debug) {
        return;
    }

    // Summarize the clusters.
    std::map<ReadId, ReadId> clusterMap;    // (cluster, number of vertices)
    for(ReadId vertexId=0; vertexId<vertexCount; vertexId++) {
        const ReadId vertexCluster = cluster[vertexId];
        const auto it = clusterMap.find(vertexCluster);
        if(it == clusterMap.end()) {
            clusterMap.insert(make_pair(vertexCluster, 1));
        } else {
            ++(it->second);
        }
    }

    {
        ofstream csv("Clusters.csv");
        csv << "Cluster,Size\n";
        for(const auto& p: clusterMap) {
            csv << p.first << ",";
            csv << p.second << "\n";
        }
    }

    // Summarize edges by cluster.
    // Key: pair(cluster0, cluster1) with cluster0<=cluster1;
    // Value: number of edges.
    std::map< pair<ReadId, ReadId>, ReadId> edgeTable;
    for(const ReadGraphEdge& edge: edges) {
        const ReadId vertexId0 = edge.orientedReadIds[0].getValue();
        const ReadId vertexId1 = edge.orientedReadIds[1].getValue();
        ReadId cluster0 = cluster[vertexId0];
        ReadId cluster1 = cluster[vertexId1];
        if(cluster1 < cluster0) {
            swap(cluster0, cluster1);
        }
        const auto it = edgeTable.find(make_pair(cluster0, cluster1));
        if(it == edgeTable.end()) {
            edgeTable.insert(make_pair(make_pair(cluster0, cluster1), 1));
        } else {
            ++(it->second);
        }
    }

    {
        ofstream csv("EdgeByClusters.csv");
        csv << "Cluster0,Cluster1,Size0,Size1,Edges\n";
        for(const auto& p: edgeTable) {
            const ReadId cluster0 = p.first.first;
            const ReadId cluster1 = p.first.second;
            csv << cluster0 << ",";
            csv << cluster1 << ",";
            csv << clusterMap[cluster0] << ",";
            csv << clusterMap[cluster1] << ",";
            csv << p.second << "\n";
        }
    }

    ofstream graphOut("ReadGraph.dot");
    graphOut << "graph ReadGraph {\n"
        "tooltip=\" \"";
    for(ReadId vertexId=0; vertexId<vertexCount; vertexId++) {
        const OrientedReadId orientedReadId = OrientedReadId::fromValue(vertexId);
        const ReadId vertexLabel = cluster[vertexId];
        graphOut << "\"" << orientedReadId << "\"[" <<
            " tooltip=\"" << orientedReadId << " " << vertexLabel << "\""
            " color = \"" << 0.05 * (vertexLabel%20) << " 1 1\"];\n";
    }
    for(const ReadGraphEdge& edge: edges) {
        graphOut << "\"" << edge.orientedReadIds[0] << "\"--\"" <<
            edge.orientedReadIds[1] << "\"";
        /*
        const ReadId vertexId0 = edge.orientedReadIds[0].getValue();
        const ReadId vertexId1 = edge.orientedReadIds[1].getValue();
        const ReadId cluster0 = cluster[vertexId0];
        const ReadId cluster1 = cluster[vertexId1];
        if(cluster0 != cluster1) {
            graphOut << " [color=red]";
        }
        */
        graphOut << ";\n";
    }
    graphOut << "}\n";
}

ext: cpp

max_stars_repo_name: chanzuckerberg/shasta

max_issues_repo_name: rlorigro/shasta

max_forks_repo_name: chanzuckerberg/shasta


text:
/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You 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.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee --- Response Module
 *
 * @author Sam Baskinger <sbaskinger@qualys.com>
 */

#include <ironbee/path.h>

#include <ironbeepp/action.hpp>
#include <ironbeepp/configuration_parser.hpp>
#include <ironbeepp/module.hpp>
#include <ironbeepp/module_delegate.hpp>
#include <ironbeepp/module_bootstrap.hpp>
#include <ironbeepp/memory_manager.hpp>
#include <ironbeepp/transformation.hpp>

#ifdef __clang__
#pragma clang diagnostic push
#if __has_warning("-Wc++11-extensions")
#pragma clang diagnostic ignored "-Wc++11-extensions"
#endif
#if __has_warning("-Wunused-local-typedef")
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#endif
#endif
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>

#include <boost/iostreams/code_converter.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/iostreams/operations.hpp>
#include <boost/iostreams/read.hpp>

#ifdef __clang__
#pragma clang diagnostic pop
#endif

#include <ios>

namespace {

using namespace IronBee;

//! Config structure for response data.
struct ResponseContextData {

};

//! Tx structure for response data.
struct ResponseTxData {

};

//! The response action.
class ResponseAction {
public:
    ResponseAction(IronBee::Engine engine);
    static Action::action_instance_t generate(
        MemoryManager mm,
        Context       ctx,
        const char *  arg
    );

    /**
     * Implement this function object.
     */
    void operator()(const ib_rule_exec_t * rule_exec);
    void addHeader(const std::string& name, const std::string& value);
    void addHeader(const std::vector<std::string>& headers);
    void setStatus(int status);
    void setFile(const std::string& file);

    //! Get the status.
    int status() const;
    const std::string& file() const;

private:
    IronBee::Engine m_engine;
    int m_status;
    std::string m_file;
    ib_parsed_headers_t *m_headers;
};

ResponseAction::ResponseAction(IronBee::Engine engine)
:
    m_engine(engine)
{
    IronBee::throw_if_error(
        ib_parsed_headers_create(&m_headers, engine.main_memory_mm().ib())
    );
}

void ResponseAction::addHeader(
    const std::string& name,
    const std::string& value
)
{
    ib_log_debug(
        m_engine.ib(),
        "Adding header %.*s=%.*s.",
        static_cast<int>(name.length()),
        name.data(),
        static_cast<int>(value.length()),
        value.data()
    );

    IronBee::throw_if_error(
        ib_parsed_headers_add(
            m_headers,
            name.data(),
            name.length(),
            value.data(),
            value.length()
        )
    );
}

void ResponseAction::addHeader(const std::vector<std::string>& headers)
{
    assert(headers.size() == 2 && "Header must be length 2.");
    addHeader(headers[0], headers[1]);
}

int ResponseAction::status() const
{
    return m_status;
}

void ResponseAction::setStatus(int status)
{
    ib_log_debug(
        m_engine.ib(),
        "Setting status to %d.",
        status
    );
    m_status = status;
}

const std::string& ResponseAction::file() const
{
    return m_file;
}

void ResponseAction::setFile(const std::string& file)
{
    ib_log_debug(
        m_engine.ib(),
        "Setting response file to %s.",
        file.c_str()
    );

    ib_status_t rc;
    const ib_cfgparser_t *ib_cp;

    rc = ib_engine_cfgparser_get(m_engine.ib(), &ib_cp);
    if (rc == IB_OK) {
        IronBee::ConstConfigurationParser cp(ib_cp);

        m_file = ib_util_relative_file(
            ib_engine_mm_config_get(m_engine.ib()),
            cp.current_file(),
            file.c_str()
        );

        ib_log_debug(
            m_engine.ib(),
            "Response file set to relative file %s.", m_file.c_str()
        );
    }
    else {
        ib_log_error(
            m_engine.ib(),
            "Failed to get cfg parser. "
            "Cannot set relative path of error page."
        );
        m_file = file;
    }
}

class ResponseModuleDelegate : public ModuleDelegate
{
public:
    ResponseModuleDelegate(Module m);
private:
}; // end class ResponseModuleDelegate

Action::action_instance_t ResponseAction::generate(
    MemoryManager mm,
    Context       ctx,
    const char *  arg
)
{
    // Build a response action that will be populated by the parser.
    ResponseAction r(ctx.engine());

    namespace qi = boost::spirit::qi;
    namespace phoenix = boost::phoenix;

    const char *first = arg;
    const char *last  = first + strlen(arg);

    /* Parse a single comment. */
    bool parse_success = qi::phrase_parse(
        // Range to parse.
        first, last,

        // Begin grammar.
        // Parse the status.
        -qi::omit[qi::int_ [ phoenix::bind(&ResponseAction::setStatus, phoenix::ref(r), qi::_1)]]
        // Optionally parse the headers.
        >> -(
                qi::lit(",") >>
                (
                    (
                        qi::as_string[+(qi::char_ - ':')] >>
                        qi::omit[qi::lit(":")]            >>
                        qi::as_string[+(qi::char_ - ',')]

                    )
                    [
                        phoenix::bind(&ResponseAction::addHeader, phoenix::ref(r), qi::_1, qi::_2)
                    ]
                    % qi::lit(",")
                )
        )
        // Optionally parse the file.
        >> -(
            qi::lit(",") >>
            qi::as_string[+qi::char_][
                phoenix::bind(&ResponseAction::setFile, phoenix::ref(r), qi::_1)
            ]
        )
        ,
        // End grammar.

        // Skip parser.
        qi::space
    );

    /* If
     * (1) we fully matched
     * (2) parsed successfully
     */
    if (first == last && parse_success) {
        ib_log_debug(
            ctx.engine().ib(),
            "Built response with status %d and content from %s.",
            r.status(),
            r.file().c_str()
        );
        return r;
    }

    BOOST_THROW_EXCEPTION(
        IronBee::einval()
            << IronBee::errinfo_what(
                str(boost::format("Failed to parse argument: %s") % arg)
            )
    );
}

void ResponseAction::operator()(const ib_rule_exec_t * rule_exec)
{
    assert(rule_exec != NULL);
    assert(rule_exec->tx != NULL);

    ib_status_t rc;

    IronBee::MemoryManager mm = IronBee::MemoryManager(rule_exec->tx->mm);

    IronBee::ByteString page_bs;
    boost::iostreams::mapped_file_source page;

    try
    {
        // Throws an error if the file does not exist.
        page.open(m_file);

        if (page.is_open()) {
            page_bs =
                IronBee::ByteString::create_alias(mm, page.data(), page.size());
        }
        else {
            page_bs = IronBee::ByteString::create_alias(mm, "", 0);
        }
    }
    catch (const std::ios_base::failure& e)
    {
        ib_log_error_tx(
            rule_exec->tx,
            "Failed to read error page file %s: %s", m_file.c_str(), e.what()
        );
        page_bs = IronBee::ByteString::create(mm, "", 0);
    }

    rc = ib_tx_response(
        rule_exec->tx,
        m_status,
        m_headers,
        page_bs.ib()
    );
    if (rc != IB_OK) {
        ib_log_debug_tx(rule_exec->tx, "Failed to send custom response.");
    }

    // Close out here because we want the file to stay mapped until
    // the response is delivered.
    if (page.is_open()) {
        page.close();
    }

}

ResponseModuleDelegate::ResponseModuleDelegate(Module m)
:
ModuleDelegate(m)
{
    ResponseContextData config;
    m.set_configuration_data(config);
    MemoryManager mm = m.engine().main_memory_mm();

    // Action response =
    Action::create(
        mm,
        "response",
        boost::bind(ResponseAction::generate, _1, _2, _3)
    ).register_with(m.engine());
}

} // Anonymous Namespace

IBPP_BOOTSTRAP_MODULE_DELEGATE("response", ResponseModuleDelegate);

max_issues_repo_name: ErikHendriks/ironbee

max_forks_repo_name: ErikHendriks/ironbee


text:
/* *****************************************************************************
Copyright (c) 2015-2017, The Regents of the University of California (Regents).
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. 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.

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.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.

REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS
PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

*************************************************************************** */

// Written: Minjie Zhu

#include "PythonAnalysisBuilder.h"
#include <elementAPI.h>
#include <Domain.h>
#include <FileStream.h>
#include <string>
#include <ID.h>
#include <Element.h>
#include <ElementIter.h>
#include <Node.h>
#include <NodeIter.h>

#include <EquiSolnAlgo.h>
#include <StaticIntegrator.h>
#include <TransientIntegrator.h>
#include <LinearSOE.h>
#include <StaticAnalysis.h>
#include <DirectIntegrationAnalysis.h>
#include <VariableTimeStepDirectIntegrationAnalysis.h>
#include <PFEMAnalysis.h>
#include <DOF_Numberer.h>
#include <ConstraintHandler.h>
#include <ConvergenceTest.h>
#include <AnalysisModel.h>
#include <NewtonRaphson.h>
#include <PlainHandler.h>
#include <RCM.h>
#include <LoadControl.h>
#include <ProfileSPDLinSolver.h>
#include <CTestNormUnbalance.h>
#include <ProfileSPDLinDirectSolver.h>
#include <TransformationConstraintHandler.h>
#include <CTestPFEM.h>
#include <PFEMIntegrator.h>
#include <PFEMLinSOE.h>
#include <PFEMSolver.h>
#include <UniaxialMaterial.h>
#include <SectionForceDeformation.h>
#include <SectionRepres.h>
#include <TimeSeries.h>
#include <NDMaterial.h>
#include <LoadPattern.h>
#include <CrdTransf.h>
#include <BeamIntegration.h>
#include <Newmark.h>
#include <EigenSOE.h>
#include <SymBandEigenSolver.h>
#include <SymBandEigenSOE.h>
#include <FullGenEigenSolver.h>
#include <FullGenEigenSOE.h>
#include <ArpackSOE.h>
#include <iostream>
#include <ProfileSPDLinSOE.h>

PythonAnalysisBuilder::PythonAnalysisBuilder()
:theHandler(0),theNumberer(0),theAnalysisModel(0),theAlgorithm(0),
 theSOE(0),theEigenSOE(0),theStaticIntegrator(0),theTransientIntegrator(0),
 theTest(0),theStaticAnalysis(0),theTransientAnalysis(0),
 theVariableTimeStepTransientAnalysis(0),thePFEMAnalysis(0)
{
}

PythonAnalysisBuilder::~PythonAnalysisBuilder()
{
    this->wipe();
    this->resetAll();
}

void PythonAnalysisBuilder::wipe()
{
    if(theStaticAnalysis != 0) {
	theStaticAnalysis->clearAll();
	delete theStaticAnalysis;
	theStaticAnalysis = 0;
    }
    if(theTransientAnalysis != 0) {
	theTransientAnalysis->clearAll();
	delete theTransientAnalysis;
	theTransientAnalysis = 0;
    }
    theVariableTimeStepTransientAnalysis = 0;
    thePFEMAnalysis = 0;

}

void PythonAnalysisBuilder::resetStatic()
{
    theAlgorithm = 0;
    theStaticIntegrator = 0;
    theSOE = 0;
    theNumberer = 0;
    theHandler = 0;
    theTest = 0;
    theAnalysisModel = 0;
}

void PythonAnalysisBuilder::resetTransient()
{
    theAlgorithm = 0;
    theTransientIntegrator = 0;
    theSOE = 0;
    theNumberer = 0;
    theHandler = 0;
    theTest = 0;
    theAnalysisModel = 0;
}

void PythonAnalysisBuilder::resetAll()
{
    theAlgorithm = 0;
    theStaticIntegrator = 0;
    theTransientIntegrator = 0;
    theSOE = 0;
    theNumberer = 0;
    theHandler = 0;
    theTest = 0;
    theAnalysisModel = 0;
    theEigenSOE = 0;
}

void PythonAnalysisBuilder::set(ConstraintHandler* obj) {
    if(obj == 0) return;
    if(theHandler != 0) {
	opserr<<"The handler can only be set once\n";
	return;
    }
    theHandler = obj;
}

void PythonAnalysisBuilder::set(DOF_Numberer* obj) {
    if(obj == 0) return;
    if(theNumberer != 0) {
	opserr<<"The numberer can only be set once for one analysis\n";
	return;
    }
    theNumberer = obj;
    if(theStaticAnalysis != 0) theStaticAnalysis->setNumberer(*obj);
    if(theTransientAnalysis != 0) theTransientAnalysis->setNumberer(*obj);
}

void PythonAnalysisBuilder::set(EquiSolnAlgo* obj) {
    if(obj == 0) return;
    if(theAlgorithm != 0) {
	opserr<<"The algorithm can only be set once for one analysis\n";
	return;
    }
    theAlgorithm = obj;
    if(theStaticAnalysis != 0) theStaticAnalysis->setAlgorithm(*obj);
    if(theTransientAnalysis != 0) theTransientAnalysis->setAlgorithm(*obj);
}

void PythonAnalysisBuilder::set(LinearSOE* obj) {
    if(obj == 0) return;
    if(theSOE != 0) {
	opserr<<"The SOE can only be set once for one analysis\n";
	return;
    }
    theSOE = obj;
    if(theStaticAnalysis != 0) theStaticAnalysis->setLinearSOE(*obj);
    if(theTransientAnalysis != 0) theTransientAnalysis->setLinearSOE(*obj);
}

void PythonAnalysisBuilder::set(Integrator* obj, int isstatic) {
    if(obj == 0) return;
    if(isstatic == 1) {
	if(theStaticIntegrator != 0) {
	    opserr<<"The static integrator can only be set once for one analysis\n";
	    return;
	}
	theStaticIntegrator = dynamic_cast<StaticIntegrator*>(obj);
	if(theStaticIntegrator != 0) {
	    if(theStaticAnalysis != 0) {
		theStaticAnalysis->setIntegrator(*theStaticIntegrator);
		return;
	    }
	}
    }
    if(isstatic == 2) {
	if(theTransientIntegrator != 0) {
	    opserr<<"The transient integrator can only be set once for one analysis\n";
	    return;
	}
	theTransientIntegrator = dynamic_cast<TransientIntegrator*>(obj);
	if(theTransientIntegrator!=0) {
	    if(theTransientAnalysis != 0) {
		theTransientAnalysis->setIntegrator(*theTransientIntegrator);
		return;
	    }
	}
    }
}

void PythonAnalysisBuilder::set(ConvergenceTest* obj) {
    if(obj == 0) return;
    if(theTest != 0) {
	opserr<<"The test can only be set once for one analysis\n";
	return;
    }
    theTest = obj;
    if(theStaticAnalysis != 0) theStaticAnalysis->setConvergenceTest(*obj);
    if(theTransientAnalysis != 0) theTransientAnalysis->setConvergenceTest(*obj);
}

void PythonAnalysisBuilder::newStaticAnalysis()
{
    this->wipe();

    if(theAnalysisModel == 0) {
	theAnalysisModel = new AnalysisModel();
    }

    if(theTest == 0) {
	theTest = new CTestNormUnbalance(1.0e-6,25,0);
    }

    if(theAlgorithm == 0) {
	opserr << "WARNING analysis Static - no Algorithm yet specified, \n";
	opserr << " NewtonRaphson default will be used\n";
	theAlgorithm = new NewtonRaphson(*theTest);
    }
    if(theHandler == 0) {
	opserr << "WARNING analysis Static - no ConstraintHandler yet specified, \n";
	opserr << " PlainHandler default will be used\n";
	theHandler = new PlainHandler();
    }
    if(theNumberer == 0) {
	opserr << "WARNING analysis Static - no Numberer specified, \n";
	opserr << " RCM default will be used\n";
	RCM *theRCM = new RCM(false);
	theNumberer = new DOF_Numberer(*theRCM);
    }
    if(theStaticIntegrator == 0) {
	opserr << "WARNING analysis Static - no Integrator specified, \n";
	opserr << " StaticIntegrator default will be used\n";
	theStaticIntegrator = new LoadControl(1, 1, 1, 1);
    }
    if(theSOE == 0) {
	opserr << "WARNING analysis Static - no LinearSOE specified, \n";
	opserr << " ProfileSPDLinSOE default will be used\n";
	ProfileSPDLinSolver *theSolver;
	theSolver = new ProfileSPDLinDirectSolver();
	theSOE = new ProfileSPDLinSOE(*theSolver);
    }

    Domain* theDomain = OPS_GetDomain();
    theStaticAnalysis = new StaticAnalysis(*theDomain,*theHandler,*theNumberer,*theAnalysisModel,
					   *theAlgorithm,*theSOE,*theStaticIntegrator,theTest);

    // set eigen SOE
    if(theEigenSOE != 0) {
	theStaticAnalysis->setEigenSOE(*theEigenSOE);
    }

    this->resetStatic();
}

void PythonAnalysisBuilder::newTransientAnalysis()
{
    this->wipe();

    if(theAnalysisModel == 0) {
	theAnalysisModel = new AnalysisModel();
    }
    if(theTest == 0) {
	theTest = new CTestNormUnbalance(1.0e-6,25,0);
    }
    if(theAlgorithm == 0) {
	opserr << "WARNING analysis Transient - no Algorithm yet specified, \n";
	opserr << " NewtonRaphson default will be used\n";

	theAlgorithm = new NewtonRaphson(*theTest);
    }
    if(theHandler == 0) {
	opserr << "WARNING analysis Transient dt tFinal - no ConstraintHandler\n";
	opserr << " yet specified, PlainHandler default will be used\n";
	theHandler = new PlainHandler();
    }
    if(theNumberer == 0) {
	opserr << "WARNING analysis Transient dt tFinal - no Numberer specified, \n";
	opserr << " RCM default will be used\n";
	RCM *theRCM = new RCM(false);
	theNumberer = new DOF_Numberer(*theRCM);
    }
    if(theTransientIntegrator == 0) {
	opserr << "WARNING analysis Transient dt tFinal - no Integrator specified, \n";
	opserr << " Newmark(.5,.25) default will be used\n";
	theTransientIntegrator = new Newmark(0.5,0.25);
    }
    if(theSOE == 0) {
	opserr << "WARNING analysis Transient dt tFinal - no LinearSOE specified, \n";
	opserr << " ProfileSPDLinSOE default will be used\n";
	ProfileSPDLinSolver *theSolver;
	theSolver = new ProfileSPDLinDirectSolver();
	theSOE = new ProfileSPDLinSOE(*theSolver);
    }

    Domain* theDomain = OPS_GetDomain();
    theTransientAnalysis=new DirectIntegrationAnalysis(*theDomain,*theHandler,*theNumberer,
						       *theAnalysisModel,*theAlgorithm,
						       *theSOE,*theTransientIntegrator,
						       theTest);

    // set eigen SOE
    if(theEigenSOE != 0) {
	if(theTransientAnalysis != 0) {
	  theTransientAnalysis->setEigenSOE(*theEigenSOE);
	}
    }

    this->resetTransient();
}

void PythonAnalysisBuilder::newPFEMAnalysis(double dtmax, double dtmin, double ratio)
{
    this->wipe();

    if(theAnalysisModel == 0) {
	theAnalysisModel = new AnalysisModel();
    }

    if(theTest == 0) {
	theTest = new CTestPFEM(1e-6,1e-6,1e-6,1e-6,1e-6,1e-6,10000,100,1,2);
    }

    if(theAlgorithm == 0) {
	opserr << "WARNING analysis PFEM - no Algorithm yet specified, \n";
	opserr << " NewtonRaphson default will be used\n";
	theAlgorithm = new NewtonRaphson(*theTest);
    }
    if(theHandler == 0) {
	opserr << "WARNING analysis PFEM - no ConstraintHandler yet specified, \n";
	opserr << " Transformation default will be used\n";
	theHandler = new TransformationConstraintHandler();
    }
    if(theNumberer == 0) {
	opserr << "WARNING analysis PFEM - no Numberer specified, \n";
	opserr << " RCM default will be used\n";
	RCM *theRCM = new RCM(false);
	theNumberer = new DOF_Numberer(*theRCM);
    }
    if(theTransientIntegrator == 0) {
	opserr << "WARNING analysis PFEM - no Integrator specified, \n";
	opserr << " PFEMIntegrator default will be used\n";
	theTransientIntegrator = new PFEMIntegrator();
    }
    if(theSOE == 0) {
	opserr << "WARNING analysis PFEM - no LinearSOE specified, \n";
	opserr << " PFEMLinSOE default will be used\n";
	PFEMSolver* theSolver = new PFEMSolver();
	theSOE = new PFEMLinSOE(*theSolver);
    }

    Domain* theDomain = OPS_GetDomain();
    thePFEMAnalysis = new PFEMAnalysis(*theDomain,
				       *theHandler,
				       *theNumberer,
				       *theAnalysisModel,
				       *theAlgorithm,
				       *theSOE,
				       *theTransientIntegrator,
				       theTest,dtmax,dtmin,ratio);

    theTransientAnalysis = thePFEMAnalysis;

    // set eigen SOE
    if(theEigenSOE != 0) {
	if(theTransientAnalysis != 0) {
	    theTransientAnalysis->setEigenSOE(*theEigenSOE);
	}
    }

    this->resetTransient();
}

void PythonAnalysisBuilder::newEigenAnalysis(int typeSolver, double shift)
{
    // create a new eigen system and solver
    if(theEigenSOE != 0) {
	if(theEigenSOE->getClassTag() != typeSolver) {
	    //	delete theEigenSOE;
	    theEigenSOE = 0;
	}
    }

    if(theEigenSOE == 0) {

	if(typeSolver == EigenSOE_TAGS_SymBandEigenSOE) {
	    SymBandEigenSolver *theEigenSolver = new SymBandEigenSolver();
	    theEigenSOE = new SymBandEigenSOE(*theEigenSolver, *theAnalysisModel);

	} else if(typeSolver == EigenSOE_TAGS_FullGenEigenSOE) {

	    FullGenEigenSolver *theEigenSolver = new FullGenEigenSolver();
	    theEigenSOE = new FullGenEigenSOE(*theEigenSolver, *theAnalysisModel);

	} else {
	    theEigenSOE = new ArpackSOE(shift);
	}

	//
	// set the eigen soe in the system
	//

	if(theStaticAnalysis != 0) {
	    theStaticAnalysis->setEigenSOE(*theEigenSOE);
	} else if(theTransientAnalysis != 0) {
	    theTransientAnalysis->setEigenSOE(*theEigenSOE);
	}
    } // theEigenSOE != 0
}

EquiSolnAlgo* PythonAnalysisBuilder::getAlgorithm()
{
    if(theStaticAnalysis != 0) {
	return theStaticAnalysis->getAlgorithm();
    } else if(theTransientAnalysis != 0) {
	return theTransientAnalysis->getAlgorithm();
    }

    return 0;
}

StaticIntegrator* PythonAnalysisBuilder::getStaticIntegrator() {
    if(theStaticAnalysis != 0) {
	return theStaticAnalysis->getIntegrator();
    }
    return 0;
}

TransientIntegrator* PythonAnalysisBuilder::getTransientIntegrator() {
    if(theTransientAnalysis != 0) {
	return theTransientAnalysis->getIntegrator();
    }
    return 0;
}

ConvergenceTest* PythonAnalysisBuilder::getConvergenceTest()
{
    if(theStaticAnalysis != 0) {
	return theStaticAnalysis->getConvergenceTest();
    } else if(theTransientAnalysis != 0) {
	return theTransientAnalysis->getConvergenceTest();
    }

    return 0;
}

static PythonAnalysisBuilder anaBuilder;

extern "C" void OPS_ResetCommandLine(int nArgs, int cArg, PyObject *args);
extern LinearSOE* OPS_ParseSOECommand(const char *type);
extern DOF_Numberer* OPS_ParseNumbererCommand(const char *type);
extern ConstraintHandler* OPS_ParseConstraintHandlerCommand(const char *type);
extern EquiSolnAlgo* OPS_ParseAlgorithmCommand(const char *type);
extern Integrator* OPS_ParseIntegratorCommand(const char *type, int& isstatic);
extern ConvergenceTest* OPS_ParseCTestCommand(const char *type);

static int ops_printEle(OPS_Stream &output, PyObject *args);
static int ops_printNode(OPS_Stream &output, PyObject *args);
static int ops_printAlgo(OPS_Stream &output, PyObject *args);
static int ops_printInteg(OPS_Stream &output, PyObject *args);

PyObject *ops_printModel(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    // file stream
    FileStream outputFile;
    OPS_Stream *output = &opserr;

    // domain
    Domain& theDomain = *(OPS_GetDomain());

    // just printModel()
    int numData = OPS_GetNumRemainingInputArgs();
    if(numData == 0) {
	opserr << theDomain;
	Py_INCREF(Py_None);
	return Py_None;
    }

    // printModel()
    int res = 0;
    while(numData > 0) {
	std::string type = OPS_GetString();
	if(type=="-ele" || type=="ele") {
	    res = ops_printEle(*output,args);
	    break;
	} else if(type=="-node" || type=="node") {
	    res = ops_printNode(*output,args);
	    break;
	} else if(type=="-integrator" || type=="integrator") {
	    res = ops_printInteg(*output,args);
	    break;
	} else if(type=="-algorithm" || type=="algorithm") {
	    res = ops_printAlgo(*output,args);
	    break;
	} else {
	    // open file
	    if(type=="-file" || type=="file") {
		type = OPS_GetString();
		numData = OPS_GetNumRemainingInputArgs();
	    }
	    if(outputFile.setFile(type.c_str(), APPEND) != 0) {
		PyErr_SetString(PyExc_RuntimeError,"failed to open file ");
		return NULL;
	    }

	    // just print(filename)
	    if(numData == 0) {
		outputFile << theDomain;
		Py_INCREF(Py_None);
		return Py_None;
	    }
	    output = &outputFile;
	}
    }

    if(res < 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to print ");
	return NULL;
    }

    // close the output file
    outputFile.close();

    Py_INCREF(Py_None);
    return Py_None;
}

int ops_printEle(OPS_Stream &output, PyObject *args)
{
    int flag = 0;

    Domain& theDomain = *(OPS_GetDomain());

    // just print(<filename>, 'ele')
    if(OPS_GetNumRemainingInputArgs() == 0) {
	ElementIter &theElements = theDomain.getElements();
	Element *theElement;
	while ((theElement = theElements()) != 0) {
	    theElement->Print(output);
	}
	return 0;
    }

    // if 'print <filename> Element flag int <int int ..>' get the flag
    std::string type = OPS_GetString();
    if(type=="flag" || type=="-flag") {
	if(OPS_GetNumRemainingInputArgs() < 1) {
	    opserr << "WARNING printModel(<filename>, 'ele', <'flag', int> no int specified \n";
	    return -1;
	}
	int numData = 1;
	if(OPS_GetIntInput(&numData,&flag) < 0) return -1;
    } else {
	int numData = OPS_GetNumRemainingInputArgs();
	int numArgs = PyTuple_Size(args);
	OPS_ResetCommandLine(numArgs, numArgs-numData-1, args);
    }

    // now print the Elements with the specified flag, 0 by default
    int numEle = OPS_GetNumRemainingInputArgs();
    if(numEle == 0) {
	ElementIter &theElements = theDomain.getElements();
	Element *theElement;
	while ((theElement = theElements()) != 0) {
	    theElement->Print(output, flag);
	}
	return 0;
    } else {

	// otherwise print out the specified nodes i j k .. with flag
	ID theEle(numEle);
	if(OPS_GetIntInput(&numEle, &theEle(0)) < 0) return -1;
	theDomain.Print(output, 0, &theEle, flag);
    }

    return 0;
}

int ops_printNode(OPS_Stream &output, PyObject *args)
{
    int flag = 0;

    Domain& theDomain = *(OPS_GetDomain());

    // just print(<filename>, 'node')
    if(OPS_GetNumRemainingInputArgs() == 0) {
	NodeIter &theNodes = theDomain.getNodes();
	Node *theNode;
	while((theNode = theNodes()) != 0) {
	    theNode->Print(output);
	}
	return 0;
    }

    // if 'print <filename> node flag int <int int ..>' get the flag
    std::string type = OPS_GetString();
    if(type=="flag" || type=="-flag") {
	if(OPS_GetNumRemainingInputArgs() < 1) {
	    opserr << "WARNING printModel(<filename>, 'ele', <'flag', int> no int specified \n";
	    return -1;
	}
	int numData = 1;
	if(OPS_GetIntInput(&numData,&flag) < 0) return -1;
    } else {
	int numData = OPS_GetNumRemainingInputArgs();
	int numArgs = PyTuple_Size(args);
	OPS_ResetCommandLine(numArgs, numArgs-numData-1, args);
    }

    // now print the nodes with the specified flag, 0 by default
    int numNode = OPS_GetNumRemainingInputArgs();
    if(numNode == 0) {
	NodeIter &theNodes = theDomain.getNodes();
	Node *theNode;
	while ((theNode = theNodes()) != 0) {
	    theNode->Print(output, flag);
	}
	return 0;
    } else {

	// otherwise print out the specified nodes i j k .. with flag
	ID theNode(numNode);
	if(OPS_GetIntInput(&numNode, &theNode(0)) < 0) return -1;
	theDomain.Print(output, &theNode, 0, flag);
    }

    return 0;
}

int ops_printAlgo(OPS_Stream &output, PyObject *args)
{
    EquiSolnAlgo* theAlgorithm = anaBuilder.getAlgorithm();
    if(theAlgorithm == 0) return 0;

    // if just 'print <filename> algorithm'- no flag
    if(OPS_GetNumRemainingInputArgs() == 0) {
	theAlgorithm->Print(output);
	return 0;
    }

    // if 'print <filename> Algorithm flag' get the flag
    int flag;
    int numData = 1;
    if(OPS_GetIntInput(&numData, &flag) < 0) return -1;
    theAlgorithm->Print(output,flag);

    return 0;
}

int ops_printInteg(OPS_Stream &output, PyObject *args)
{
    StaticIntegrator* theStaticIntegrator=anaBuilder.getStaticIntegrator();
    TransientIntegrator* theTransientIntegrator=anaBuilder.getTransientIntegrator();

    if(theStaticIntegrator == 0 && theTransientIntegrator==0)
	return 0;

    IncrementalIntegrator *theIntegrator;
    if (theStaticIntegrator != 0)
	theIntegrator = theStaticIntegrator;
    else
	theIntegrator = theTransientIntegrator;

    // if just 'print <filename> algorithm'- no flag
    if(OPS_GetNumRemainingInputArgs() == 0) {
	theIntegrator->Print(output);
	return 0;
    }

    // if 'print <filename> Algorithm flag' get the flag
    int flag;
    int numData = 1;
    if(OPS_GetIntInput(&numData, &flag) < 0) return -1;
    theIntegrator->Print(output,flag);

    return 0;
}

PyObject *ops_wipeAnalysis(PyObject *self, PyObject *args)
{
    anaBuilder.wipe();
    anaBuilder.resetAll();

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_wipeModel(PyObject *self, PyObject *args)
{
    anaBuilder.wipe();
    anaBuilder.resetAll();

    // wipe domain
    Domain* theDomain = OPS_GetDomain();
    theDomain->clearAll();

    // wipe uniaxial material
    OPS_clearAllUniaxialMaterial();
    OPS_clearAllNDMaterial();

    // wipe sections
    OPS_clearAllSectionForceDeformation();
    OPS_clearAllSectionRepres();

    // wipe time series
    OPS_clearAllTimeSeries();

    // wipe GeomTransf
    OPS_ClearAllCrdTransf();

    // wipe BeamIntegration
    OPS_clearAllBeamIntegrationRule();

    ops_Dt = 0.0;

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_specifySOE(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    const char *type = OPS_GetString();
    LinearSOE* theSOE = OPS_ParseSOECommand(type);

    if(theSOE != 0) {
	anaBuilder.set(theSOE);
    } else {
	PyErr_SetString(PyExc_RuntimeError,"failed to create SOE ");
	return NULL;
    }

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_specifyNumberer(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    const char *type = OPS_GetString();
    DOF_Numberer* theNumberer = OPS_ParseNumbererCommand(type);

    if(theNumberer == 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to create Numberer ");
	return NULL;
    }

    anaBuilder.set(theNumberer);

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_specifyConstraintHandler(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    const char *type = OPS_GetString();
    ConstraintHandler* theHandler = OPS_ParseConstraintHandlerCommand(type);

    if(theHandler == 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to create ConstraintHandler ");
	return NULL;
    }

    anaBuilder.set(theHandler);

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_specifyAlgorithm(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    const char *type = OPS_GetString();
    EquiSolnAlgo* theAlgorithm = OPS_ParseAlgorithmCommand(type);

    if(theAlgorithm == 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to create Algorithm ");
	return NULL;
    }

    anaBuilder.set(theAlgorithm);

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_specifyIntegrator(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    const char *type = OPS_GetString();
    int isstatic = -1;
    Integrator* integ = OPS_ParseIntegratorCommand(type,isstatic);

    if(integ == 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to create Integrator ");
	return NULL;
    }

    anaBuilder.set(integ,isstatic);

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_specifyAnalysis(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    if(OPS_GetNumRemainingInputArgs() < 1) {
	PyErr_SetString(PyExc_RuntimeError,"must specify analysis name ");
	return NULL;
    }

    // analysis type
    std::string type = OPS_GetString();

    // create analysis
    if(type == "Static") {
	anaBuilder.newStaticAnalysis();
    } else if(type == "Transient") {
	anaBuilder.newTransientAnalysis();
    } else if(type == "PFEM") {
	int numData = OPS_GetNumRemainingInputArgs();
	if(numData < 2) {
	    PyErr_SetString(PyExc_RuntimeError,"must specify dtmax and dtmin for PFEM analysis");
	    return NULL;
	}

	double data[3] = {0,0,0.5};
	if(numData > 3) numData = 3;
	if(OPS_GetDoubleInput(&numData,&data[0]) < 0) return 0;

	anaBuilder.newPFEMAnalysis(data[0],data[1],data[2]);
    }

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_specifyCTest(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    const char *type = OPS_GetString();
    ConvergenceTest* theTest = OPS_ParseCTestCommand(type);

    if(theTest == 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to create ConvergenceTest ");
	return NULL;
    }

    anaBuilder.set(theTest);

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_analyzeModel(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    int result = 0;

    StaticAnalysis* theStaticAnalysis = anaBuilder.getStaticAnalysis();
    DirectIntegrationAnalysis* theTransientAnalysis = anaBuilder.getTransientAnalysis();
    PFEMAnalysis* thePFEMAnalysis = anaBuilder.getPFEMAnalysis();
    VariableTimeStepDirectIntegrationAnalysis* theVariableTimeStepTransientAnalysis =
	anaBuilder.getVariableTimeStepDirectIntegrationAnalysis();

    if(theStaticAnalysis != 0) {
	// static analysis
	if(OPS_GetNumRemainingInputArgs() < 1) {
	    PyErr_SetString(PyExc_RuntimeError,"must set numStep");
	    return NULL;
	}

	// get step
	int numStep;
	int numData = 1;
	if(OPS_GetIntInput(&numData,&numStep) < 0) return NULL;
	result = theStaticAnalysis->analyze(numStep);

    } else if(thePFEMAnalysis != 0) {
	// PFEM analysis
	result = thePFEMAnalysis->analyze();

    } else if(theTransientAnalysis != 0) {
	// transient analysis
	if(OPS_GetNumRemainingInputArgs() < 2) {
	    PyErr_SetString(PyExc_RuntimeError,"must set numStep and dT");
	    return NULL;
	}
	// get step
	int numStep;
	int numData = 1;
	if(OPS_GetIntInput(&numData,&numStep) < 0) return NULL;

	// get dT
	double dT;
	numData = 1;
	if(OPS_GetDoubleInput(&numData,&dT) < 0) return NULL;

	// set global time step variable
	ops_Dt = dT;

	// variable transient analysis
	if(OPS_GetNumRemainingInputArgs() > 3) {
	    // get dtmin and dtmax
	    double dtm[2] = {0,0};
	    numData = 2;
	    if(OPS_GetDoubleInput(&numData,&dtm[0]) < 0) return NULL;

	    // get Jd
	    int Jd;
	    numData = 1;
	    if(OPS_GetIntInput(&numData,&Jd) < 0) return NULL;

	    if(theVariableTimeStepTransientAnalysis != 0) {
		result = theVariableTimeStepTransientAnalysis
		    ->analyze(numData, dT, dtm[0], dtm[1], Jd);
	    } else {
		PyErr_SetString(PyExc_RuntimeError,"no variable time step transient \
analysis object constructed");
		return NULL;
	    }
	} else {
	    result = theTransientAnalysis->analyze(numStep, dT);
	}
    } else {
	PyErr_SetString(PyExc_RuntimeError,"no Analysis type has been specified");
	return NULL;
    }

    if(result < 0) {
	PyErr_SetString(PyExc_RuntimeError,"OpenSees > analyze failed,");
	opserr << "returned: " << result << " error flag\n";
	return NULL;
    }

    return Py_BuildValue("d", result);
}

PyObject *ops_nodeDisp(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    int numData = OPS_GetNumRemainingInputArgs();
    if(numData < 1) {
	PyErr_SetString(PyExc_RuntimeError,"WARNING want - nodeDisp nodeTag? <dof?>");
	return NULL;
    }

    // get inputs
    int data[2] = {0,0};
    if(OPS_GetIntInput(&numData,&data[0]) < 0) return NULL;
    data[1]--;

    // get nodal response
    Domain& theDomain = *(OPS_GetDomain());
    const Vector *nodalResponse = theDomain.getNodeResponse(data[0], Disp);
    if(nodalResponse == 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to get nodal response");
	return NULL;
    }

    // get disp
    int size = nodalResponse->Size();
    if(data[1] >= 0) {
	if(data[1] >= size) {
	    PyErr_SetString(PyExc_RuntimeError,
			    "WARNING nodeDisp nodeTag? dof? - dofTag? too large\n");
	    return NULL;
	}
	double value = (*nodalResponse)(data[1]);
	return Py_BuildValue("d", value);
    }

    // get list
    PyObject* theList = PyList_New(0);
    if(theList == 0) {
	PyErr_SetString(PyExc_RuntimeError,"failed to create disp list");
	return NULL;
    }

    for(int i=0; i<size; i++) {
	if(PyList_Append(theList,Py_BuildValue("d",(*nodalResponse)(i))) < 0) {
	    PyErr_SetString(PyExc_RuntimeError,"failed to create disp list");
	    return NULL;
	}
    }

    return theList;
}

PyObject *ops_getLoadFactor(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    int numData = OPS_GetNumRemainingInputArgs();
    if(numData < 1) {
	PyErr_SetString(PyExc_RuntimeError,"want patternTag");
	return NULL;
    }

    // get inputs
    int patternTag;
    numData = 1;
    if(OPS_GetIntInput(&numData,&patternTag) < 0) return NULL;

    // get load pattern
    Domain& theDomain = *(OPS_GetDomain());
    LoadPattern* thePattern = theDomain.getLoadPattern(patternTag);
    if(thePattern == 0) {
	PyErr_SetString(PyExc_RuntimeError,"the load pattern is not found");
	return NULL;
    }

    // get load factor
    double value = thePattern->getLoadFactor();
    return Py_BuildValue("d", value);
}

PyObject *ops_setLoadConst(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    int numData = OPS_GetNumRemainingInputArgs();
    if(numData < 2) {
	Py_INCREF(Py_None);
	return Py_None;
    }

    Domain* theDomain = OPS_GetDomain();
    theDomain->setLoadConstant();

    std::string type = OPS_GetString();

    if(type == "-time") {
	double newTime;
	numData = 1;
	if(OPS_GetDoubleInput(&numData,&newTime) < 0) return NULL;
	theDomain->setCurrentTime(newTime);
	theDomain->setCommittedTime(newTime);
    }
    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_rayleighDamping(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    // check inputs
    if(OPS_GetNumRemainingInputArgs() < 4) {
	PyErr_SetString(PyExc_RuntimeError,"ERROR rayleigh(alphaM,betaK,betaK0,betaKc)");
	return NULL;
    }

    // get parameters
    double data[4];
    int numData = 4;
    if(OPS_GetDoubleInput(&numData,&data[0]) < 0) return 0;

    Domain* theDomain = OPS_GetDomain();
    theDomain->setRayleighDampingFactors(data[0],data[1],data[2],data[3]);

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject *ops_eigenAnalysis(PyObject *self, PyObject *args)
{
    OPS_ResetCommandLine(PyTuple_Size(args), 0, args);

    // check inputs
    int numArgs = OPS_GetNumRemainingInputArgs();
    if(numArgs < 1) {
	PyErr_SetString(PyExc_RuntimeError,"ERROR eigen('type',numModes)");
	return NULL;
    }

    // get parameters
    bool generalizedAlgo = true;// 0 - frequency/generalized (default),1 - standard, 2 - buckling
    int typeSolver = EigenSOE_TAGS_ArpackSOE;
    double shift = 0.0;
    bool findSmallest = true;
    int numEigen = 0;

    // check type of eigenvalue analysis
    if(numArgs >1) {
	std::string type = OPS_GetString();
	if(type=="frequency"||type=="-frenquency"||type=="generalized"||type=="-generalized") {
	    generalizedAlgo = true;
	} else if(type=="standard"||type=="-standard") {
	    generalizedAlgo = false;
	} else if(type=="-findLargest") {
	    findSmallest = false;
	} else if(type=="genBandArpack"||type=="--genBandArpack"||
		  type=="genBandArpackEigen"||type=="-genBandArpackEigen") {
	    typeSolver = EigenSOE_TAGS_ArpackSOE;
	} else if(type=="symmBandLapack"||type=="-symmBandLapack"||
		  type=="symmBandLapackEigen"||type=="-symmBandLapackEigen") {
	    typeSolver = EigenSOE_TAGS_SymBandEigenSOE;
	} else if(type=="fullGenLapack"||type=="-fullGenLapack"||
		  type=="fullGenLapackEigen"||type=="-fullGenLapackEigen") {
	    typeSolver = EigenSOE_TAGS_FullGenEigenSOE;
	} else {
	    PyErr_SetString(PyExc_RuntimeError,"eigen - unknown option specified");
	    return NULL;
	}
    }

    int numData = 1;
    if(OPS_GetIntInput(&numData,&numEigen) < 0) return NULL;

    anaBuilder.newEigenAnalysis(typeSolver,shift);

    // create a transient analysis if no analysis exists
    Domain* theDomain = OPS_GetDomain();

    StaticAnalysis* theStaticAnalysis = anaBuilder.getStaticAnalysis();
    DirectIntegrationAnalysis* theTransientAnalysis = anaBuilder.getTransientAnalysis();
    if(theStaticAnalysis == 0 && theTransientAnalysis == 0) {
	anaBuilder.newTransientAnalysis();
    }

    // call analysis
    int res = 0;
    if(theStaticAnalysis != 0) {
	res = theStaticAnalysis->eigen(numEigen,generalizedAlgo,findSmallest);
    } else if(theTransientAnalysis != 0) {
	res = theTransientAnalysis->eigen(numEigen,generalizedAlgo,findSmallest);
    }

    // return
    PyObject* theList = PyList_New(0);
    if(res == 0) {
	const Vector& eigenvalues = theDomain->getEigenvalues();
	// get list
	if(theList == 0) {
	    PyErr_SetString(PyExc_RuntimeError,"failed to create disp list");
	    return NULL;
	}

	for(int i=0; i<numEigen; i++) {
	    if(PyList_Append(theList,Py_BuildValue("d",eigenvalues(i))) < 0) {
		PyErr_SetString(PyExc_RuntimeError,"failed to create disp list");
		return NULL;
	    }
	}
    }

    return theList;

}

max_stars_repo_name: kuanshi/ductile-fracture


text:
#include "stdafx.h"
#include "session.client.h"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/null_sink.h>
#include <boost/asio/bind_executor.hpp>
#include <boost/beast/http/read.hpp>
#include <boost/beast/http/write.hpp>
#include <fmt/ostream.h>

namespace net::client
{
    namespace http = boost::beast::http;

    auto make_logger = core::console_logger_factory("net.client.session", true);

    session<protocal::http>::session(socket_type&& socket,
                                     boost::asio::io_context& context)
        : session_base{ std::move(socket), context }
        , request_sequence_{ context_.get_executor() } {
        assert(socket_.is_open());
        std::tie(core::as_mutable(index_),
                 core::as_mutable(logger_)) = make_logger();
        core::as_mutable(identity_) = fmt::format("session${}", index_);
        core::as_mutable(tracer_) = spdlog::create<spdlog::sinks::null_sink_st>(identity_);
#ifdef NDEBUG
        logger_().set_level(spdlog::level::warn);
#endif
        logger_().info("constructor socket endpoint client {} server {}", socket_.local_endpoint(), socket_.remote_endpoint());
        reserve_recvbuf_capacity();
    }

    auto session<protocal::http>::create(socket_type&& socket,
                                         boost::asio::io_context& context) -> pointer {
        return std::make_unique<session<protocal::http>>(std::move(socket), context);
    }

    void session<protocal::http>::emplace_response_parser() {
        response_parser_.emplace()
                        .body_limit(std::numeric_limits<uint64_t>::max());
    }

    auto session<protocal::http>::on_recv_response(int64_t index) {
        return [=](boost::system::error_code errc,
                   std::size_t transfer_size) mutable {
            assert(request_sequence_.running_in_this_thread());
            logger_().info("on_recv_response errc {} transfer {}", errc, transfer_size);
            if (errc) {
                logger_().error("on_recv_response failure");
                return fail_request_then_close(
                    core::bad_response_error{} << core::errinfo_code{ errc },
                    errc, boost::asio::socket_base::shutdown_receive);
            }
            if (response_parser_->get().result() != http::status::ok) {
                logger_().error("on_recv_response bad response");
                return fail_request_then_close(
                    core::bad_response_error{} << core::errinfo_message{
                        response_parser_->get().reason().to_string()
                    },
                    errc, boost::asio::socket_base::shutdown_receive);
            }
            tracer_->info("response=recv:index={}:transfer={}", index, transfer_size);
            request_list_.front().second.setValue(response_parser_->release());
            request_list_.pop_front();
            if (!request_list_.empty()) {
                send_front_request();
            }
        };
    }

    auto session<protocal::http>::on_send_request(int64_t index) {
        return [=](boost::system::error_code errc,
                   std::size_t transfer_size) mutable {
            assert(request_sequence_.running_in_this_thread());
            logger_().info("on_send_request errc {} transfer {}", errc, transfer_size);
            if (errc) {
                logger_().error("on_send_request failure");
                return fail_request_then_close(
                    core::bad_request_error{} << core::errinfo_code{ errc },
                    errc, boost::asio::socket_base::shutdown_send);
            }
            tracer_->info("request=send:index={}:transfer={}", index, transfer_size);
            http::async_read(socket_, recvbuf_, *response_parser_,
                             boost::asio::bind_executor(request_sequence_, on_recv_response(index)));
        };
    }

    void session<protocal::http>::send_front_request() {
        assert(request_sequence_.running_in_this_thread());
        emplace_response_parser();
        auto request_index = ++round_index_;
        tracer_->info("request=ready:index={}", request_index);
        http::async_write(socket_, request_list_.front().first,
                          boost::asio::bind_executor(request_sequence_, on_send_request(request_index)));
    }

    void session<protocal::http>::trace_by(spdlog::sink_ptr sink) const {
        spdlog::drop(identity_);
        core::as_mutable(tracer_) = core::make_async_logger(identity_, std::move(sink));
    }

    auto session<protocal::http>::send_request(request<empty_body>&& request)
    -> folly::SemiFuture<response<dynamic_body>> {
        logger_().info("send_request empty body");
        auto [promise, future] = folly::makePromiseContract<response<dynamic_body>>();
        boost::asio::post(
            request_sequence_,
            [this, request = std::move(request), response = std::move(promise)]() mutable {
                auto request_target = request.target().to_string();
                if (active_) {
                    request_list_.emplace_back(std::move(request), std::move(response));
                    if (request_list_.size() == 1) {
                        send_front_request();
                    }
                } else {
                    response.setException(core::session_closed_error{});
                }
            });
        return std::move(future);
    }
}

max_stars_repo_name: metaplus/Gallery

max_issues_repo_name: metaplus/Gallery

max_forks_repo_name: metaplus/Gallery


text:
/*
Copyright Rene Rivera 2011-2017
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#include <boost/predef/version_number.h>
#define BOOST_STRICT_CONFIG
#include <boost/predef/other/workaround.h>

int main()
{
#if BOOST_PREDEF_WORKAROUND(BOOST_VERSION_NUMBER_AVAILABLE,==,0,0,1)
    fail();
#endif
    return 0;
}


text:
/**
 * \file   magic_number.cpp
 * \author Mike Roup <roup1@llnl.gov>
 * \date   July 8, 2013
 */

#include <iostream>

#include <boost/foreach.hpp>
#include <boost/regex.hpp>

#include "rose.h"
#include "compass2/compass.h"
#include "AstMatching.h"

using std::string;
using namespace rose::StringUtility;

extern const Compass::Checker* const magicNumberChecker;

/*-----------------------------------------------------------------------------
 * Interface
 *---------------------------------------------------------------------------*/

#ifndef COMPASS_MAGIC_NUMBER_H
#define COMPASS_MAGIC_NUMBER_H

namespace CompassAnalyses
{
/**
 * \brief Description of checker
 */
namespace MagicNumber
{
  extern const string checker_name;
  extern const string short_description;
  extern const string long_description;
  extern       string source_directory;

  /**
   * \brief Specificaiton of checker results.
   */
  class CheckerOutput: public Compass::OutputViolationBase {
   public:
    explicit CheckerOutput(SgNode *const node);

   private:
    DISALLOW_COPY_AND_ASSIGN(CheckerOutput);
  };

  bool IsNodeNotInUserLocation(const SgNode* node)
  {
      const SgLocatedNode* located_node = isSgLocatedNode(node);
      if (located_node != NULL)
      {
          return ! Compass::IsNodeInUserLocation(
                      located_node,
                      MagicNumber::source_directory);
      }
      else
      {
          return true;
      }
  };

} // ::CompassAnalyses
} // ::MagicNumber
#endif // COMPASS_MAGIC_NUMBER_H

/*-----------------------------------------------------------------------------
 * Implementation
 *---------------------------------------------------------------------------*/

namespace CompassAnalyses
{
 namespace MagicNumber
 {
  const string checker_name      = "MagicNumber";
  const string short_description = "Magic number found";
  const string long_description  = "Looks for floating point or integer constants that are not in init expressions.";
  string source_directory = "/";
 }
}

CompassAnalyses::MagicNumber::
CheckerOutput::CheckerOutput(SgNode *const node)
    : OutputViolationBase(node,
                          ::magicNumberChecker->checkerName,
                          ::magicNumberChecker->shortDescription) {}

static void
run(Compass::Parameters parameters, Compass::OutputObject* output)
  {
    typedef std::map<string, string> ExpectedValuesMap;
    ExpectedValuesMap magic_;
      // We only care about source code in the user's space, not,
      // for example, Boost or system files.
      string target_directory =
          parameters["general::target_directory"].front();
      CompassAnalyses::MagicNumber::source_directory.assign(target_directory);

      Compass::ParametersMap things = parameters[boost::regex("^magicNumbers::.*$")];
      BOOST_FOREACH(const Compass::ParametersMap::value_type& pair, things)
	{
	  Compass::ParameterValues values = pair.second;
	  BOOST_FOREACH(string keyword, values)
	    {
	      magic_[keyword] = keyword;
	    }
	}

      // Use the pre-built ROSE AST
      SgProject* sageProject = Compass::projectPrerequisite.getProject();

      // perform AST matching here
      AstMatching match_val_exps;
      MatchResult val_exps_result = match_val_exps.performMatching("$r = SgIntVal | $r = SgDoubleVal", sageProject);
      BOOST_FOREACH(SingleMatchVarBindings match, val_exps_result)
	{
	  SgValueExp* val = (SgValueExp*)match["$r"];
	  if (val->get_originalExpressionTree() == NULL)
	    {
	      SgNode* p = val->get_parent();
	      while (isSgExpression(p) && !isSgInitializer(p))
		{
		  p = p->get_parent();
		}
	      if (!isSgInitializer(p) || isSgConstructorInitializer(p))
		{
		  string number = val->get_constant_folded_value_as_string();
		  if (magic_[number] == "")
		    {
		      output->addOutput(new CompassAnalyses::MagicNumber::CheckerOutput(val));
		    }
		}
	    }
	}
  }

// Remove this function if your checker is not an AST traversal
static Compass::AstSimpleProcessingWithRunFunction*
createTraversal(Compass::Parameters params, Compass::OutputObject* output)
  {
    return NULL;
  }

extern const Compass::Checker* const magicNumberChecker =
  new Compass::CheckerUsingAstSimpleProcessing(
      CompassAnalyses::MagicNumber::checker_name,
    // Descriptions should not include the newline character "\n".
      CompassAnalyses::MagicNumber::short_description,
      CompassAnalyses::MagicNumber::long_description,
      Compass::C | Compass::Cpp,
      Compass::PrerequisiteList(1, &Compass::projectPrerequisite),
      run,
      createTraversal);


text:
/**
 * \file SimpleOverdriveFilter.cpp
 */

#include "SimpleOverdriveFilter.h"

#include <boost/math/special_functions/sign.hpp>

#include <ATK/Utility/ScalarNewtonRaphson.h>

namespace ATK
{
  template<typename DataType_>
  class SimpleOverdriveFilter<DataType_>::SimpleOverdriveFunction
  {
  public:
    typedef DataType_ DataType;
  protected:
    DataType A;
    DataType B;
    DataType is;
    DataType vt;

    DataType oldy0;
    DataType oldexpy0;
    DataType oldinvexpy0;
    DataType oldy1;
    DataType oldexpy1;
    DataType oldinvexpy1;
  public:
    SimpleOverdriveFunction(DataType dt, DataType R, DataType C, DataType is, DataType vt)
    :is(is), vt(vt)
    {
      A = dt / (2 * C) + R;
      B = dt / (2 * C) - R;

      oldy0 = oldy1 = 0;
      oldexpy0 = oldinvexpy0 = oldexpy1 = oldinvexpy1 = 1;
    }

    std::pair<DataType, DataType> operator()(const DataType* ATK_RESTRICT input, DataType* ATK_RESTRICT output, DataType y1)
    {
      auto x0 = input[-1];
      auto x1 = input[0];
      auto y0 = output[-1];
      DataType expdiode_y1_p = std::exp(y1 / vt);
      DataType expdiode_y1_m = 1 / expdiode_y1_p;
      DataType expdiode_y0_p;
      DataType expdiode_y0_m;

	    if(y0 == oldy0)
	    {
	      expdiode_y0_p = oldexpy0;
	      expdiode_y0_m = oldinvexpy0;
	    }
	    else if(y0 == oldy1)
	    {
	      expdiode_y0_p = oldexpy1;
	      expdiode_y0_m = oldinvexpy1;
	    }
	    else
	    {
	      expdiode_y0_p = std::exp(y0 / vt);
	      expdiode_y0_m = 1 / expdiode_y0_p;
	    }

      oldy0 = y0;
      oldexpy0 = expdiode_y0_p;
      oldinvexpy0 = expdiode_y0_m;

      oldy1 = y1;
      oldexpy1 = expdiode_y1_p;
      oldinvexpy1 = expdiode_y1_m;

      std::pair<DataType, DataType> diode = std::make_pair(is * (expdiode_y1_p - expdiode_y1_m), is * (expdiode_y1_p + expdiode_y1_m) / vt);
      return std::make_pair(A * diode.first + y1 + x0 - x1 + B * is * (expdiode_y0_p - expdiode_y0_m) - y0, A * diode.second + 1);
    }

    DataType estimate(const DataType* ATK_RESTRICT input, DataType* ATK_RESTRICT output)
    {
      auto x0 = input[-1];
      auto x1 = input[0];
      auto y0 = output[-1];
      return affine_estimate(x0, x1, y0);
    }

    DataType id_estimate(DataType x0, DataType x1, DataType y0)
    {
      return y0;
    }

    DataType linear_estimate(DataType x0, DataType x1, DataType y0)
    {
      if(y0 == 0)
        return 0;
      auto sinh = (oldexpy1 - oldinvexpy1);
      return y0 * (x1 - x0 + y0 - is * sinh * B) / (is * sinh * A + y0);
    }

    DataType affine_estimate(DataType x0, DataType x1, DataType y0)
    {
      auto sinh = (oldexpy1 - oldinvexpy1);
      auto cosh = (oldexpy1 + oldinvexpy1);
      return (x1 - x0 + y0 - is * sinh * B - (sinh - y0 / vt * cosh) * is * A) / (is * cosh * A / vt + 1);
    }
  };

  template <typename DataType>
  SimpleOverdriveFilter<DataType>::SimpleOverdriveFilter()
  :TypedBaseFilter<DataType>(1, 1)
  {
    input_delay = 1;
    output_delay = 1;
  }

  template <typename DataType>
  SimpleOverdriveFilter<DataType>::~SimpleOverdriveFilter()
  {
  }

  template <typename DataType>
  void SimpleOverdriveFilter<DataType>::setup()
  {
    Parent::setup();
    optimizer.reset(new ScalarNewtonRaphson<SimpleOverdriveFunction>(SimpleOverdriveFunction(static_cast<DataType>(1. / input_sampling_rate),
      10000, static_cast<DataType>(22e-9), static_cast<DataType>(1e-12), static_cast<DataType>(26e-3))));
  }

  template <typename DataType>
  void SimpleOverdriveFilter<DataType>::process_impl(int64_t size) const
  {
    const DataType* ATK_RESTRICT input = converted_inputs[0];
    DataType* ATK_RESTRICT output = outputs[0];
    for(int64_t i = 0; i < size; ++i)
    {
      optimizer->optimize(input + i, output + i);
    }
  }

  template class SimpleOverdriveFilter<float>;
  template class SimpleOverdriveFilter<double>;

  template<typename DataType_>
  class BackwardSimpleOverdriveFilter<DataType_>::SimpleOverdriveFunction
  {
  public:
    typedef DataType_ DataType;
  protected:
    DataType A;
    DataType B;
    DataType is;
    DataType vt;

    DataType oldy0;
    DataType oldexpy0;
    DataType oldinvexpy0;
    DataType oldy1;
    DataType oldexpy1;
    DataType oldinvexpy1;
  public:
    SimpleOverdriveFunction(DataType dt, DataType R, DataType C, DataType is, DataType vt)
    :is(is), vt(vt)
    {
      A = dt / C + R;
      B = - R;

      oldy0 = oldy1 = 0;
      oldexpy0 = oldinvexpy0 = oldexpy1 = oldinvexpy1 = 1;
    }

    std::pair<DataType, DataType> operator()(const DataType* ATK_RESTRICT input, DataType* ATK_RESTRICT output, DataType y1)
    {
      auto x0 = input[-1];
      auto x1 = input[0];
      auto y0 = output[-1];
      DataType expdiode_y1_p = std::exp(y1 / vt);
      DataType expdiode_y1_m = 1 / expdiode_y1_p;
      DataType expdiode_y0_p;
      DataType expdiode_y0_m;

      if(y0 == oldy0)
      {
        expdiode_y0_p = oldexpy0;
        expdiode_y0_m = oldinvexpy0;
      }
      else if(y0 == oldy1)
      {
        expdiode_y0_p = oldexpy1;
        expdiode_y0_m = oldinvexpy1;
      }
      else
      {
        expdiode_y0_p = std::exp(y0 / vt);
        expdiode_y0_m = 1 / expdiode_y0_p;
      }

      oldy0 = y0;
      oldexpy0 = expdiode_y0_p;
      oldinvexpy0 = expdiode_y0_m;

      oldy1 = y1;
      oldexpy1 = expdiode_y1_p;
      oldinvexpy1 = expdiode_y1_m;

      std::pair<DataType, DataType> diode = std::make_pair(is * (expdiode_y1_p - expdiode_y1_m), is * (expdiode_y1_p + expdiode_y1_m) / vt);
      return std::make_pair(A * diode.first + (y1 + (x0 - x1 + B * is * (expdiode_y0_p - expdiode_y0_m) - y0)), A * diode.second + 1);
    }

    DataType estimate(const DataType* ATK_RESTRICT input, DataType* ATK_RESTRICT output)
    {
      auto x0 = input[-1];
      auto x1 = input[0];
      auto y0 = output[-1];
      return affine_estimate(x0, x1, y0);
    }

    DataType id_estimate(DataType x0, DataType x1, DataType y0)
    {
      return y0;
    }

    DataType linear_estimate(DataType x0, DataType x1, DataType y0)
    {
      if(y0 == 0)
        return 0;
      auto exp = std::exp(y0 / vt);
      auto sinh = (exp - 1/exp);
      return y0 * (x1 - x0 + y0 - is * sinh * B) / (is * sinh * A + y0);
    }

    DataType affine_estimate(DataType x0, DataType x1, DataType y0)
    {
      auto exp = std::exp(y0 / vt);
      auto sinh = (exp - 1/exp);
      auto cosh = (exp + 1/exp);
      return (x1 - x0 + y0 - is * sinh * B - (sinh - y0 / vt * cosh) * is * A) / (is * cosh * A / vt + 1);
    }
  };

  template <typename DataType>
  BackwardSimpleOverdriveFilter<DataType>::BackwardSimpleOverdriveFilter()
  :TypedBaseFilter<DataType>(1, 1)
  {
    input_delay = 1;
    output_delay = 1;
  }

  template <typename DataType>
  BackwardSimpleOverdriveFilter<DataType>::~BackwardSimpleOverdriveFilter()
  {
  }

  template <typename DataType>
  void BackwardSimpleOverdriveFilter<DataType>::setup()
  {
    Parent::setup();
    optimizer.reset(new ScalarNewtonRaphson<SimpleOverdriveFunction>(SimpleOverdriveFunction(static_cast<DataType>(1. / input_sampling_rate),
                                                                                10000, static_cast<DataType>(22e-9), static_cast<DataType>(1e-12), static_cast<DataType>(26e-3))));
  }

  template <typename DataType>
  void BackwardSimpleOverdriveFilter<DataType>::process_impl(int64_t size) const
  {
    const DataType* ATK_RESTRICT input = converted_inputs[0];
    DataType* ATK_RESTRICT output = outputs[0];
    for(int64_t i = 0; i < size; ++i)
    {
      optimizer->optimize(input + i, output + i);
    }
  }

  template class BackwardSimpleOverdriveFilter<float>;
  template class BackwardSimpleOverdriveFilter<double>;

  template <typename DataType>
  ForwardSimpleOverdriveFilter<DataType>::ForwardSimpleOverdriveFilter()
  :TypedBaseFilter<DataType>(1, 1)
  {
    input_delay = 1;
    output_delay = 1;
  }

  template <typename DataType>
  ForwardSimpleOverdriveFilter<DataType>::~ForwardSimpleOverdriveFilter()
  {
  }

  template <typename DataType>
  void ForwardSimpleOverdriveFilter<DataType>::setup()
  {
    Parent::setup();
  }

  template <typename DataType>
  void ForwardSimpleOverdriveFilter<DataType>::process_impl(int64_t size) const
  {
    DataType dt = static_cast<DataType>(1. / input_sampling_rate);
    DataType R = 10000;
    DataType C = static_cast<DataType>(22e-9);
    DataType is = static_cast<DataType>(1e-12);
    DataType vt = static_cast<DataType>(26e-3);

    const DataType* ATK_RESTRICT input = converted_inputs[0];
    DataType* ATK_RESTRICT output = outputs[0];
    for(int64_t i = 0; i < size; ++i)
    {
      output[i] = output[i-1] + (input[i] - input[i-1] - (4 * dt * is * C * sinh(output[i-1] / vt))) / (1 + 2 * is * R * vt * cosh(output[i-1] / vt));
    }
  }

  template class ForwardSimpleOverdriveFilter<float>;
  template class ForwardSimpleOverdriveFilter<double>;

}