<commit_before>#include <iostream>
#include <unordered_set>
#include <vg/io/stream.hpp>
#include "chunker.hpp"
#include "algorithms/subgraph.hpp"

namespace vg {

using namespace std;

PathChunker::PathChunker(const PathPositionHandleGraph* graph) : graph(graph) {

}

PathChunker::~PathChunker() {

}

void PathChunker::extract_subgraph(const Region& region, int context, int length, bool forward_only,
                                   VG& subgraph, Region& out_region) {
    // extract our path range into the graph
    path_handle_t path_handle = graph->get_path_handle(region.seq);
    step_handle_t start_step = graph->get_step_at_position(path_handle, region.start);
    handle_t start_handle = graph->get_handle_of_step(start_step);
    step_handle_t end_step = graph->get_step_at_position(path_handle, region.end);
    handle_t end_handle = graph->get_handle_of_step(end_step);

    step_handle_t end_plus_one_step = graph->has_next_step(end_step) ? graph->get_next_step(end_step) : graph->path_end(path_handle) ;
    for (step_handle_t step = start_step; step != end_plus_one_step; step = graph->get_next_step(step)) {
        handle_t step_handle = graph->get_handle_of_step(step);
        if (graph->get_is_reverse(step_handle)) {
            step_handle = graph->flip(step_handle);
        }
        if (!subgraph.has_node(graph->get_id(step_handle))) {
            subgraph.create_handle(graph->get_sequence(step_handle), graph->get_id(step_handle));
        }
    };
    // expand the context and get path information
    // if forward_only true, then we only go forward.
    if (context > 0) {
        algorithms::expand_subgraph_by_steps(*graph, subgraph, context, forward_only);
    }
    if (length > 0) {
        algorithms::expand_subgraph_by_length(*graph, subgraph, context, forward_only);
    }
    else if (context == 0 && length == 0) {
        algorithms::add_connecting_edges_to_subgraph(*graph, subgraph);
    }
    algorithms::add_subpaths_to_subgraph(*graph, subgraph);

    // build the vg of the subgraph
    subgraph.remove_orphan_edges();

    // get our range endpoints before context expansion
    list<mapping_t>& mappings = subgraph.paths.get_path(region.seq);
    assert(!mappings.empty());
    size_t mappings_size = mappings.size();
    int64_t input_start_node = graph->get_id(start_handle);
    int64_t input_end_node = graph->get_id(end_handle);

    // replaces old xg position_in_path() to check node counts in path
    function<vector<step_handle_t>(const PathHandleGraph&, handle_t, path_handle_t)> path_steps_of_handle =
        [] (const PathHandleGraph& graph, handle_t handle, path_handle_t path_handle) {
        vector<step_handle_t> node_steps = graph.steps_of_handle(handle);
        vector<step_handle_t> node_path_steps;
        for (auto step : node_steps) {
            if (graph.get_path_handle_of_step(step) == path_handle) {
                node_path_steps.push_back(step);
            }
        }
        return node_path_steps;
    };

    // we have no direct way of getting our steps out of the subgraph, so we
    // go through node ids.  the problem is that cycles can introduce
    // ambiguity.  we check for that here (only to punt on it later)
    vector<step_handle_t> start_node_path_steps = path_steps_of_handle(*graph, start_handle, path_handle);
    vector<step_handle_t> end_node_path_steps = path_steps_of_handle(*graph, end_handle, path_handle);
    bool end_points_on_cycle = start_node_path_steps.size() > 1 || end_node_path_steps.size() > 1;

    // keep track of the edges in our original path
    set<pair<pair<id_t, bool>, pair<id_t, bool>>> path_edge_set =
        get_path_edge_index(start_step, end_step, std::max(context, length));

    // the distance between them and the nodes in our input range
    size_t left_padding = 0;
    size_t right_padding = 0;
    // do we need to rewrite back to our graph?
    bool rewrite_paths = false;

    if (!end_points_on_cycle) {
        // start and end of our expanded chunk
        auto start_it = mappings.begin();
        auto end_it = --mappings.end();

        // find our input range in the expanded path. we know these nodes only appear once.
        for (; start_it != mappings.end() && start_it->node_id() != input_start_node; ++start_it);
        for (; end_it != mappings.begin() && end_it->node_id() != input_end_node; --end_it);

        // walk back our start point as we can without rank discontinuities. doesn't matter
        // if we encounter cycles here, because we keep a running path length
        auto cur_it = start_it;
        auto prev_it = cur_it;
        if (prev_it != mappings.begin()) {
            for (; prev_it != mappings.begin(); --prev_it) {
                cur_it = prev_it;
                --cur_it;
                handle_t  prev_handle = subgraph.get_handle(prev_it->node_id(),
                                                            prev_it->is_reverse());
                handle_t cur_handle = subgraph.get_handle(cur_it->node_id(),
                                                          cur_it->is_reverse());
                edge_t edge = subgraph.edge_handle(cur_handle, prev_handle);
                if (!path_edge_set.count(make_pair(make_pair(subgraph.get_id(edge.first), subgraph.get_is_reverse(edge.first)),
                                                   make_pair(subgraph.get_id(edge.second), subgraph.get_is_reverse(edge.second))))) {
                    break;
                }
                left_padding += cur_it->length;
            }
        }
        start_it = prev_it;
        // walk forward the end point
        cur_it = end_it;
        prev_it = cur_it;
        for (++cur_it; cur_it != mappings.end(); ++prev_it, ++cur_it) {
            handle_t  prev_handle = subgraph.get_handle(prev_it->node_id(),
                                                        prev_it->is_reverse());
            handle_t cur_handle = subgraph.get_handle(cur_it->node_id(),
                                                      cur_it->is_reverse());
            edge_t edge = subgraph.edge_handle(prev_handle, cur_handle);
            if (!path_edge_set.count(make_pair(make_pair(subgraph.get_id(edge.first), subgraph.get_is_reverse(edge.first)),
                                               make_pair(subgraph.get_id(edge.second), subgraph.get_is_reverse(edge.second))))) {
                break;
            }
            right_padding += cur_it->length;
        }
        end_it = prev_it;

        rewrite_paths = start_it != mappings.begin() || end_it != --mappings.end();

        // cut out nodes before and after discontinuity
        mappings.erase(mappings.begin(), start_it);
        mappings.erase(++end_it, mappings.end());
    }
    // We're clipping at a cycle in the reference path.  Just preserve the path as-is from the
    // input region.
    else {
        mappings.clear();
        for (step_handle_t step = start_step; step != end_plus_one_step; step = graph->get_next_step(step)) {
            handle_t step_handle = graph->get_handle_of_step(step);
            mapping_t mapping;
            mapping.set_node_id(graph->get_id(step_handle));
            mapping.set_is_reverse(graph->get_is_reverse(step_handle));
            mappings.push_back(mapping);
        }
        rewrite_paths = true;
    }

    // Cut our graph so that our reference path end points are graph tips.  This will let the
    // snarl finder use the path to find telomeres.
    path_handle_t sg_path_handle = subgraph.get_path_handle(region.seq);
    Node* start_node = subgraph.get_node(mappings.begin()->node_id());
    auto sg_start_steps = path_steps_of_handle(subgraph, subgraph.get_handle(start_node->id()), sg_path_handle);
    if (rewrite_paths && sg_start_steps.size() == 1) {
        if (!mappings.begin()->is_reverse() && subgraph.start_degree(start_node) != 0) {
            for (auto edge : subgraph.edges_to(start_node)) {
                assert(false);
                subgraph.destroy_edge(edge);
            }
        } else if (mappings.begin()->is_reverse() && subgraph.end_degree(start_node) != 0) {
            for (auto edge : subgraph.edges_from(start_node)) {
                assert(false);
                subgraph.destroy_edge(edge);
            }
        }
    }
    Node* end_node = subgraph.get_node(mappings.rbegin()->node_id());
    auto sg_end_steps = path_steps_of_handle(subgraph, subgraph.get_handle(end_node->id()), sg_path_handle);
    if (rewrite_paths && sg_end_steps.size() == 1) {
        if (!mappings.rbegin()->is_reverse() && subgraph.end_degree(end_node) != 0) {
            for (auto edge : subgraph.edges_from(end_node)) {
                assert(false);
                subgraph.destroy_edge(edge);
            }
        } else if (mappings.rbegin()->is_reverse() && subgraph.start_degree(end_node) != 0) {
            for (auto edge : subgraph.edges_to(end_node)) {
                assert(false);
                subgraph.destroy_edge(edge);
            }
        }
    }

    // Sync our updated paths lists back into the Graph protobuf
    if (rewrite_paths) {
        subgraph.paths.rebuild_node_mapping();
        subgraph.paths.rebuild_mapping_aux();
        subgraph.graph.clear_path();
        subgraph.paths.to_graph(subgraph.graph);
    }

    // start could fall inside a node.  we find out where in the path the
    // 0-offset point of the node is.
    int64_t input_start_pos = graph->get_position_of_step(start_step);
    int64_t input_end_pos = graph->get_position_of_step(end_step);
    out_region.seq = region.seq;
    out_region.start = input_start_pos - left_padding;
    out_region.end = input_end_pos + graph->get_length(end_handle) + right_padding - 1;
}

void PathChunker::extract_id_range(vg::id_t start, vg::id_t end, int context, int length,
                                   bool forward_only, VG& subgraph,
                                   Region& out_region) {

    Graph g;

    for (vg::id_t i = start; i <= end; ++i) {
        Node node;
        node.set_id(i);
        node.set_sequence(graph->get_sequence(graph->get_handle(i)));
        *g.add_node() = node;
    }

    VG vg_g(g);

    // expand the context and get path information
    // if forward_only true, then we only go forward.
    algorithms::expand_subgraph_by_steps(*graph, vg_g, context, forward_only);
    if (length) {
        algorithms::expand_subgraph_by_length(*graph, vg_g, context, forward_only);
    }
    algorithms::add_subpaths_to_subgraph(*graph, vg_g);

    // build the vg
    subgraph.extend(vg_g);
    subgraph.remove_orphan_edges();

    out_region.start = subgraph.min_node_id();
    out_region.end = subgraph.max_node_id();
}

set<pair<pair<id_t, bool>, pair<id_t, bool>>> PathChunker::get_path_edge_index(step_handle_t start_step,
                                                                               step_handle_t end_step, int context) const {
    // we don't use handles as we're going to use this structure to compare edges across different graphs
    set<pair<pair<id_t, bool>, pair<id_t, bool>>> path_edges;

    function<void(step_handle_t)> add_edge = [&](step_handle_t step) {
        step_handle_t next = graph->get_next_step(step);
        edge_t edge = graph->edge_handle(graph->get_handle_of_step(step), graph->get_handle_of_step(next));
        path_edges.insert(make_pair(make_pair(graph->get_id(edge.first), graph->get_is_reverse(edge.first)),
                                    make_pair(graph->get_id(edge.second), graph->get_is_reverse(edge.second))));

    };

    // edges from left context
    int i = 0;
    for (step_handle_t step = start_step; graph->has_previous_step(step) && i <= context;
         step = graph->get_previous_step(step), ++i) {
        add_edge(graph->get_previous_step(step));
    }

    // edges from range
    for (step_handle_t step = start_step; step != end_step; step = graph->get_next_step(step)) {
        if (graph->has_next_step(step)) {
            add_edge(step);
        }
    }

    // edges from right context
    i = 0;
    for (step_handle_t step = end_step; graph->has_next_step(step) && i <= context;
         step = graph->get_next_step(step), ++i) {
        add_edge(step);
    }

    return path_edges;
}

}
<commit_msg>remove stray assert falses<commit_after>#include <iostream>
#include <unordered_set>
#include <vg/io/stream.hpp>
#include "chunker.hpp"
#include "algorithms/subgraph.hpp"

namespace vg {

using namespace std;

PathChunker::PathChunker(const PathPositionHandleGraph* graph) : graph(graph) {

}

PathChunker::~PathChunker() {

}

void PathChunker::extract_subgraph(const Region& region, int context, int length, bool forward_only,
                                   VG& subgraph, Region& out_region) {
    // extract our path range into the graph
    path_handle_t path_handle = graph->get_path_handle(region.seq);
    step_handle_t start_step = graph->get_step_at_position(path_handle, region.start);
    handle_t start_handle = graph->get_handle_of_step(start_step);
    step_handle_t end_step = graph->get_step_at_position(path_handle, region.end);
    handle_t end_handle = graph->get_handle_of_step(end_step);

    step_handle_t end_plus_one_step = graph->has_next_step(end_step) ? graph->get_next_step(end_step) : graph->path_end(path_handle) ;
    for (step_handle_t step = start_step; step != end_plus_one_step; step = graph->get_next_step(step)) {
        handle_t step_handle = graph->get_handle_of_step(step);
        if (graph->get_is_reverse(step_handle)) {
            step_handle = graph->flip(step_handle);
        }
        if (!subgraph.has_node(graph->get_id(step_handle))) {
            subgraph.create_handle(graph->get_sequence(step_handle), graph->get_id(step_handle));
        }
    };
    // expand the context and get path information
    // if forward_only true, then we only go forward.
    if (context > 0) {
        algorithms::expand_subgraph_by_steps(*graph, subgraph, context, forward_only);
    }
    if (length > 0) {
        algorithms::expand_subgraph_by_length(*graph, subgraph, context, forward_only);
    }
    else if (context == 0 && length == 0) {
        algorithms::add_connecting_edges_to_subgraph(*graph, subgraph);
    }
    algorithms::add_subpaths_to_subgraph(*graph, subgraph);

    // build the vg of the subgraph
    subgraph.remove_orphan_edges();

    // get our range endpoints before context expansion
    list<mapping_t>& mappings = subgraph.paths.get_path(region.seq);
    assert(!mappings.empty());
    size_t mappings_size = mappings.size();
    int64_t input_start_node = graph->get_id(start_handle);
    int64_t input_end_node = graph->get_id(end_handle);

    // replaces old xg position_in_path() to check node counts in path
    function<vector<step_handle_t>(const PathHandleGraph&, handle_t, path_handle_t)> path_steps_of_handle =
        [] (const PathHandleGraph& graph, handle_t handle, path_handle_t path_handle) {
        vector<step_handle_t> node_steps = graph.steps_of_handle(handle);
        vector<step_handle_t> node_path_steps;
        for (auto step : node_steps) {
            if (graph.get_path_handle_of_step(step) == path_handle) {
                node_path_steps.push_back(step);
            }
        }
        return node_path_steps;
    };

    // we have no direct way of getting our steps out of the subgraph, so we
    // go through node ids.  the problem is that cycles can introduce
    // ambiguity.  we check for that here (only to punt on it later)
    vector<step_handle_t> start_node_path_steps = path_steps_of_handle(*graph, start_handle, path_handle);
    vector<step_handle_t> end_node_path_steps = path_steps_of_handle(*graph, end_handle, path_handle);
    bool end_points_on_cycle = start_node_path_steps.size() > 1 || end_node_path_steps.size() > 1;

    // keep track of the edges in our original path
    set<pair<pair<id_t, bool>, pair<id_t, bool>>> path_edge_set =
        get_path_edge_index(start_step, end_step, std::max(context, length));

    // the distance between them and the nodes in our input range
    size_t left_padding = 0;
    size_t right_padding = 0;
    // do we need to rewrite back to our graph?
    bool rewrite_paths = false;

    if (!end_points_on_cycle) {
        // start and end of our expanded chunk
        auto start_it = mappings.begin();
        auto end_it = --mappings.end();

        // find our input range in the expanded path. we know these nodes only appear once.
        for (; start_it != mappings.end() && start_it->node_id() != input_start_node; ++start_it);
        for (; end_it != mappings.begin() && end_it->node_id() != input_end_node; --end_it);

        // walk back our start point as we can without rank discontinuities. doesn't matter
        // if we encounter cycles here, because we keep a running path length
        auto cur_it = start_it;
        auto prev_it = cur_it;
        if (prev_it != mappings.begin()) {
            for (; prev_it != mappings.begin(); --prev_it) {
                cur_it = prev_it;
                --cur_it;
                handle_t  prev_handle = subgraph.get_handle(prev_it->node_id(),
                                                            prev_it->is_reverse());
                handle_t cur_handle = subgraph.get_handle(cur_it->node_id(),
                                                          cur_it->is_reverse());
                edge_t edge = subgraph.edge_handle(cur_handle, prev_handle);
                if (!path_edge_set.count(make_pair(make_pair(subgraph.get_id(edge.first), subgraph.get_is_reverse(edge.first)),
                                                   make_pair(subgraph.get_id(edge.second), subgraph.get_is_reverse(edge.second))))) {
                    break;
                }
                left_padding += cur_it->length;
            }
        }
        start_it = prev_it;
        // walk forward the end point
        cur_it = end_it;
        prev_it = cur_it;
        for (++cur_it; cur_it != mappings.end(); ++prev_it, ++cur_it) {
            handle_t  prev_handle = subgraph.get_handle(prev_it->node_id(),
                                                        prev_it->is_reverse());
            handle_t cur_handle = subgraph.get_handle(cur_it->node_id(),
                                                      cur_it->is_reverse());
            edge_t edge = subgraph.edge_handle(prev_handle, cur_handle);
            if (!path_edge_set.count(make_pair(make_pair(subgraph.get_id(edge.first), subgraph.get_is_reverse(edge.first)),
                                               make_pair(subgraph.get_id(edge.second), subgraph.get_is_reverse(edge.second))))) {
                break;
            }
            right_padding += cur_it->length;
        }
        end_it = prev_it;

        rewrite_paths = start_it != mappings.begin() || end_it != --mappings.end();

        // cut out nodes before and after discontinuity
        mappings.erase(mappings.begin(), start_it);
        mappings.erase(++end_it, mappings.end());
    }
    // We're clipping at a cycle in the reference path.  Just preserve the path as-is from the
    // input region.
    else {
        mappings.clear();
        for (step_handle_t step = start_step; step != end_plus_one_step; step = graph->get_next_step(step)) {
            handle_t step_handle = graph->get_handle_of_step(step);
            mapping_t mapping;
            mapping.set_node_id(graph->get_id(step_handle));
            mapping.set_is_reverse(graph->get_is_reverse(step_handle));
            mappings.push_back(mapping);
        }
        rewrite_paths = true;
    }

    // Cut our graph so that our reference path end points are graph tips.  This will let the
    // snarl finder use the path to find telomeres.
    path_handle_t sg_path_handle = subgraph.get_path_handle(region.seq);
    Node* start_node = subgraph.get_node(mappings.begin()->node_id());
    auto sg_start_steps = path_steps_of_handle(subgraph, subgraph.get_handle(start_node->id()), sg_path_handle);
    if (rewrite_paths && sg_start_steps.size() == 1) {
        if (!mappings.begin()->is_reverse() && subgraph.start_degree(start_node) != 0) {
            for (auto edge : subgraph.edges_to(start_node)) {
                subgraph.destroy_edge(edge);
            }
        } else if (mappings.begin()->is_reverse() && subgraph.end_degree(start_node) != 0) {
            for (auto edge : subgraph.edges_from(start_node)) {
                subgraph.destroy_edge(edge);
            }
        }
    }
    Node* end_node = subgraph.get_node(mappings.rbegin()->node_id());
    auto sg_end_steps = path_steps_of_handle(subgraph, subgraph.get_handle(end_node->id()), sg_path_handle);
    if (rewrite_paths && sg_end_steps.size() == 1) {
        if (!mappings.rbegin()->is_reverse() && subgraph.end_degree(end_node) != 0) {
            for (auto edge : subgraph.edges_from(end_node)) {
                subgraph.destroy_edge(edge);
            }
        } else if (mappings.rbegin()->is_reverse() && subgraph.start_degree(end_node) != 0) {
            for (auto edge : subgraph.edges_to(end_node)) {
                subgraph.destroy_edge(edge);
            }
        }
    }

    // Sync our updated paths lists back into the Graph protobuf
    if (rewrite_paths) {
        subgraph.paths.rebuild_node_mapping();
        subgraph.paths.rebuild_mapping_aux();
        subgraph.graph.clear_path();
        subgraph.paths.to_graph(subgraph.graph);
    }

    // start could fall inside a node.  we find out where in the path the
    // 0-offset point of the node is.
    int64_t input_start_pos = graph->get_position_of_step(start_step);
    int64_t input_end_pos = graph->get_position_of_step(end_step);
    out_region.seq = region.seq;
    out_region.start = input_start_pos - left_padding;
    out_region.end = input_end_pos + graph->get_length(end_handle) + right_padding - 1;
}

void PathChunker::extract_id_range(vg::id_t start, vg::id_t end, int context, int length,
                                   bool forward_only, VG& subgraph,
                                   Region& out_region) {

    Graph g;

    for (vg::id_t i = start; i <= end; ++i) {
        Node node;
        node.set_id(i);
        node.set_sequence(graph->get_sequence(graph->get_handle(i)));
        *g.add_node() = node;
    }

    VG vg_g(g);

    // expand the context and get path information
    // if forward_only true, then we only go forward.
    algorithms::expand_subgraph_by_steps(*graph, vg_g, context, forward_only);
    if (length) {
        algorithms::expand_subgraph_by_length(*graph, vg_g, context, forward_only);
    }
    algorithms::add_subpaths_to_subgraph(*graph, vg_g);

    // build the vg
    subgraph.extend(vg_g);
    subgraph.remove_orphan_edges();

    out_region.start = subgraph.min_node_id();
    out_region.end = subgraph.max_node_id();
}

set<pair<pair<id_t, bool>, pair<id_t, bool>>> PathChunker::get_path_edge_index(step_handle_t start_step,
                                                                               step_handle_t end_step, int context) const {
    // we don't use handles as we're going to use this structure to compare edges across different graphs
    set<pair<pair<id_t, bool>, pair<id_t, bool>>> path_edges;

    function<void(step_handle_t)> add_edge = [&](step_handle_t step) {
        step_handle_t next = graph->get_next_step(step);
        edge_t edge = graph->edge_handle(graph->get_handle_of_step(step), graph->get_handle_of_step(next));
        path_edges.insert(make_pair(make_pair(graph->get_id(edge.first), graph->get_is_reverse(edge.first)),
                                    make_pair(graph->get_id(edge.second), graph->get_is_reverse(edge.second))));

    };

    // edges from left context
    int i = 0;
    for (step_handle_t step = start_step; graph->has_previous_step(step) && i <= context;
         step = graph->get_previous_step(step), ++i) {
        add_edge(graph->get_previous_step(step));
    }

    // edges from range
    for (step_handle_t step = start_step; step != end_step; step = graph->get_next_step(step)) {
        if (graph->has_next_step(step)) {
            add_edge(step);
        }
    }

    // edges from right context
    i = 0;
    for (step_handle_t step = end_step; graph->has_next_step(step) && i <= context;
         step = graph->get_next_step(step), ++i) {
        add_edge(step);
    }

    return path_edges;
}

}
<|endoftext|>


<commit_before>/* LiteSQL - Common routines for backends
 *
 * The list of contributors at http://litesql.sf.net/
 *
 * See LICENSE for copyright information. */

#include <map>

#include "compatibility.hpp"
#include "litesql/backend.hpp"
#include "litesql/string.hpp"
#include "litesql/types.hpp"

#include "mysql.hpp"
#include "postgresql.hpp"
#include "sqlite3.hpp"
#include "odbc_backend.hpp"

using namespace litesql;
using namespace std;

string Backend::groupInsert(Record tables, Records fields, Records values,
                   string sequence) const {
    string id = values[0][0];

    if (supportsSequences() && values[0][0] == "NULL") {
      Result * r = execute("SELECT nextval('" + sequence + "');");
      id = r->records()[0][0];
      delete r;
    }
    for (int i = tables.size()-1; i >= 0; i--) {
        string fieldString = Split(fields[i]).join(",");
        string valueString;
        if (!values[i].empty())
            values[i][0] = id;
        Split valueSplit(values[i]);
        for (size_t i2 = 0; i2 < valueSplit.size(); i2++)
            valueSplit[i2] = escapeSQL(valueSplit[i2]);
        valueString = valueSplit.join(",");
        string query = "INSERT INTO " + tables[i] + " (" + fieldString
            + ") VALUES (" + valueString + ");";
        delete execute(query);
        if (!supportsSequences() && id == "NULL")
            id = getInsertID();

    }
    return id;
}

Backend* Backend::getBackend(const string & backendType,string connInfo)
{
  Backend* backend = NULL;

#ifdef HAVE_LIBMYSQLCLIENT
  if (backendType == "mysql") {
    backend = new MySQL(connInfo);
  } else
#endif
#ifdef HAVE_LIBPQ
    if (backendType == "postgresql") {
      backend = new PostgreSQL(connInfo);
    } else
#endif
#ifdef HAVE_ODBC
      if (backendType == "odbc") {
        backend = new ODBCBackend(connInfo);
      } else
#endif
#ifdef HAVE_LIBSQLITE3
        if (backendType == "sqlite3") {
          backend = new SQLite3(connInfo);
        }
#endif
        return backend;
}
<commit_msg>string -> const string &<commit_after>/* LiteSQL - Common routines for backends
 *
 * The list of contributors at http://litesql.sf.net/
 *
 * See LICENSE for copyright information. */

#include <map>

#include "compatibility.hpp"
#include "litesql/backend.hpp"
#include "litesql/string.hpp"
#include "litesql/types.hpp"

#include "mysql.hpp"
#include "postgresql.hpp"
#include "sqlite3.hpp"
#include "odbc_backend.hpp"

using namespace litesql;
using namespace std;

string Backend::groupInsert(Record tables, Records fields, Records values,
                   string sequence) const {
    string id = values[0][0];

    if (supportsSequences() && values[0][0] == "NULL") {
      Result * r = execute("SELECT nextval('" + sequence + "');");
      id = r->records()[0][0];
      delete r;
    }
    for (int i = tables.size()-1; i >= 0; i--) {
        string fieldString = Split(fields[i]).join(",");
        string valueString;
        if (!values[i].empty())
            values[i][0] = id;
        Split valueSplit(values[i]);
        for (size_t i2 = 0; i2 < valueSplit.size(); i2++)
            valueSplit[i2] = escapeSQL(valueSplit[i2]);
        valueString = valueSplit.join(",");
        string query = "INSERT INTO " + tables[i] + " (" + fieldString
            + ") VALUES (" + valueString + ");";
        delete execute(query);
        if (!supportsSequences() && id == "NULL")
            id = getInsertID();

    }
    return id;
}

Backend* Backend::getBackend(const string & backendType,const string& connInfo)
{
  Backend* backend = NULL;

#ifdef HAVE_LIBMYSQLCLIENT
  if (backendType == "mysql") {
    backend = new MySQL(connInfo);
  } else
#endif
#ifdef HAVE_LIBPQ
    if (backendType == "postgresql") {
      backend = new PostgreSQL(connInfo);
    } else
#endif
#ifdef HAVE_ODBC
      if (backendType == "odbc") {
        backend = new ODBCBackend(connInfo);
      } else
#endif
#ifdef HAVE_LIBSQLITE3
        if (backendType == "sqlite3") {
          backend = new SQLite3(connInfo);
        }
#endif
        return backend;
}
<|endoftext|>


<commit_before>/*
    Implementation of the Compiler class.

*/

#include <cctype>       //character comparison functions
#include <stdexcept>
#include "compiler.hh"

namespace ds_compiler {

const size_t Compiler::NUM_REGISTERS = 8;
const char Compiler::ERR_CHAR = '\0';
const std::unordered_set<char> Compiler::ADD_OPS({'+', '-'});
const std::unordered_set<char> Compiler::MULT_OPS;

//constructors
Compiler::Compiler ()
    : m_is (&std::cin), m_os (&std::cout)
{

}

Compiler::Compiler (std::istream *new_is, std::ostream *new_os)
    : m_is (new_is), m_os (new_os)
{

}

void Compiler::compile_intermediate () const {
    try {
        expression();
    } catch (std::exception &ex) {
        std::cerr << ex.what() << '\n';
    }
}

void Compiler::compile_full () const {

    compile_start();
    compile_intermediate();
    compile_end();

}

void Compiler::compile_start () const {

    //emit lines for necessary includes
    emit_line("#include <stack>");
    emit_line("#include <vector>");
    emit_line("#include <iostream>");
    emit_line("#include <string>");

    //create a stack and vector for registers
    std::string stack_init = "static std::stack<int> cpu_stack;";
    std::string registers_init = "static std::vector<int> cpu_registers(" + std::to_string(NUM_REGISTERS) + ", 0);";
    emit_line(stack_init);
    emit_line(registers_init);

    //emit definition of a function for easier stack handling
    emit_line("int cpu_pop() {");
    emit_line("int val = cpu_stack.top();");
    emit_line("cpu_stack.pop();");
    emit_line("return val; }");

    //emit lines for int main() {
    emit_line("int main () {");

}

void Compiler::compile_end () const {

    //dump register contents
    emit_line("std::cout << \"Register contents\\n\";");
    emit_line(
        std::string("for (int i = 0; i < ") + std::to_string(NUM_REGISTERS) + "; ++i)"
        );
    emit_line("std::cout << std::string(\"Register \") << i << \": \" << cpu_registers.at(i) << '\\n';");

    //emit lines for closing main
    emit_line("return 0;");
    emit_line("}");

}

//cradle methods

void Compiler::report_error(const std::string err) const {

    os() << '\n';
    os() << "Error: " << err << '\n';

}

void Compiler::abort(const std::string err) const {

    report_error(err);
    throw std::runtime_error("Compilation failed.\n");
}

void Compiler::expected(const std::string expect) const {

    abort(expect + " expected.\n");
}

//overload to handle single characters;
//prevents having to construct a string whenever calling expected()
void Compiler::expected(const char c) const {
    expected(std::string(1, c));
}

//checks if next character matches; if so, consume that character
void Compiler::match(const char c) const {

    if (is().peek() == c) {
        is().get();
    } else {
        expected(c);
    }
}

void Compiler::expression () const {
    term();

    while (is_in(ADD_OPS, is().peek())) {
        emit_line("cpu_registers.at(1) = cpu_registers.at(0);");
        switch (is().peek()) {
            case '+':
                add();
                break;
            case '-':
                subtract();
                break;
            default:
                expected("Addop");
        }
    }
}

void Compiler::term () const {
    char expr = get_num();

    if (expr != ERR_CHAR) {
        emit_line(
            std::string("cpu_registers.at(0) = ") + expr + ";"
        );
    }
}

// gets a valid identifier from input stream
char Compiler::get_name () const {
    if (!std::isalpha(is().peek())) {
        expected("Name");
        return ERR_CHAR;
    } else {
        return std::toupper(is().get());
    }

}

//gets a number
char Compiler::get_num () const {
    if (!std::isdigit(is().peek())) {
        expected("Integer");
        return ERR_CHAR;
    } else {
        return is().get();
    }
}

//output a string
void Compiler::emit (std::string s) const {
    os() << s;
}

//output a string with newline
void Compiler::emit_line (std::string s) const {
    emit(s);
    emit("\n");
}

//helper members to allow using stream syntax with *is, *os

void Compiler::add () const {
    match('+');
    term();
    emit_line(
        std::string("cpu_registers.at(0) = cpu_registers.at(1) + cpu_registers.at(0);")
    );
}

void Compiler::subtract () const {
    match('-');
    term();
    emit_line(
        std::string("cpu_registers.at(0) = cpu_registers.at(1) - cpu_registers.at(0);")
    );
}

bool Compiler::is_in(const std::unordered_set<char> us, const char elem) {
    return us.find(elem) != us.end();
}

void Compiler::set_is (std::istream *new_is) {
    m_is = new_is;
}

void Compiler::set_os (std::ostream *new_os) {
    m_os = new_os;
}

std::istream& Compiler::is() const {
    return *m_is;
}

std::ostream& Compiler::os() const {
    return *m_os;
}

} //end namespace<commit_msg>Reordered members in compiler.cc to form more logical groups.<commit_after>/*
    Implementation of the Compiler class.

*/

#include <cctype>       //character comparison functions
#include <stdexcept>
#include "compiler.hh"

namespace ds_compiler {

const size_t Compiler::NUM_REGISTERS = 8;
const char Compiler::ERR_CHAR = '\0';
const std::unordered_set<char> Compiler::ADD_OPS({'+', '-'});
const std::unordered_set<char> Compiler::MULT_OPS;

//constructors
Compiler::Compiler ()
    : m_is (&std::cin), m_os (&std::cout)
{

}

Compiler::Compiler (std::istream *new_is, std::ostream *new_os)
    : m_is (new_is), m_os (new_os)
{

}

void Compiler::compile_intermediate () const {
    try {
        expression();
    } catch (std::exception &ex) {
        std::cerr << ex.what() << '\n';
    }
}

void Compiler::compile_full () const {

    compile_start();
    compile_intermediate();
    compile_end();

}

void Compiler::compile_start () const {

    //emit lines for necessary includes
    emit_line("#include <stack>");
    emit_line("#include <vector>");
    emit_line("#include <iostream>");
    emit_line("#include <string>");

    //create a stack and vector for registers
    std::string stack_init = "static std::stack<int> cpu_stack;";
    std::string registers_init = "static std::vector<int> cpu_registers(" + std::to_string(NUM_REGISTERS) + ", 0);";
    emit_line(stack_init);
    emit_line(registers_init);

    //emit definition of a function for easier stack handling
    emit_line("int cpu_pop() {");
    emit_line("int val = cpu_stack.top();");
    emit_line("cpu_stack.pop();");
    emit_line("return val; }");

    //emit lines for int main() {
    emit_line("int main () {");

}

void Compiler::compile_end () const {

    //dump register contents
    emit_line("std::cout << \"Register contents\\n\";");
    emit_line(
        std::string("for (int i = 0; i < ") + std::to_string(NUM_REGISTERS) + "; ++i)"
        );
    emit_line("std::cout << std::string(\"Register \") << i << \": \" << cpu_registers.at(i) << '\\n';");

    //emit lines for closing main
    emit_line("return 0;");
    emit_line("}");

}

//cradle methods

void Compiler::report_error(const std::string err) const {

    os() << '\n';
    os() << "Error: " << err << '\n';

}

void Compiler::abort(const std::string err) const {

    report_error(err);
    throw std::runtime_error("Compilation failed.\n");
}

void Compiler::expected(const std::string expect) const {

    abort(expect + " expected.\n");
}

//overload to handle single characters;
//prevents having to construct a string whenever calling expected()
void Compiler::expected(const char c) const {
    expected(std::string(1, c));
}

//checks if next character matches; if so, consume that character
void Compiler::match(const char c) const {

    if (is().peek() == c) {
        is().get();
    } else {
        expected(c);
    }
}

// gets a valid identifier from input stream
char Compiler::get_name () const {
    if (!std::isalpha(is().peek())) {
        expected("Name");
        return ERR_CHAR;
    } else {
        return std::toupper(is().get());
    }

}

//gets a number
char Compiler::get_num () const {
    if (!std::isdigit(is().peek())) {
        expected("Integer");
        return ERR_CHAR;
    } else {
        return is().get();
    }
}

//output a string
void Compiler::emit (std::string s) const {
    os() << s;
}

//output a string with newline
void Compiler::emit_line (std::string s) const {
    emit(s);
    emit("\n");
}

void Compiler::expression () const {
    term();

    while (is_in(ADD_OPS, is().peek())) {
        emit_line("cpu_registers.at(1) = cpu_registers.at(0)");
        switch (is().peek()) {
            case '+':
                add();
                break;
            case '-':
                subtract();
                break;
            default:
                expected("Addop");
        }
    }
}

void Compiler::term () const {
    char expr = get_num();

    if (expr != ERR_CHAR) {
        emit_line(
            std::string("cpu_registers.at(0) = ") + expr + ";"
        );
    }
}

void Compiler::add () const {
    match('+');
    term();
    emit_line(
        std::string("cpu_registers.at(0) = cpu_registers.at(1) + cpu_registers.at(0);")
    );
}

void Compiler::subtract () const {
    match('-');
    term();
    emit_line(
        std::string("cpu_registers.at(0) = cpu_registers.at(1) - cpu_registers.at(0);")
    );
}

bool Compiler::is_in(const std::unordered_set<char> us, const char elem) {
    return us.find(elem) != us.end();
}

//helper members to allow using stream syntax with *is, *os

void Compiler::set_is (std::istream *new_is) {
    m_is = new_is;
}

void Compiler::set_os (std::ostream *new_os) {
    m_os = new_os;
}

std::istream& Compiler::is() const {
    return *m_is;
}

std::ostream& Compiler::os() const {
    return *m_os;
}

} //end namespace<|endoftext|>


<commit_before>/****************************************************************************

This file is part of the QtMediaHub project on http://www.qtmediahub.com

Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Girish Ramakrishnan girish@forwardbias.in
Contact:  Nokia Corporation donald.carr@nokia.com
Contact:  Nokia Corporation johannes.zellner@nokia.com

You may use this file under the terms of the BSD license as follows:

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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

#include "mainwindow.h"
#include "skinmanager.h"
#include "skinselector.h"
#include "skinruntime.h"
#include "globalsettings.h"

#include <QtCore>
#include <QtGui>

#ifdef SCENEGRAPH
#include <QQuickView>
#include <QtWidgets>
#else
#include <QDeclarativeView>
#endif

MainWindow::MainWindow(GlobalSettings *settings, QWidget *parent)
    : QWidget(parent),
      m_centralWidget(0),
      m_settings(settings)
{
    m_overscanWorkAround = m_settings->isEnabled(GlobalSettings::Overscan);
    m_attemptingFullScreen = m_settings->isEnabled(GlobalSettings::FullScreen);

    const bool isOverlay = m_settings->isEnabled(GlobalSettings::OverlayMode);
    setAttribute(isOverlay ? Qt::WA_TranslucentBackground : Qt::WA_NoSystemBackground);

    m_skinRuntime = new SkinRuntime(m_settings, this);

    // TODO Orientation needs to be changeable from skin during runtime
    setOrientation(ScreenOrientationAuto);

    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Backspace), this, SIGNAL(resetUI()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Down), this, SLOT(decreaseHeight()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Up), this, SLOT(increaseHeight()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Right), this, SLOT(decreaseWidth()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Left), this, SLOT(increaseWidth()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right), this, SLOT(moveRight()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Left), this, SLOT(moveLeft()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up), this, SLOT(moveUp()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down), this, SLOT(moveDown()));

    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this, SLOT(toggleFullScreen()));

    m_resizeSettleTimer.setSingleShot(true);

    connect(&m_resizeSettleTimer, SIGNAL(timeout()), this, SLOT(handleResize()));

    m_inputIdleTimer.setInterval(m_settings->value(GlobalSettings::IdleTimeout).toInt() * 1000);
    m_inputIdleTimer.setSingleShot(true);
    m_inputIdleTimer.start();
    connect(&m_inputIdleTimer, SIGNAL(timeout()), this, SIGNAL(inputIdle()));

    QList<QAction*> actions;
    QAction *selectSkinAction = new QAction(tr("Select skin"), this);
    QAction *quitAction = new QAction(tr("Quit"), this);
    connect(selectSkinAction, SIGNAL(triggered()), this, SLOT(selectSkin()));
    connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));
    actions.append(selectSkinAction);
    actions.append(quitAction);

    if (m_settings->isEnabled(GlobalSettings::SystemTray)) {
        QSystemTrayIcon *systray = new QSystemTrayIcon(QIcon(":/images/petite-ganesh-22x22.jpg"), this);
        systray->setVisible(true);
        QMenu *contextMenu = new QMenu;
        contextMenu->addActions(actions);
        systray->setContextMenu(contextMenu);
    }

        m_skinManager = new SkinManager(m_settings, this);
}

MainWindow::~MainWindow()
{
    m_settings->setValue(GlobalSettings::Overscan, m_overscanWorkAround);
    m_settings->setValue(GlobalSettings::FullScreen, m_attemptingFullScreen);

    if (!m_attemptingFullScreen)
        m_settings->setValue(GlobalSettings::WindowGeometry, geometry());
    else if (m_overscanWorkAround)
        m_settings->setValue(GlobalSettings::OverscanGeometry, geometry());
}

QWidget *MainWindow::centralWidget() const
{
    return m_centralWidget;
}

void MainWindow::setCentralWidget(QWidget *centralWidget)
{
    if (m_centralWidget) {
        m_centralWidget->hide();
        delete m_centralWidget;
    }
    m_centralWidget = centralWidget;
    m_centralWidget->setParent(this);
    m_centralWidget->setFixedSize(size());
    m_centralWidget->installEventFilter(this);
    if (isVisible())
        m_centralWidget->show();
}

void MainWindow::resizeEvent(QResizeEvent *e)
{
    Q_UNUSED(e);

    static int staggerResizingDelay = m_settings->value(GlobalSettings::ResizeDelay).toInt();
    if (staggerResizingDelay == 0)
        handleResize();
    else
        m_resizeSettleTimer.start(staggerResizingDelay);
}

void MainWindow::setOrientation(ScreenOrientation orientation)
{
#ifdef SCENEGRAPH
    qWarning("set orientation is not supported, yet");
#else
    Qt::WidgetAttribute attribute;
    switch (orientation) {
    case ScreenOrientationLockPortrait:
        attribute = Qt::WA_LockPortraitOrientation;
        break;
    case ScreenOrientationLockLandscape:
        attribute = Qt::WA_LockLandscapeOrientation;
        break;
    default:
    case ScreenOrientationAuto:
        attribute = Qt::WA_AutoOrientation;
        break;
    };
    setAttribute(attribute, true);
#endif
}

void MainWindow::handleResize()
{
    if (m_centralWidget)
        m_centralWidget->setFixedSize(size());
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress
        || event->type() == QEvent::KeyRelease
        || event->type() == QEvent::MouseMove
        || event->type() == QEvent::MouseButtonPress) {
        if (!m_inputIdleTimer.isActive())
            emit inputActive();
        m_inputIdleTimer.start();
    }

    return QObject::eventFilter(obj, event);
}

void MainWindow::increaseHeight()
{
    if (!m_attemptingFullScreen)
        return;

    const QRect newGeometry = geometry().adjusted(0,-1,0,1);

    const QSize desktopSize = qApp->desktop()->screenGeometry(this).size();
    if ((newGeometry.width() > desktopSize.width())
            || (newGeometry.height() > desktopSize.height())) {
        m_settings->setValue(GlobalSettings::Overscan, false);
        showFullScreen();
    } else {
        setGeometry(newGeometry);
    }
}

void MainWindow::increaseWidth()
{
    if (!m_attemptingFullScreen)
        return;

    const QRect newGeometry = geometry().adjusted(-1,0,1,0);

    const QSize desktopSize = qApp->desktop()->screenGeometry(this).size();
    if ((newGeometry.width() > desktopSize.width())
            || (newGeometry.height() > desktopSize.height())) {
        m_settings->setValue(GlobalSettings::Overscan, false);
        showFullScreen();
    } else {
        setGeometry(newGeometry);
    }

}

void MainWindow::decreaseHeight()
{
    if (!m_attemptingFullScreen)
        return;

    if (!m_overscanWorkAround) {
        m_settings->setValue(GlobalSettings::Overscan, true);
        showFullScreen();
    }
    setGeometry(geometry().adjusted(0,1,0,-1));
}

void MainWindow::decreaseWidth()
{
    if (!m_attemptingFullScreen)
        return;

    if (!m_overscanWorkAround) {
        m_settings->setValue(GlobalSettings::Overscan, true);
        showFullScreen();
    }
    setGeometry(geometry().adjusted(1,0,-1,0));
}

void MainWindow::moveLeft()
{
    QRect g = geometry();
    g.moveLeft(g.left() - 1);
    setGeometry(g);
}

void MainWindow::moveRight()
{
    QRect g = geometry();
    g.moveLeft(g.left() + 1);
    setGeometry(g);
}

void MainWindow::moveDown()
{
    QRect g = geometry();
    g.moveTop(g.top() + 1);
    setGeometry(g);
}

void MainWindow::moveUp()
{
    QRect g = geometry();
    g.moveTop(g.top() - 1);
    setGeometry(g);
}

void MainWindow::toggleFullScreen()
{
    m_settings->setValue(GlobalSettings::OverscanGeometry, geometry());
    if (m_attemptingFullScreen) {
        showNormal();
    } else {
        showFullScreen();
    }
}

void MainWindow::showFullScreen()
{
    m_attemptingFullScreen = true;
    m_overscanWorkAround = m_settings->isEnabled(GlobalSettings::Overscan);

    if (m_overscanWorkAround) {
        QRect geometry = m_settings->value(GlobalSettings::OverscanGeometry).toRect();
        geometry.moveCenter(qApp->desktop()->availableGeometry().center());

        setGeometry(geometry);
        setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
        setWindowState(Qt::WindowNoState);
        QWidget::show();
    } else {
        QWidget::showFullScreen();
    }

    activateWindow();
}

void MainWindow::showNormal()
{
    m_attemptingFullScreen = m_overscanWorkAround = false;

    setWindowFlags(Qt::Window);
    setGeometry(m_settings->value(GlobalSettings::WindowGeometry).toRect());
    QWidget::showNormal();

    activateWindow();
}

void MainWindow::show()
{
    //FIXME: QML 2 related hackery
#ifndef SCENEGRAPH
    if (m_attemptingFullScreen) {
        showFullScreen();
    } else {
        showNormal();
    }
#endif
}

void MainWindow::selectSkin()
{
    SkinSelector *skinSelector = new SkinSelector(m_skinManager, this);
    skinSelector->setAttribute(Qt::WA_DeleteOnClose);
    connect(skinSelector, SIGNAL(skinSelected(Skin *)), this, SLOT(setSkin(Skin *)));
    skinSelector->exec();
}

bool MainWindow::setSkin(const QString &name)
{
    QHash<QString, Skin *> skins = m_skinManager->skins();
    Skin *newSkin = skins.value(name);
    if (!newSkin && skins.size() > 0) {
        newSkin = skins.value(m_settings->value(GlobalSettings::Skin).toString());
    }

    if (!newSkin && skins.size() > 0) {
        newSkin = skins.value(skins.keys().at(0));
    }

    if (newSkin) {
        qDebug() << "Attempting to use:" << name << "skin";
    } else {
        qDebug() << "Failed to set skin:" << name;
        return false;
    }
    setSkin(newSkin);
    return true;
}

bool MainWindow::setSkin(Skin *newSkin)
{
    QObject *skinWidget = m_skinRuntime->create(newSkin, this);
    if (!skinWidget) {
        qDebug() << "Failed to load skin:" << newSkin->name();
        return false;
    }

    QWidget *widget = qobject_cast<QWidget*>(skinWidget);
    if (widget) {
        setCentralWidget(widget);
    }
#ifdef SCENEGRAPH
    else {
        //FIXME: We clearly need parity window state management in the long run
        (qobject_cast<QWindow*>(skinWidget))->show();
    }
#endif
    return true;
}

<commit_msg>always useful to know what size is being attempted<commit_after>/****************************************************************************

This file is part of the QtMediaHub project on http://www.qtmediahub.com

Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Girish Ramakrishnan girish@forwardbias.in
Contact:  Nokia Corporation donald.carr@nokia.com
Contact:  Nokia Corporation johannes.zellner@nokia.com

You may use this file under the terms of the BSD license as follows:

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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

#include "mainwindow.h"
#include "skinmanager.h"
#include "skinselector.h"
#include "skinruntime.h"
#include "globalsettings.h"

#include <QtCore>
#include <QtGui>

#ifdef SCENEGRAPH
#include <QQuickView>
#include <QtWidgets>
#else
#include <QDeclarativeView>
#endif

MainWindow::MainWindow(GlobalSettings *settings, QWidget *parent)
    : QWidget(parent),
      m_centralWidget(0),
      m_settings(settings)
{
    m_overscanWorkAround = m_settings->isEnabled(GlobalSettings::Overscan);
    m_attemptingFullScreen = m_settings->isEnabled(GlobalSettings::FullScreen);

    const bool isOverlay = m_settings->isEnabled(GlobalSettings::OverlayMode);
    setAttribute(isOverlay ? Qt::WA_TranslucentBackground : Qt::WA_NoSystemBackground);

    m_skinRuntime = new SkinRuntime(m_settings, this);

    // TODO Orientation needs to be changeable from skin during runtime
    setOrientation(ScreenOrientationAuto);

    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Backspace), this, SIGNAL(resetUI()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Down), this, SLOT(decreaseHeight()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Up), this, SLOT(increaseHeight()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Right), this, SLOT(decreaseWidth()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Left), this, SLOT(increaseWidth()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right), this, SLOT(moveRight()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Left), this, SLOT(moveLeft()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up), this, SLOT(moveUp()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down), this, SLOT(moveDown()));

    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this, SLOT(toggleFullScreen()));

    m_resizeSettleTimer.setSingleShot(true);

    connect(&m_resizeSettleTimer, SIGNAL(timeout()), this, SLOT(handleResize()));

    m_inputIdleTimer.setInterval(m_settings->value(GlobalSettings::IdleTimeout).toInt() * 1000);
    m_inputIdleTimer.setSingleShot(true);
    m_inputIdleTimer.start();
    connect(&m_inputIdleTimer, SIGNAL(timeout()), this, SIGNAL(inputIdle()));

    QList<QAction*> actions;
    QAction *selectSkinAction = new QAction(tr("Select skin"), this);
    QAction *quitAction = new QAction(tr("Quit"), this);
    connect(selectSkinAction, SIGNAL(triggered()), this, SLOT(selectSkin()));
    connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));
    actions.append(selectSkinAction);
    actions.append(quitAction);

    if (m_settings->isEnabled(GlobalSettings::SystemTray)) {
        QSystemTrayIcon *systray = new QSystemTrayIcon(QIcon(":/images/petite-ganesh-22x22.jpg"), this);
        systray->setVisible(true);
        QMenu *contextMenu = new QMenu;
        contextMenu->addActions(actions);
        systray->setContextMenu(contextMenu);
    }

        m_skinManager = new SkinManager(m_settings, this);
}

MainWindow::~MainWindow()
{
    m_settings->setValue(GlobalSettings::Overscan, m_overscanWorkAround);
    m_settings->setValue(GlobalSettings::FullScreen, m_attemptingFullScreen);

    if (!m_attemptingFullScreen)
        m_settings->setValue(GlobalSettings::WindowGeometry, geometry());
    else if (m_overscanWorkAround)
        m_settings->setValue(GlobalSettings::OverscanGeometry, geometry());
}

QWidget *MainWindow::centralWidget() const
{
    return m_centralWidget;
}

void MainWindow::setCentralWidget(QWidget *centralWidget)
{
    if (m_centralWidget) {
        m_centralWidget->hide();
        delete m_centralWidget;
    }
    m_centralWidget = centralWidget;
    m_centralWidget->setParent(this);
    m_centralWidget->setFixedSize(size());
    m_centralWidget->installEventFilter(this);
    if (isVisible())
        m_centralWidget->show();
}

void MainWindow::resizeEvent(QResizeEvent *e)
{
    Q_UNUSED(e);

    static int staggerResizingDelay = m_settings->value(GlobalSettings::ResizeDelay).toInt();
    if (staggerResizingDelay == 0)
        handleResize();
    else
        m_resizeSettleTimer.start(staggerResizingDelay);
}

void MainWindow::setOrientation(ScreenOrientation orientation)
{
#ifdef SCENEGRAPH
    qWarning("set orientation is not supported, yet");
#else
    Qt::WidgetAttribute attribute;
    switch (orientation) {
    case ScreenOrientationLockPortrait:
        attribute = Qt::WA_LockPortraitOrientation;
        break;
    case ScreenOrientationLockLandscape:
        attribute = Qt::WA_LockLandscapeOrientation;
        break;
    default:
    case ScreenOrientationAuto:
        attribute = Qt::WA_AutoOrientation;
        break;
    };
    setAttribute(attribute, true);
#endif
}

void MainWindow::handleResize()
{
    if (m_centralWidget)
        m_centralWidget->setFixedSize(size());
    qDebug() << "Resizing widget to:" << size();
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress
        || event->type() == QEvent::KeyRelease
        || event->type() == QEvent::MouseMove
        || event->type() == QEvent::MouseButtonPress) {
        if (!m_inputIdleTimer.isActive())
            emit inputActive();
        m_inputIdleTimer.start();
    }

    return QObject::eventFilter(obj, event);
}

void MainWindow::increaseHeight()
{
    if (!m_attemptingFullScreen)
        return;

    const QRect newGeometry = geometry().adjusted(0,-1,0,1);

    const QSize desktopSize = qApp->desktop()->screenGeometry(this).size();
    if ((newGeometry.width() > desktopSize.width())
            || (newGeometry.height() > desktopSize.height())) {
        m_settings->setValue(GlobalSettings::Overscan, false);
        showFullScreen();
    } else {
        setGeometry(newGeometry);
    }
}

void MainWindow::increaseWidth()
{
    if (!m_attemptingFullScreen)
        return;

    const QRect newGeometry = geometry().adjusted(-1,0,1,0);

    const QSize desktopSize = qApp->desktop()->screenGeometry(this).size();
    if ((newGeometry.width() > desktopSize.width())
            || (newGeometry.height() > desktopSize.height())) {
        m_settings->setValue(GlobalSettings::Overscan, false);
        showFullScreen();
    } else {
        setGeometry(newGeometry);
    }

}

void MainWindow::decreaseHeight()
{
    if (!m_attemptingFullScreen)
        return;

    if (!m_overscanWorkAround) {
        m_settings->setValue(GlobalSettings::Overscan, true);
        showFullScreen();
    }
    setGeometry(geometry().adjusted(0,1,0,-1));
}

void MainWindow::decreaseWidth()
{
    if (!m_attemptingFullScreen)
        return;

    if (!m_overscanWorkAround) {
        m_settings->setValue(GlobalSettings::Overscan, true);
        showFullScreen();
    }
    setGeometry(geometry().adjusted(1,0,-1,0));
}

void MainWindow::moveLeft()
{
    QRect g = geometry();
    g.moveLeft(g.left() - 1);
    setGeometry(g);
}

void MainWindow::moveRight()
{
    QRect g = geometry();
    g.moveLeft(g.left() + 1);
    setGeometry(g);
}

void MainWindow::moveDown()
{
    QRect g = geometry();
    g.moveTop(g.top() + 1);
    setGeometry(g);
}

void MainWindow::moveUp()
{
    QRect g = geometry();
    g.moveTop(g.top() - 1);
    setGeometry(g);
}

void MainWindow::toggleFullScreen()
{
    m_settings->setValue(GlobalSettings::OverscanGeometry, geometry());
    if (m_attemptingFullScreen) {
        showNormal();
    } else {
        showFullScreen();
    }
}

void MainWindow::showFullScreen()
{
    m_attemptingFullScreen = true;
    m_overscanWorkAround = m_settings->isEnabled(GlobalSettings::Overscan);

    if (m_overscanWorkAround) {
        QRect geometry = m_settings->value(GlobalSettings::OverscanGeometry).toRect();
        geometry.moveCenter(qApp->desktop()->availableGeometry().center());

        setGeometry(geometry);
        setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
        setWindowState(Qt::WindowNoState);
        QWidget::show();
    } else {
        QWidget::showFullScreen();
    }

    activateWindow();
}

void MainWindow::showNormal()
{
    m_attemptingFullScreen = m_overscanWorkAround = false;

    setWindowFlags(Qt::Window);
    setGeometry(m_settings->value(GlobalSettings::WindowGeometry).toRect());
    QWidget::showNormal();

    activateWindow();
}

void MainWindow::show()
{
    //FIXME: QML 2 related hackery
#ifndef SCENEGRAPH
    if (m_attemptingFullScreen) {
        showFullScreen();
    } else {
        showNormal();
    }
#endif
}

void MainWindow::selectSkin()
{
    SkinSelector *skinSelector = new SkinSelector(m_skinManager, this);
    skinSelector->setAttribute(Qt::WA_DeleteOnClose);
    connect(skinSelector, SIGNAL(skinSelected(Skin *)), this, SLOT(setSkin(Skin *)));
    skinSelector->exec();
}

bool MainWindow::setSkin(const QString &name)
{
    QHash<QString, Skin *> skins = m_skinManager->skins();
    Skin *newSkin = skins.value(name);
    if (!newSkin && skins.size() > 0) {
        newSkin = skins.value(m_settings->value(GlobalSettings::Skin).toString());
    }

    if (!newSkin && skins.size() > 0) {
        newSkin = skins.value(skins.keys().at(0));
    }

    if (newSkin) {
        qDebug() << "Attempting to use:" << name << "skin";
    } else {
        qDebug() << "Failed to set skin:" << name;
        return false;
    }
    setSkin(newSkin);
    return true;
}

bool MainWindow::setSkin(Skin *newSkin)
{
    QObject *skinWidget = m_skinRuntime->create(newSkin, this);
    if (!skinWidget) {
        qDebug() << "Failed to load skin:" << newSkin->name();
        return false;
    }

    QWidget *widget = qobject_cast<QWidget*>(skinWidget);
    if (widget) {
        setCentralWidget(widget);
    }
#ifdef SCENEGRAPH
    else {
        //FIXME: We clearly need parity window state management in the long run
        (qobject_cast<QWindow*>(skinWidget))->show();
    }
#endif
    return true;
}

<|endoftext|>


<commit_before>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2002 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#ifdef WIN32
# pragma warning (disable: 4786)
# pragma warning (disable: 4243)
// warning C4355: 'this' : used in base member initializer list
# pragma warning (disable: 4355)
#endif  // WIN32

#include <limits.h>

#include <vector>
#include <numeric>
#include <limits>
#include <set>

#include "copasi.h"
#include "CStochMethod.h"
#include "CStochDirectMethod.h"
#include "CStochNextReactionMethod.h"
#include "copasi/core/CDataVector.h"
#include "function/CFunction.h"
#include "randomGenerator/CRandom.h"
#include "CTrajectoryMethod.h"
#include "CTrajectoryProblem.h"
#include "math/CMathContainer.h"
#include "math/CMathReaction.h"
#include "model/CModel.h"

C_INT32 CStochMethod::checkModel(CModel * C_UNUSED(pmodel))
{
  // Here several checks will be performed to validate the model
  return 2; // suggest next reaction method
}

CStochMethod::CStochMethod(const CDataContainer * pParent,
                           const CTaskEnum::Method & methodType,
                           const CTaskEnum::Task & taskType):
  CTrajectoryMethod(pParent, methodType, taskType),
  mpRandomGenerator(NULL),
  mA0(0.0),
  mNumReactions(0),
  mReactions(),
  mPropensityObjects(),
  mAmu(),
  mUpdateSequences(),
  mMaxSteps(0),
  mMaxStepsReached(false),
  mNextReactionTime(0.0),
  mNextReactionIndex(C_INVALID_INDEX),
  mNumReactionSpecies(0),
  mFirstReactionSpeciesIndex(C_INVALID_INDEX),
  mDG()
{
  initializeParameter();
  mpRandomGenerator = CRandom::createGenerator(CRandom::mt19937);
}

CStochMethod::CStochMethod(const CStochMethod & src,
                           const CDataContainer * pParent):
  CTrajectoryMethod(src, pParent),
  mpRandomGenerator(NULL),
  mA0(0.0),
  mNumReactions(0),
  mReactions(),
  mPropensityObjects(),
  mAmu(),
  mUpdateSequences(),
  mMaxSteps(0),
  mMaxStepsReached(false),
  mNextReactionTime(0.0),
  mNextReactionIndex(C_INVALID_INDEX),
  mNumReactionSpecies(0),
  mFirstReactionSpeciesIndex(C_INVALID_INDEX),
  mDG()
{
  initializeParameter();
  mpRandomGenerator = CRandom::createGenerator(CRandom::mt19937);
}

CStochMethod::~CStochMethod()
{}

void CStochMethod::initializeParameter()
{
  CCopasiParameter *pParm;

  assertParameter("Max Internal Steps", CCopasiParameter::INT, (C_INT32) 1000000);
  assertParameter("Subtype", CCopasiParameter::UINT, (unsigned C_INT32) 2);
  assertParameter("Use Random Seed", CCopasiParameter::BOOL, false);
  assertParameter("Random Seed", CCopasiParameter::UINT, (unsigned C_INT32) 1);

  // Check whether we have a method with the old parameter names
  if ((pParm = getParameter("STOCH.MaxSteps")) != NULL)
    {
      setValue("Max Internal Steps", pParm->getValue< C_INT32 >());
      removeParameter("STOCH.MaxSteps");

      if ((pParm = getParameter("STOCH.Subtype")) != NULL)
        {
          setValue("Subtype", pParm->getValue< unsigned C_INT32 >());
          removeParameter("STOCH.Subtype");
        }

      if ((pParm = getParameter("STOCH.UseRandomSeed")) != NULL)
        {
          setValue("Use Random Seed", pParm->getValue< bool >());
          removeParameter("STOCH.UseRandomSeed");
        }

      if ((pParm = getParameter("STOCH.RandomSeed")) != NULL)
        {
          setValue("Random Seed", pParm->getValue< unsigned C_INT32 >());
          removeParameter("STOCH.RandomSeed");
        }
    }
}

bool CStochMethod::elevateChildren()
{
  initializeParameter();
  return true;
}

CTrajectoryMethod::Status CStochMethod::step(const double & deltaT,
    const bool & /* final */)
{
  // write the current state to the model:
  //mpProblem->getModel()->setState(mpCurrentState); //?

  // check for possible overflows:

  // do several steps:
  C_FLOAT64 time = *mpContainerStateTime;
  C_FLOAT64 endtime = time + deltaT;

  size_t Steps = 0;

  while (time < endtime)
    {
      time = doSingleStep(time, endtime);
      *mpContainerStateTime = time;

      if (++Steps > mMaxSteps)
        {
          CCopasiMessage(CCopasiMessage::EXCEPTION, MCTrajectoryMethod + 12);
        }

      if (mpProblem->getAutomaticStepSize()) break;
    }

  *mpContainerStateTime = time;

  return NORMAL;
}

void CStochMethod::start()
{
  CTrajectoryMethod::start();

  mpRandomGenerator = &mpContainer->getRandomGenerator();

  bool useRandomSeed = getValue< bool >("Use Random Seed");
  unsigned C_INT32 randomSeed = getValue< unsigned C_INT32 >("Random Seed");

  if (useRandomSeed) mpRandomGenerator->initialize(randomSeed);

  mMaxSteps = getValue< C_INT32 >("Max Internal Steps");

  //initialize the vector of ints that contains the particle numbers
  //for the discrete simulation. This also floors all particle numbers in the model.

  // Size the arrays
  mReactions.initialize(mpContainer->getReactions());
  mNumReactions = mReactions.size();
  mAmu.initialize(mpContainer->getPropensities());
  mPropensityObjects.initialize(mAmu.size(), mpContainer->getMathObject(mAmu.array()));
  mUpdateSequences.resize(mNumReactions);

  CMathReaction * pReaction = mReactions.array();
  CMathReaction * pReactionEnd = pReaction + mNumReactions;
  CCore::CUpdateSequence * pUpdateSequence = mUpdateSequences.array();
  CMathObject * pPropensityObject = mPropensityObjects.array();
  CMathObject * pPropensityObjectEnd = pPropensityObject + mPropensityObjects.size();
  CObjectInterface::ObjectSet Requested;

  for (; pPropensityObject != pPropensityObjectEnd; ++pPropensityObject)
    {
      Requested.insert(pPropensityObject);
    }

  CObjectInterface::ObjectSet Changed;
  CMathObject * pTimeObject = mpContainer->getMathObject(mpContainerStateTime);
  pPropensityObject = mPropensityObjects.array();

  for (; pReaction  != pReactionEnd; ++pReaction, ++pUpdateSequence, ++pPropensityObject)
    {
      Changed = pReaction->getChangedObjects();

      // The time is always updated
      Changed.insert(pTimeObject);

      pUpdateSequence->clear();
      mpContainer->getTransientDependencies().getUpdateSequence(*pUpdateSequence, CCore::SimulationContext::Default, Changed, Requested);
    }

  mNumReactionSpecies = mpContainer->getCountIndependentSpecies() + mpContainer->getCountDependentSpecies();
  mFirstReactionSpeciesIndex = mpContainer->getCountFixedEventTargets() + 1 /* Time */ + mpContainer->getCountODEs();

  C_FLOAT64 * pSpecies = mContainerState.array() + mFirstReactionSpeciesIndex;
  C_FLOAT64 * pSpeciesEnd = pSpecies + mNumReactionSpecies;

  for (; pSpecies != pSpeciesEnd; ++pSpecies)
    {
      *pSpecies = floor(*pSpecies + 0.5);
    }

  // The container state is now up to date we just need to calculate all values needed for simulation.
  mpContainer->updateSimulatedValues(false); //for assignments

  pPropensityObject = mPropensityObjects.array();
  C_FLOAT64 * pAmu = mAmu.array();
  mA0 = 0.0;

  // Update the propensity
  for (; pPropensityObject != pPropensityObjectEnd; ++pPropensityObject, ++pAmu)
    {
      pPropensityObject->calculateValue();
      mA0 += *pAmu;
    }

  mMaxStepsReached = false;
  mNextReactionTime = *mpContainerStateTime;
  mNextReactionIndex = C_INVALID_INDEX;

  setupDependencyGraph();

  initMethod();
}

size_t CStochMethod::generateReactionIndex()
{
  C_FLOAT64 sum = 0.0;
  C_FLOAT64 rand = mpRandomGenerator->getRandomOO() * mA0;

  const C_FLOAT64 * pAmu = mAmu.array();
  const C_FLOAT64 * pAmuEnd = pAmu + mNumReactions;

  for (; (sum < rand) && (pAmu != pAmuEnd); ++pAmu, ++mNextReactionIndex)
    {
      sum += *pAmu;
    }

  mNextReactionIndex--;

  return mNextReactionIndex;
}

C_FLOAT64 CStochMethod::generateReactionTime()
{
  if (mA0 == 0) return std::numeric_limits<C_FLOAT64>::infinity();

  C_FLOAT64 rand2 = mpRandomGenerator->getRandomOO();
  return - 1 * log(rand2) / mA0;
}

C_FLOAT64 CStochMethod::generateReactionTime(size_t reaction_index)
{
  if (mAmu[reaction_index] == 0) return std::numeric_limits<C_FLOAT64>::infinity();

  C_FLOAT64 rand2 = mpRandomGenerator->getRandomOO();
  return - 1 * log(rand2) / mAmu[reaction_index];
}

void CStochMethod::setupDependencyGraph()
{
  mDG.clear();

  mDG.resize(mNumReactions);
  // We build the dependency graph based on the information in mUpdateSequences which
  // includes time dependencies.
  const CCore::CUpdateSequence * pUpdateSequence = mUpdateSequences.array();
  const CCore::CUpdateSequence * pUpdateSequenceEnd = pUpdateSequence + mUpdateSequences.size();

  const CMathObject * pPropensity = mPropensityObjects.array();
  const CMathObject * pPropensityEnd = pPropensity + mPropensityObjects.size();

  for (size_t i = 0; pUpdateSequence < pUpdateSequenceEnd; ++pUpdateSequence, ++i)
    {
      pPropensity = mPropensityObjects.array();

      for (size_t j = 0; pPropensity != pPropensityEnd; ++pPropensity, ++j)
        {
          CCore::CUpdateSequence::const_iterator it = pUpdateSequence->begin();
          CCore::CUpdateSequence::const_iterator end = pUpdateSequence->end();

          for (; it != end; ++it)
            {
              if (*it == pPropensity)
                {
                  mDG.addDependent(i, j);
                  break;
                }
            }
        }
    }
}

//virtual
bool CStochMethod::isValidProblem(const CCopasiProblem * pProblem)
{
  if (!CTrajectoryMethod::isValidProblem(pProblem)) return false;

  const CTrajectoryProblem * pTP = dynamic_cast<const CTrajectoryProblem *>(pProblem);

  if (pTP->getDuration() < 0.0)
    {
      //back integration not possible
      CCopasiMessage(CCopasiMessage::ERROR, MCTrajectoryMethod + 9);
      return false;
    }

  // check for ODEs
  if (mpContainer->getCountODEs() > 0)
    {
      CCopasiMessage(CCopasiMessage::ERROR, MCTrajectoryMethod + 28);
    }

  //TODO: rewrite CModel::suitableForStochasticSimulation() to use
  //      CCopasiMessage
  std::string message = mpContainer->getModel().suitableForStochasticSimulation();

  if (message != "")
    {
      //model not suitable, message describes the problem
      CCopasiMessage(CCopasiMessage::ERROR, message.c_str());
      return false;
    }

  if (getValue< C_INT32 >("Max Internal Steps") <= 0)
    {
      //max steps should be at least 1
      CCopasiMessage(CCopasiMessage::ERROR, MCTrajectoryMethod + 15);
      return false;
    }

  return true;
}
<commit_msg>- binary search to improve the setting up of dependency graph in Gibson and Bruck<commit_after>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2002 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#ifdef WIN32
# pragma warning (disable: 4786)
# pragma warning (disable: 4243)
// warning C4355: 'this' : used in base member initializer list
# pragma warning (disable: 4355)
#endif  // WIN32

#include <limits.h>

#include <vector>
#include <numeric>
#include <limits>
#include <set>

#include "copasi.h"
#include "CStochMethod.h"
#include "CStochDirectMethod.h"
#include "CStochNextReactionMethod.h"
#include "copasi/core/CDataVector.h"
#include "function/CFunction.h"
#include "randomGenerator/CRandom.h"
#include "CTrajectoryMethod.h"
#include "CTrajectoryProblem.h"
#include "math/CMathContainer.h"
#include "math/CMathReaction.h"
#include "model/CModel.h"

C_INT32 CStochMethod::checkModel(CModel * C_UNUSED(pmodel))
{
  // Here several checks will be performed to validate the model
  return 2; // suggest next reaction method
}

CStochMethod::CStochMethod(const CDataContainer * pParent,
                           const CTaskEnum::Method & methodType,
                           const CTaskEnum::Task & taskType):
  CTrajectoryMethod(pParent, methodType, taskType),
  mpRandomGenerator(NULL),
  mA0(0.0),
  mNumReactions(0),
  mReactions(),
  mPropensityObjects(),
  mAmu(),
  mUpdateSequences(),
  mMaxSteps(0),
  mMaxStepsReached(false),
  mNextReactionTime(0.0),
  mNextReactionIndex(C_INVALID_INDEX),
  mNumReactionSpecies(0),
  mFirstReactionSpeciesIndex(C_INVALID_INDEX),
  mDG()
{
  initializeParameter();
  mpRandomGenerator = CRandom::createGenerator(CRandom::mt19937);
}

CStochMethod::CStochMethod(const CStochMethod & src,
                           const CDataContainer * pParent):
  CTrajectoryMethod(src, pParent),
  mpRandomGenerator(NULL),
  mA0(0.0),
  mNumReactions(0),
  mReactions(),
  mPropensityObjects(),
  mAmu(),
  mUpdateSequences(),
  mMaxSteps(0),
  mMaxStepsReached(false),
  mNextReactionTime(0.0),
  mNextReactionIndex(C_INVALID_INDEX),
  mNumReactionSpecies(0),
  mFirstReactionSpeciesIndex(C_INVALID_INDEX),
  mDG()
{
  initializeParameter();
  mpRandomGenerator = CRandom::createGenerator(CRandom::mt19937);
}

CStochMethod::~CStochMethod()
{}

void CStochMethod::initializeParameter()
{
  CCopasiParameter *pParm;

  assertParameter("Max Internal Steps", CCopasiParameter::INT, (C_INT32) 1000000);
  assertParameter("Subtype", CCopasiParameter::UINT, (unsigned C_INT32) 2);
  assertParameter("Use Random Seed", CCopasiParameter::BOOL, false);
  assertParameter("Random Seed", CCopasiParameter::UINT, (unsigned C_INT32) 1);

  // Check whether we have a method with the old parameter names
  if ((pParm = getParameter("STOCH.MaxSteps")) != NULL)
    {
      setValue("Max Internal Steps", pParm->getValue< C_INT32 >());
      removeParameter("STOCH.MaxSteps");

      if ((pParm = getParameter("STOCH.Subtype")) != NULL)
        {
          setValue("Subtype", pParm->getValue< unsigned C_INT32 >());
          removeParameter("STOCH.Subtype");
        }

      if ((pParm = getParameter("STOCH.UseRandomSeed")) != NULL)
        {
          setValue("Use Random Seed", pParm->getValue< bool >());
          removeParameter("STOCH.UseRandomSeed");
        }

      if ((pParm = getParameter("STOCH.RandomSeed")) != NULL)
        {
          setValue("Random Seed", pParm->getValue< unsigned C_INT32 >());
          removeParameter("STOCH.RandomSeed");
        }
    }
}

bool CStochMethod::elevateChildren()
{
  initializeParameter();
  return true;
}

CTrajectoryMethod::Status CStochMethod::step(const double & deltaT,
    const bool & /* final */)
{
  // write the current state to the model:
  //mpProblem->getModel()->setState(mpCurrentState); //?

  // check for possible overflows:

  // do several steps:
  C_FLOAT64 time = *mpContainerStateTime;
  C_FLOAT64 endtime = time + deltaT;

  size_t Steps = 0;

  while (time < endtime)
    {
      time = doSingleStep(time, endtime);
      *mpContainerStateTime = time;

      if (++Steps > mMaxSteps)
        {
          CCopasiMessage(CCopasiMessage::EXCEPTION, MCTrajectoryMethod + 12);
        }

      if (mpProblem->getAutomaticStepSize()) break;
    }

  *mpContainerStateTime = time;

  return NORMAL;
}

void CStochMethod::start()
{
  CTrajectoryMethod::start();

  mpRandomGenerator = &mpContainer->getRandomGenerator();

  bool useRandomSeed = getValue< bool >("Use Random Seed");
  unsigned C_INT32 randomSeed = getValue< unsigned C_INT32 >("Random Seed");

  if (useRandomSeed) mpRandomGenerator->initialize(randomSeed);

  mMaxSteps = getValue< C_INT32 >("Max Internal Steps");

  //initialize the vector of ints that contains the particle numbers
  //for the discrete simulation. This also floors all particle numbers in the model.

  // Size the arrays
  mReactions.initialize(mpContainer->getReactions());
  mNumReactions = mReactions.size();
  mAmu.initialize(mpContainer->getPropensities());
  mPropensityObjects.initialize(mAmu.size(), mpContainer->getMathObject(mAmu.array()));
  mUpdateSequences.resize(mNumReactions);

  CMathReaction * pReaction = mReactions.array();
  CMathReaction * pReactionEnd = pReaction + mNumReactions;
  CCore::CUpdateSequence * pUpdateSequence = mUpdateSequences.array();
  CMathObject * pPropensityObject = mPropensityObjects.array();
  CMathObject * pPropensityObjectEnd = pPropensityObject + mPropensityObjects.size();
  CObjectInterface::ObjectSet Requested;

  for (; pPropensityObject != pPropensityObjectEnd; ++pPropensityObject)
    {
      Requested.insert(pPropensityObject);
    }

  CObjectInterface::ObjectSet Changed;
  CMathObject * pTimeObject = mpContainer->getMathObject(mpContainerStateTime);
  pPropensityObject = mPropensityObjects.array();

  for (; pReaction  != pReactionEnd; ++pReaction, ++pUpdateSequence, ++pPropensityObject)
    {
      Changed = pReaction->getChangedObjects();

      // The time is always updated
      Changed.insert(pTimeObject);

      pUpdateSequence->clear();
      mpContainer->getTransientDependencies().getUpdateSequence(*pUpdateSequence, CCore::SimulationContext::Default, Changed, Requested);
    }

  mNumReactionSpecies = mpContainer->getCountIndependentSpecies() + mpContainer->getCountDependentSpecies();
  mFirstReactionSpeciesIndex = mpContainer->getCountFixedEventTargets() + 1 /* Time */ + mpContainer->getCountODEs();

  C_FLOAT64 * pSpecies = mContainerState.array() + mFirstReactionSpeciesIndex;
  C_FLOAT64 * pSpeciesEnd = pSpecies + mNumReactionSpecies;

  for (; pSpecies != pSpeciesEnd; ++pSpecies)
    {
      *pSpecies = floor(*pSpecies + 0.5);
    }

  // The container state is now up to date we just need to calculate all values needed for simulation.
  mpContainer->updateSimulatedValues(false); //for assignments

  pPropensityObject = mPropensityObjects.array();
  C_FLOAT64 * pAmu = mAmu.array();
  mA0 = 0.0;

  // Update the propensity
  for (; pPropensityObject != pPropensityObjectEnd; ++pPropensityObject, ++pAmu)
    {
      pPropensityObject->calculateValue();
      mA0 += *pAmu;
    }

  mMaxStepsReached = false;
  mNextReactionTime = *mpContainerStateTime;
  mNextReactionIndex = C_INVALID_INDEX;

  setupDependencyGraph();

  initMethod();
}

size_t CStochMethod::generateReactionIndex()
{
  C_FLOAT64 sum = 0.0;
  C_FLOAT64 rand = mpRandomGenerator->getRandomOO() * mA0;

  const C_FLOAT64 * pAmu = mAmu.array();
  const C_FLOAT64 * pAmuEnd = pAmu + mNumReactions;

  for (; (sum < rand) && (pAmu != pAmuEnd); ++pAmu, ++mNextReactionIndex)
    {
      sum += *pAmu;
    }

  mNextReactionIndex--;

  return mNextReactionIndex;
}

C_FLOAT64 CStochMethod::generateReactionTime()
{
  if (mA0 == 0) return std::numeric_limits<C_FLOAT64>::infinity();

  C_FLOAT64 rand2 = mpRandomGenerator->getRandomOO();
  return - 1 * log(rand2) / mA0;
}

C_FLOAT64 CStochMethod::generateReactionTime(size_t reaction_index)
{
  if (mAmu[reaction_index] == 0) return std::numeric_limits<C_FLOAT64>::infinity();

  C_FLOAT64 rand2 = mpRandomGenerator->getRandomOO();
  return - 1 * log(rand2) / mAmu[reaction_index];
}

void CStochMethod::setupDependencyGraph()
{
  mDG.clear();

  mDG.resize(mNumReactions);
  // We build the dependency graph based on the information in mUpdateSequences which
  // includes time dependencies.
  const CCore::CUpdateSequence * pUpdateSequence = mUpdateSequences.array();
  const CCore::CUpdateSequence * pUpdateSequenceEnd = pUpdateSequence + mUpdateSequences.size();

  const CMathObject * pPropensity = mPropensityObjects.array();
  const CMathObject * pPropensityEnd = pPropensity + mPropensityObjects.size();

  int idx = 0, idxMid = 0;
  int idxEnd = mPropensityObjects.size();

  for (size_t i = 0; pUpdateSequence < pUpdateSequenceEnd; ++pUpdateSequence, ++i)
    {
      CCore::CUpdateSequence::const_iterator it = pUpdateSequence->begin();
      CCore::CUpdateSequence::const_iterator end = pUpdateSequence->end();

      for (; it != end; ++it)
        {
          if (*it >= pPropensity && *it <= pPropensityEnd)
            {
              idx = 0;
              idxEnd = mPropensityObjects.size();

              while (idx <= idxEnd)
                {
                  idxMid = (idx + idxEnd) / 2;

                  if (*it == (pPropensity + idxMid))
                    {
                      mDG.addDependent(i, idxMid);
                      break;
                    }
                  else if (*it > (pPropensity + idxMid))
                    {
                      idx = (idxMid + 1);
                    }
                  else
                    {
                      idxEnd = (idxMid - 1);
                    }
                }
            }
        }
    }
}

//virtual
bool CStochMethod::isValidProblem(const CCopasiProblem * pProblem)
{
  if (!CTrajectoryMethod::isValidProblem(pProblem)) return false;

  const CTrajectoryProblem * pTP = dynamic_cast<const CTrajectoryProblem *>(pProblem);

  if (pTP->getDuration() < 0.0)
    {
      //back integration not possible
      CCopasiMessage(CCopasiMessage::ERROR, MCTrajectoryMethod + 9);
      return false;
    }

  // check for ODEs
  if (mpContainer->getCountODEs() > 0)
    {
      CCopasiMessage(CCopasiMessage::ERROR, MCTrajectoryMethod + 28);
    }

  //TODO: rewrite CModel::suitableForStochasticSimulation() to use
  //      CCopasiMessage
  std::string message = mpContainer->getModel().suitableForStochasticSimulation();

  if (message != "")
    {
      //model not suitable, message describes the problem
      CCopasiMessage(CCopasiMessage::ERROR, message.c_str());
      return false;
    }

  if (getValue< C_INT32 >("Max Internal Steps") <= 0)
    {
      //max steps should be at least 1
      CCopasiMessage(CCopasiMessage::ERROR, MCTrajectoryMethod + 15);
      return false;
    }

  return true;
}
<|endoftext|>