<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include "device.h"
#include "image.h"
#include <array>
#include <set>

using namespace rsimpl;

streaming_lock::streaming_lock()
    : _is_streaming(false),
      _callback(nullptr, [](rs_frame_callback*) {}),
      _archive(std::make_shared<frame_archive>(&_max_publish_list_size)),
      _max_publish_list_size(16), _owner(nullptr)
{

}

void streaming_lock::play(frame_callback_ptr callback)
{
    std::lock_guard<std::mutex> lock(_callback_mutex);
    _callback = std::move(callback);
    _is_streaming = true;
}

void streaming_lock::stop()
{
    _is_streaming = false;
    flush();
    std::lock_guard<std::mutex> lock(_callback_mutex);
    _callback.reset();
}

rs_frame* streaming_lock::alloc_frame(size_t size, frame_additional_data additional_data) const
{
    auto frame = _archive->alloc_frame(size, additional_data, true);
    return _archive->track_frame(frame);
}

void streaming_lock::invoke_callback(rs_frame* frame_ref) const
{
    if (frame_ref)
    {
        auto callback = _archive->begin_callback();
        try
        {
            if (_callback) _callback->on_frame(frame_ref);
        }
        catch(...)
        {
            LOG_ERROR("Exception was thrown during user callback!");
        }
    }
}

void streaming_lock::flush() const
{
    _archive->flush();
}

streaming_lock::~streaming_lock()
{
    try {
        streaming_lock::stop();
    }
    catch (...)
    {
        // TODO: Write to Log
    }
}

std::vector<stream_request> endpoint::get_principal_requests()
{
    std::unordered_set<stream_request> results;

    std::set<std::string> unutilized_formats;

    auto profiles = get_stream_profiles();
    for (auto&& p : profiles)
    {
        native_pixel_format pf;
        if (try_get_pf(p, pf))
        {
            for (auto&& unpacker : pf.unpackers)
            {
                for (auto&& output : unpacker.outputs)
                {
                    results.insert({ output.first, p.width, p.height, p.fps, output.second });
                }
            }
        }
        else
        {
            uint32_t device_fourcc = reinterpret_cast<const big_endian<uint32_t>&>(p.format);
            char fourcc[sizeof(device_fourcc) + 1];
            memcpy(fourcc, &device_fourcc, sizeof(device_fourcc));
            fourcc[sizeof(device_fourcc)] = 0;
            unutilized_formats.insert(fourcc);
        }
    }

    for (auto&& fourcc : unutilized_formats)
    {
        LOG_WARNING("Unutilized format " << fourcc << "!");
    }

    std::vector<stream_request> res{ begin(results), end(results) };
    std::sort(res.begin(), res.end(), [](const stream_request& a, const stream_request& b)
    {
        return a.width > b.width;
    });
    return res;
}

bool endpoint::try_get_pf(const uvc::stream_profile& p, native_pixel_format& result) const
{
    auto it = std::find_if(begin(_pixel_formats), end(_pixel_formats),
        [&p](const native_pixel_format& pf)
    {
        return pf.fourcc == p.format;
    });
    if (it != end(_pixel_formats))
    {
        result = *it;
        return true;
    }
    return false;
}

std::vector<request_mapping> endpoint::resolve_requests(std::vector<stream_request> requests)
{
    // TODO: Move to rsutil.hpp
    if (!auto_complete_request(requests))
    {
        throw std::runtime_error("Subdevice could not auto complete requests!");
    }

    std::vector<uint32_t> legal_4ccs;
    for (auto mode : get_stream_profiles()) {
        if (mode.fps == requests[0].fps && mode.height == requests[0].height && mode.width == requests[0].width)
            legal_4ccs.push_back(mode.format);
    }

    std::unordered_set<request_mapping> results;

    while (!requests.empty() && !_pixel_formats.empty())
    {
        auto max = 0;
        auto best_size = 0;
        auto best_pf = &_pixel_formats[0];
        auto best_unpacker = &_pixel_formats[0].unpackers[0];
        for (auto&& pf : _pixel_formats)
        {
            if (std::none_of(begin(legal_4ccs), end(legal_4ccs), [&](const uint32_t fourcc) {return fourcc == pf.fourcc; })) continue;
            for (auto&& unpacker : pf.unpackers)
            {
                auto count = static_cast<int>(std::count_if(begin(requests), end(requests),
                    [&unpacker](stream_request& r)
                {
                    return unpacker.satisfies(r);
                }));

                // Here we check if the current pixel format / unpacker combination is better than the current best.
                // We judge on two criteria. A: how many of the requested streams can we supply? B: how many total streams do we open?
                // Optimally, we want to find a combination that supplies all the requested streams, and no additional streams.
                if (
                    count > max                                 // If the current combination supplies more streams, it is better.
                    || (count == max                            // Alternatively, if it supplies the same number of streams,
                        && unpacker.outputs.size() < best_size) // but this combination opens fewer total streams, it is also better
                    )
                {
                    max = count;
                    best_size = unpacker.outputs.size();
                    best_pf = &pf;
                    best_unpacker = &unpacker;
                }
            }
        }

        if (max == 0) break;

        requests.erase(std::remove_if(begin(requests), end(requests),
            [best_unpacker, best_pf, &results, this](stream_request& r)
        {

            if (best_unpacker->satisfies(r))
            {
                request_mapping mapping;
                mapping.profile = { r.width, r.height, r.fps, best_pf->fourcc };
                mapping.unpacker = best_unpacker;
                mapping.pf = best_pf;

                results.insert(mapping);
                return true;
            }
            return false;
        }), end(requests));
    }

    if (requests.empty()) return{ begin(results), end(results) };

    throw std::runtime_error("Subdevice unable to satisfy stream requests!");
}

bool rsimpl::endpoint::auto_complete_request(std::vector<stream_request>& requests)
{
    for (stream_request& request : requests)
    {
        for (auto&& req : get_principal_requests())
        {
            if (req.match(request) && !req.contradicts(requests))
            {
                request = req;
                break;
            }
        }

        if (request.has_wildcards()) throw std::runtime_error("Subdevice auto complete the stream requests!");
    }
    return true;
}

std::vector<uvc::stream_profile> uvc_endpoint::init_stream_profiles()
{
    power on(shared_from_this());
    return _device->get_profiles();
}

std::shared_ptr<streaming_lock> uvc_endpoint::configure(
    const std::vector<stream_request>& requests)
{
    std::lock_guard<std::mutex> lock(_configure_lock);
    std::shared_ptr<uvc_streaming_lock> streaming(new uvc_streaming_lock(shared_from_this()));
    power on(shared_from_this());

    auto mapping = resolve_requests(requests);

    auto timestamp_readers = create_frame_timestamp_readers();
    auto timestamp_reader = timestamp_readers[0];

    for (auto& mode : mapping)
    {
        using namespace std::chrono;

        std::weak_ptr<uvc_streaming_lock> stream_ptr(streaming);

        auto start = high_resolution_clock::now();
        auto frame_number = 0;
        _device->play(mode.profile,
            [stream_ptr, mode, start, frame_number, timestamp_reader](uvc::stream_profile p, uvc::frame_object f) mutable
        {
            auto&& unpacker = *mode.unpacker;

            auto stream = stream_ptr.lock();
            if (stream && stream->is_streaming())
            {
                frame_continuation release_and_enqueue([]() {}, f.pixels);

                // Ignore any frames which appear corrupted or invalid
                if (!timestamp_reader->validate_frame(mode, f.pixels)) return;

                // Determine the timestamp for this frame
                auto timestamp = timestamp_reader->get_frame_timestamp(mode, f.pixels);
                auto frame_counter = timestamp_reader->get_frame_counter(mode, f.pixels);
                //auto received_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - capture_start_time).count();

                auto width = mode.profile.width;
                auto height = mode.profile.height;
                auto fps = mode.profile.fps;

                std::vector<byte *> dest;
                std::vector<rs_frame*> refs;

                auto now = high_resolution_clock::now();
                auto ms = duration_cast<milliseconds>(now - start);
                auto system_time = static_cast<double>(ms.count());

                //auto stride_x = mode_selection.get_stride_x();
                //auto stride_y = mode_selection.get_stride_y();
                /*for (auto&& output : unpacker.outputs)
                {
                    LOG_DEBUG("FrameAccepted, RecievedAt," << received_time
                        << ", FWTS," << timestamp << ", DLLTS," << received_time << ", Type," << rsimpl::get_string(output.first) << ",HasPair,0,F#," << frame_counter);
                }*/

                //frame_drops_status->was_initialized = true;

                // Not updating prev_frame_counter when first frame arrival
                /*if (frame_drops_status->was_initialized)
                {
                    frames_drops_counter.fetch_add(int(frame_counter - frame_drops_status->prev_frame_counter - 1));
                    frame_drops_status->prev_frame_counter = frame_counter;
                }*/

                for (auto&& output : unpacker.outputs)
                {
                    auto bpp = get_image_bpp(output.second);
                    frame_additional_data additional_data(timestamp,
                        frame_number++,
                        system_time,
                        width,
                        height,
                        fps,
                        width,
                        bpp,
                        output.second,
                        output.first);

                    auto frame_ref = stream->alloc_frame(width * height * bpp / 8, additional_data);
                    if (frame_ref)
                    {
                        refs.push_back(frame_ref);
                        dest.push_back(const_cast<byte*>(frame_ref->get()->get_frame_data()));
                    }

                    // Obtain buffers for unpacking the frame
                    //dest.push_back(archive->alloc_frame(output.first, additional_data, requires_processing));
                }

                // Unpack the frame
                //if (requires_processing)
                if (dest.size() > 0)
                {
                    unpacker.unpack(dest.data(), reinterpret_cast<const byte *>(f.pixels), width * height);
                }

                // If any frame callbacks were specified, dispatch them now
                for (auto&& pref : refs)
                {
                    stream->invoke_callback(pref);
                }
            }
        });
    }

    return std::move(streaming);
}

void uvc_endpoint::stop_streaming()
{
    std::lock_guard<std::mutex> lock(_configure_lock);
    for (auto& profile : _configuration)
    {
        _device->stop(profile);
    }
    _configuration.clear();
}

void uvc_endpoint::acquire_power()
{
    std::lock_guard<std::mutex> lock(_power_lock);
    if (!_user_count)
    {
        _device->set_power_state(uvc::D0);
        for (auto& xu : _xus) _device->init_xu(xu);
    }
    _user_count++;
}

void uvc_endpoint::release_power()
{
    std::lock_guard<std::mutex> lock(_power_lock);
    _user_count--;
    if (!_user_count) _device->set_power_state(uvc::D3);
}
<commit_msg>Add logic to disregard frames from garbage streams, deallocating them immediately instead of sending them to the user<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include "device.h"
#include "image.h"
#include <array>
#include <set>

using namespace rsimpl;

streaming_lock::streaming_lock()
    : _is_streaming(false),
      _callback(nullptr, [](rs_frame_callback*) {}),
      _archive(std::make_shared<frame_archive>(&_max_publish_list_size)),
      _max_publish_list_size(16), _owner(nullptr)
{

}

void streaming_lock::play(frame_callback_ptr callback)
{
    std::lock_guard<std::mutex> lock(_callback_mutex);
    _callback = std::move(callback);
    _is_streaming = true;
}

void streaming_lock::stop()
{
    _is_streaming = false;
    flush();
    std::lock_guard<std::mutex> lock(_callback_mutex);
    _callback.reset();
}

rs_frame* streaming_lock::alloc_frame(size_t size, frame_additional_data additional_data) const
{
    auto frame = _archive->alloc_frame(size, additional_data, true);
    return _archive->track_frame(frame);
}

void streaming_lock::invoke_callback(rs_frame* frame_ref) const
{
    if (frame_ref)
    {
        auto callback = _archive->begin_callback();
        try
        {
            if (_callback) _callback->on_frame(frame_ref);
        }
        catch(...)
        {
            LOG_ERROR("Exception was thrown during user callback!");
        }
    }
}

void streaming_lock::flush() const
{
    _archive->flush();
}

streaming_lock::~streaming_lock()
{
    try {
        streaming_lock::stop();
    }
    catch (...)
    {
        // TODO: Write to Log
    }
}

std::vector<stream_request> endpoint::get_principal_requests()
{
    std::unordered_set<stream_request> results;

    std::set<std::string> unutilized_formats;

    auto profiles = get_stream_profiles();
    for (auto&& p : profiles)
    {
        native_pixel_format pf;
        if (try_get_pf(p, pf))
        {
            for (auto&& unpacker : pf.unpackers)
            {
                for (auto&& output : unpacker.outputs)
                {
                    results.insert({ output.first, p.width, p.height, p.fps, output.second });
                }
            }
        }
        else
        {
            uint32_t device_fourcc = reinterpret_cast<const big_endian<uint32_t>&>(p.format);
            char fourcc[sizeof(device_fourcc) + 1];
            memcpy(fourcc, &device_fourcc, sizeof(device_fourcc));
            fourcc[sizeof(device_fourcc)] = 0;
            unutilized_formats.insert(fourcc);
        }
    }

    for (auto&& fourcc : unutilized_formats)
    {
        LOG_WARNING("Unutilized format " << fourcc << "!");
    }

    std::vector<stream_request> res{ begin(results), end(results) };
    std::sort(res.begin(), res.end(), [](const stream_request& a, const stream_request& b)
    {
        return a.width > b.width;
    });
    return res;
}

bool endpoint::try_get_pf(const uvc::stream_profile& p, native_pixel_format& result) const
{
    auto it = std::find_if(begin(_pixel_formats), end(_pixel_formats),
        [&p](const native_pixel_format& pf)
    {
        return pf.fourcc == p.format;
    });
    if (it != end(_pixel_formats))
    {
        result = *it;
        return true;
    }
    return false;
}

std::vector<request_mapping> endpoint::resolve_requests(std::vector<stream_request> requests)
{
    // TODO: Move to rsutil.hpp
    if (!auto_complete_request(requests))
    {
        throw std::runtime_error("Subdevice could not auto complete requests!");
    }

    std::vector<uint32_t> legal_4ccs;
    for (auto mode : get_stream_profiles()) {
        if (mode.fps == requests[0].fps && mode.height == requests[0].height && mode.width == requests[0].width)
            legal_4ccs.push_back(mode.format);
    }

    std::unordered_set<request_mapping> results;

    while (!requests.empty() && !_pixel_formats.empty())
    {
        auto max = 0;
        auto best_size = 0;
        auto best_pf = &_pixel_formats[0];
        auto best_unpacker = &_pixel_formats[0].unpackers[0];
        for (auto&& pf : _pixel_formats)
        {
            if (std::none_of(begin(legal_4ccs), end(legal_4ccs), [&](const uint32_t fourcc) {return fourcc == pf.fourcc; })) continue;
            for (auto&& unpacker : pf.unpackers)
            {
                auto count = static_cast<int>(std::count_if(begin(requests), end(requests),
                    [&unpacker](stream_request& r)
                {
                    return unpacker.satisfies(r);
                }));

                // Here we check if the current pixel format / unpacker combination is better than the current best.
                // We judge on two criteria. A: how many of the requested streams can we supply? B: how many total streams do we open?
                // Optimally, we want to find a combination that supplies all the requested streams, and no additional streams.
                if (
                    count > max                                 // If the current combination supplies more streams, it is better.
                    || (count == max                            // Alternatively, if it supplies the same number of streams,
                        && unpacker.outputs.size() < best_size) // but this combination opens fewer total streams, it is also better
                    )
                {
                    max = count;
                    best_size = unpacker.outputs.size();
                    best_pf = &pf;
                    best_unpacker = &unpacker;
                }
            }
        }

        if (max == 0) break;

        requests.erase(std::remove_if(begin(requests), end(requests),
            [best_unpacker, best_pf, &results, this](stream_request& r)
        {

            if (best_unpacker->satisfies(r))
            {
                request_mapping mapping;
                mapping.profile = { r.width, r.height, r.fps, best_pf->fourcc };
                mapping.unpacker = best_unpacker;
                mapping.pf = best_pf;

                results.insert(mapping);
                return true;
            }
            return false;
        }), end(requests));
    }

    if (requests.empty()) return{ begin(results), end(results) };

    throw std::runtime_error("Subdevice unable to satisfy stream requests!");
}

bool rsimpl::endpoint::auto_complete_request(std::vector<stream_request>& requests)
{
    for (stream_request& request : requests)
    {
        for (auto&& req : get_principal_requests())
        {
            if (req.match(request) && !req.contradicts(requests))
            {
                request = req;
                break;
            }
        }

        if (request.has_wildcards()) throw std::runtime_error("Subdevice auto complete the stream requests!");
    }
    return true;
}

std::vector<uvc::stream_profile> uvc_endpoint::init_stream_profiles()
{
    power on(shared_from_this());
    return _device->get_profiles();
}

std::shared_ptr<streaming_lock> uvc_endpoint::configure(
    const std::vector<stream_request>& requests)
{
    std::lock_guard<std::mutex> lock(_configure_lock);
    std::shared_ptr<uvc_streaming_lock> streaming(new uvc_streaming_lock(shared_from_this()));
    power on(shared_from_this());

    auto mapping = resolve_requests(requests);

    auto timestamp_readers = create_frame_timestamp_readers();
    auto timestamp_reader = timestamp_readers[0];

    for (auto& mode : mapping)
    {
        using namespace std::chrono;

        std::weak_ptr<uvc_streaming_lock> stream_ptr(streaming);

        auto start = high_resolution_clock::now();
        auto frame_number = 0;
        _device->play(mode.profile,
            [stream_ptr, mode, start, frame_number, timestamp_reader, requests](uvc::stream_profile p, uvc::frame_object f) mutable
        {
            auto&& unpacker = *mode.unpacker;

            auto stream = stream_ptr.lock();
            if (stream && stream->is_streaming())
            {
                frame_continuation release_and_enqueue([]() {}, f.pixels);

                // Ignore any frames which appear corrupted or invalid
                if (!timestamp_reader->validate_frame(mode, f.pixels)) return;

                // Determine the timestamp for this frame
                auto timestamp = timestamp_reader->get_frame_timestamp(mode, f.pixels);
                auto frame_counter = timestamp_reader->get_frame_counter(mode, f.pixels);
                //auto received_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - capture_start_time).count();

                auto width = mode.profile.width;
                auto height = mode.profile.height;
                auto fps = mode.profile.fps;

                std::vector<byte *> dest;
                std::vector<rs_frame*> refs;

                auto now = high_resolution_clock::now();
                auto ms = duration_cast<milliseconds>(now - start);
                auto system_time = static_cast<double>(ms.count());

                //auto stride_x = mode_selection.get_stride_x();
                //auto stride_y = mode_selection.get_stride_y();
                /*for (auto&& output : unpacker.outputs)
                {
                    LOG_DEBUG("FrameAccepted, RecievedAt," << received_time
                        << ", FWTS," << timestamp << ", DLLTS," << received_time << ", Type," << rsimpl::get_string(output.first) << ",HasPair,0,F#," << frame_counter);
                }*/

                //frame_drops_status->was_initialized = true;

                // Not updating prev_frame_counter when first frame arrival
                /*if (frame_drops_status->was_initialized)
                {
                    frames_drops_counter.fetch_add(int(frame_counter - frame_drops_status->prev_frame_counter - 1));
                    frame_drops_status->prev_frame_counter = frame_counter;
                }*/

                for (auto&& output : unpacker.outputs)
                {
                    auto bpp = get_image_bpp(output.second);
                    frame_additional_data additional_data(timestamp,
                        frame_number++,
                        system_time,
                        width,
                        height,
                        fps,
                        width,
                        bpp,
                        output.second,
                        output.first);

                    auto frame_ref = stream->alloc_frame(width * height * bpp / 8, additional_data);
                    if (frame_ref)
                    {
                        refs.push_back(frame_ref);
                        dest.push_back(const_cast<byte*>(frame_ref->get()->get_frame_data()));
                    }

                    // Obtain buffers for unpacking the frame
                    //dest.push_back(archive->alloc_frame(output.first, additional_data, requires_processing));
                }

                // Unpack the frame
                //if (requires_processing)
                if (dest.size() > 0)
                {
                    unpacker.unpack(dest.data(), reinterpret_cast<const byte *>(f.pixels), width * height);
                }

                // If any frame callbacks were specified, dispatch them now
                for (auto&& pref : refs)
                {
                    // all the streams the unpacker generates get here. If it matches one of the streams the user requested, dispatch it
                    if (std::any_of(begin(requests), end(requests), [&pref](stream_request request) { return request.stream == pref->get()->get_stream_type(); }))
                        stream->invoke_callback(pref);
                    // otherwise, the stream is a garbage stream we were forced to open, and we simply deallocate the frame.
                    else
                        pref->get()->get_owner()->release_frame_ref(pref);
                }
            }
        });
    }

    return std::move(streaming);
}

void uvc_endpoint::stop_streaming()
{
    std::lock_guard<std::mutex> lock(_configure_lock);
    for (auto& profile : _configuration)
    {
        _device->stop(profile);
    }
    _configuration.clear();
}

void uvc_endpoint::acquire_power()
{
    std::lock_guard<std::mutex> lock(_power_lock);
    if (!_user_count)
    {
        _device->set_power_state(uvc::D0);
        for (auto& xu : _xus) _device->init_xu(xu);
    }
    _user_count++;
}

void uvc_endpoint::release_power()
{
    std::lock_guard<std::mutex> lock(_power_lock);
    _user_count--;
    if (!_user_count) _device->set_power_state(uvc::D3);
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <sstream>
#include <vector>
#include <stdlib.h>
#include <Context.h>
#include <Filter.h>
#include <ViewText.h>
#include <CmdTags.h>
#include <text.h>
#include <i18n.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdTags::CmdTags ()
{
  _keyword     = "tags";
  _usage       = "task <filter> tags";
  _description = STRING_CMD_TAGS_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdTags::execute (std::string& output)
{
  int rc = 0;
  std::stringstream out;

  // Get all the tasks.
  std::vector <Task> tasks = context.tdb2.pending.get_tasks ();

  if (context.config.getBoolean ("list.all.tags"))
  {
    std::vector <Task> extra = context.tdb2.completed.get_tasks ();
    std::vector <Task>::iterator task;
    for (task = extra.begin (); task != extra.end (); ++task)
      tasks.push_back (*task);
  }

  int quantity = tasks.size ();

  // Apply filter.
  Filter filter;
  std::vector <Task> filtered;
  filter.subset (filtered);

  // Scan all the tasks for their project name, building a map using project
  // names as keys.
  std::map <std::string, int> unique;
  std::vector <Task>::iterator task;
  for (task = filtered.begin (); task != filtered.end (); ++task)
  {
    std::vector <std::string> tags;
    task->getTags (tags);

    std::vector <std::string>::iterator tag;
    for (tag = tags.begin (); tag != tags.end (); ++tag)
      if (unique.find (*tag) != unique.end ())
        unique[*tag]++;
      else
        unique[*tag] = 1;
  }

  if (unique.size ())
  {
    // Render a list of tags names from the map.
    ViewText view;
    view.width (context.getWidth ());
    view.add (Column::factory ("string", STRING_COLUMN_LABEL_TAG));
    view.add (Column::factory ("string.right", STRING_COLUMN_LABEL_COUNT));

    Color bold ("bold");
    bool special = false;
    std::map <std::string, int>::iterator i;
    for (i = unique.begin (); i != unique.end (); ++i)
    {
      // Highlight the special tags.
      special = (context.color () &&
                 (i->first == "nocolor" ||
                  i->first == "nonag"   ||
                  i->first == "nocal"   ||
                  i->first == "next")) ? true : false;

      int row = view.addRow ();
      view.set (row, 0, i->first,  special ? bold : Color ());
      view.set (row, 1, i->second, special ? bold : Color ());
    }

    out << optionalBlankLine ()
        << view.render ()
        << optionalBlankLine ();

    if (unique.size () == 1)
      context.footnote (STRING_CMD_TAGS_SINGLE);
    else
      context.footnote (format (STRING_CMD_TAGS_PLURAL, unique.size ()));

    if (quantity == 1)
      context.footnote (STRING_FEEDBACK_TASKS_SINGLE);
    else
      context.footnote (format (STRING_FEEDBACK_TASKS_PLURAL, quantity));

    out << "\n";
  }
  else
  {
    context.footnote (STRING_CMD_TAGS_NO_TAGS);
    rc = 1;
  }

  output = out.str ();
  return rc;
}

////////////////////////////////////////////////////////////////////////////////
CmdCompletionTags::CmdCompletionTags ()
{
  _keyword     = "_tags";
  _usage       = "task <filter> _tags";
  _description = STRING_CMD_COMTAGS_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdCompletionTags::execute (std::string& output)
{
  // Get all the tasks.
  std::vector <Task> tasks = context.tdb2.pending.get_tasks ();

  if (context.config.getBoolean ("complete.all.tags"))
  {
    std::vector <Task> extra = context.tdb2.completed.get_tasks ();
    std::vector <Task>::iterator task;
    for (task = extra.begin (); task != extra.end (); ++task)
      tasks.push_back (*task);
  }

  // Apply filter.
  Filter filter;
  std::vector <Task> filtered;
  filter.subset (filtered);

  // Scan all the tasks for their tags, building a map using tag
  // names as keys.
  std::map <std::string, int> unique;
  std::vector <Task>::iterator task;
  for (task = filtered.begin (); task != filtered.end (); ++task)
  {
    std::vector <std::string> tags;
    task->getTags (tags);

    std::vector <std::string>::iterator tag;
    for (tag = tags.begin (); tag != tags.end (); ++tag)
      unique[*tag] = 0;
  }

  // add built-in tags to map
  unique["nocolor"] = 0;
  unique["nonag"]   = 0;
  unique["nocal"]   = 0;
  unique["next"]    = 0;

  std::stringstream out;
  std::map <std::string, int>::iterator it;
  for (it = unique.begin (); it != unique.end (); ++it)
    out << it->first << "\n";

  output = out.str ();
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>CmdTags<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <sstream>
#include <vector>
#include <stdlib.h>
#include <Context.h>
#include <Filter.h>
#include <ViewText.h>
#include <CmdTags.h>
#include <text.h>
#include <i18n.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdTags::CmdTags ()
{
  _keyword     = "tags";
  _usage       = "task <filter> tags";
  _description = STRING_CMD_TAGS_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdTags::execute (std::string& output)
{
  int rc = 0;
  std::stringstream out;

  // Get all the tasks.
  std::vector <Task> tasks = context.tdb2.pending.get_tasks ();

  if (context.config.getBoolean ("list.all.tags"))
  {
    std::vector <Task> extra = context.tdb2.completed.get_tasks ();
    std::vector <Task>::iterator task;
    for (task = extra.begin (); task != extra.end (); ++task)
      tasks.push_back (*task);
  }

  int quantity = tasks.size ();

  // Apply filter.
  Filter filter;
  std::vector <Task> filtered;
  filter.subset (tasks, filtered);

  // Scan all the tasks for their project name, building a map using project
  // names as keys.
  std::map <std::string, int> unique;
  std::vector <Task>::iterator task;
  for (task = filtered.begin (); task != filtered.end (); ++task)
  {
    std::vector <std::string> tags;
    task->getTags (tags);

    std::vector <std::string>::iterator tag;
    for (tag = tags.begin (); tag != tags.end (); ++tag)
      if (unique.find (*tag) != unique.end ())
        unique[*tag]++;
      else
        unique[*tag] = 1;
  }

  if (unique.size ())
  {
    // Render a list of tags names from the map.
    ViewText view;
    view.width (context.getWidth ());
    view.add (Column::factory ("string", STRING_COLUMN_LABEL_TAG));
    view.add (Column::factory ("string.right", STRING_COLUMN_LABEL_COUNT));

    Color bold ("bold");
    bool special = false;
    std::map <std::string, int>::iterator i;
    for (i = unique.begin (); i != unique.end (); ++i)
    {
      // Highlight the special tags.
      special = (context.color () &&
                 (i->first == "nocolor" ||
                  i->first == "nonag"   ||
                  i->first == "nocal"   ||
                  i->first == "next")) ? true : false;

      int row = view.addRow ();
      view.set (row, 0, i->first,  special ? bold : Color ());
      view.set (row, 1, i->second, special ? bold : Color ());
    }

    out << optionalBlankLine ()
        << view.render ()
        << optionalBlankLine ();

    if (unique.size () == 1)
      context.footnote (STRING_CMD_TAGS_SINGLE);
    else
      context.footnote (format (STRING_CMD_TAGS_PLURAL, unique.size ()));

    if (quantity == 1)
      context.footnote (STRING_FEEDBACK_TASKS_SINGLE);
    else
      context.footnote (format (STRING_FEEDBACK_TASKS_PLURAL, quantity));

    out << "\n";
  }
  else
  {
    context.footnote (STRING_CMD_TAGS_NO_TAGS);
    rc = 1;
  }

  output = out.str ();
  return rc;
}

////////////////////////////////////////////////////////////////////////////////
CmdCompletionTags::CmdCompletionTags ()
{
  _keyword     = "_tags";
  _usage       = "task <filter> _tags";
  _description = STRING_CMD_COMTAGS_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdCompletionTags::execute (std::string& output)
{
  // Get all the tasks.
  std::vector <Task> tasks = context.tdb2.pending.get_tasks ();

  if (context.config.getBoolean ("complete.all.tags"))
  {
    std::vector <Task> extra = context.tdb2.completed.get_tasks ();
    std::vector <Task>::iterator task;
    for (task = extra.begin (); task != extra.end (); ++task)
      tasks.push_back (*task);
  }

  // Apply filter.
  Filter filter;
  std::vector <Task> filtered;
  filter.subset (filtered);

  // Scan all the tasks for their tags, building a map using tag
  // names as keys.
  std::map <std::string, int> unique;
  std::vector <Task>::iterator task;
  for (task = filtered.begin (); task != filtered.end (); ++task)
  {
    std::vector <std::string> tags;
    task->getTags (tags);

    std::vector <std::string>::iterator tag;
    for (tag = tags.begin (); tag != tags.end (); ++tag)
      unique[*tag] = 0;
  }

  // add built-in tags to map
  unique["nocolor"] = 0;
  unique["nonag"]   = 0;
  unique["nocal"]   = 0;
  unique["next"]    = 0;

  std::stringstream out;
  std::map <std::string, int>::iterator it;
  for (it = unique.begin (); it != unique.end (); ++it)
    out << it->first << "\n";

  output = out.str ();
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#ifndef VG_SURJECTOR_HPP_INCLUDED
#define VG_SURJECTOR_HPP_INCLUDED

/** \file
 *
 *  A class to hold surjection algorithms that do lossy realignment restricted to paths in the graph
 */

#include <set>

#include "alignment.hpp"
#include "aligner.hpp"
#include "vg.hpp"
#include "translator.hpp"
#include "utility.hpp"
#include <vg/vg.pb.h>
#include "multipath_alignment_graph.hpp"
#include "memoizing_graph.hpp"

#include "algorithms/topological_sort.hpp"
#include "algorithms/split_strands.hpp"

#include "bdsg/hash_graph.hpp"

namespace vg {

using namespace std;

    class Surjector : AlignerClient {
    public:

        Surjector(const PathPositionHandleGraph* graph);

        /// Extract the portions of an alignment that are on a chosen set of paths and try to
        /// align realign the portions that are off of the chosen paths to the intervening
        /// path segments to obtain an alignment that is fully restricted to the paths.
        ///
        /// Also returns the path name, position, and strand of the new alignment.
        ///
        /// Optionally either allow softclips so that the alignment has a nonnegative score on
        /// the path or require the full-length alignment, possibly creating a negative score.
        Alignment surject(const Alignment& source,
                          const set<string>& path_names,
                          string& path_name_out,
                          int64_t& path_pos_out,
                          bool& path_rev_out,
                          bool allow_negative_scores = false) const;

        /// Extract the portions of an alignment that are on a chosen set of
        /// paths and try to align realign the portions that are off of the
        /// chosen paths to the intervening path segments to obtain an
        /// alignment that is fully restricted to the paths.
        ///
        /// Replaces the alignment's refpos with the path name, position, and
        /// strand the alignment has been surjected to.
        ///
        /// Optionally either allow softclips so that the alignment has a
        /// nonnegative score on the path or require the full-length alignment,
        /// possibly creating a negative score.
        Alignment surject(const Alignment& source,
                          const set<string>& path_names,
                          bool allow_negative_scores = false) const;

        /// a local type that represents a read interval matched to a portion of the alignment path
        using path_chunk_t = pair<pair<string::const_iterator, string::const_iterator>, Path>;

    private:

        /// get the chunks of the alignment path that follow the given reference paths
        unordered_map<path_handle_t, vector<path_chunk_t>>
        extract_overlapping_paths(const PathPositionHandleGraph* graph, const Alignment& source,
                                  const unordered_set<path_handle_t>& surjection_paths) const;

        /// compute the widest interval of path positions that the realigned sequence could align to
        pair<size_t, size_t>
        compute_path_interval(const PathPositionHandleGraph* graph, const Alignment& source, path_handle_t path_handle,
                              const vector<path_chunk_t>& path_chunks) const;

        /// make a linear graph that corresponds to a path interval, possibly duplicating nodes in case of cycles
        unordered_map<id_t, pair<id_t, bool>>
        extract_linearized_path_graph(const PathPositionHandleGraph* graph, MutableHandleGraph* into,
                                      path_handle_t path_handle, size_t first, size_t last) const;

        /// associate a path position and strand to a surjected alignment against this path
        void set_path_position(const PathPositionHandleGraph* graph, const Alignment& surjected,
                               path_handle_t best_path_handle,
                               string& path_name_out, int64_t& path_pos_out, bool& path_rev_out) const;

        // make a sentinel meant to indicate an unmapped read
        static Alignment make_null_alignment(const Alignment& source);

        const PathPositionHandleGraph* graph;
    };
}

#endif
<commit_msg>edit documentation<commit_after>#ifndef VG_SURJECTOR_HPP_INCLUDED
#define VG_SURJECTOR_HPP_INCLUDED

/** \file
 *
 *  A class to hold surjection algorithms that do lossy realignment restricted to paths in the graph
 */

#include <set>

#include "alignment.hpp"
#include "aligner.hpp"
#include "vg.hpp"
#include "translator.hpp"
#include "utility.hpp"
#include <vg/vg.pb.h>
#include "multipath_alignment_graph.hpp"
#include "memoizing_graph.hpp"

#include "algorithms/topological_sort.hpp"
#include "algorithms/split_strands.hpp"

#include "bdsg/hash_graph.hpp"

namespace vg {

using namespace std;

    class Surjector : AlignerClient {
    public:

        Surjector(const PathPositionHandleGraph* graph);

        /// Extract the portions of an alignment that are on a chosen set of paths and try to
        /// align realign the portions that are off of the chosen paths to the intervening
        /// path segments to obtain an alignment that is fully restricted to the paths.
        ///
        /// Also returns the path name, position, and strand of the new alignment.
        ///
        /// Optionally either allow softclips so that the alignment has a nonnegative score on
        /// the path or require the full-length alignment, possibly creating a negative score.
        Alignment surject(const Alignment& source,
                          const set<string>& path_names,
                          string& path_name_out,
                          int64_t& path_pos_out,
                          bool& path_rev_out,
                          bool allow_negative_scores = false) const;

        /// Extract the portions of an alignment that are on a chosen set of
        /// paths and try to align realign the portions that are off of the
        /// chosen paths to the intervening path segments to obtain an
        /// alignment that is fully restricted to the paths.
        ///
        /// Replaces the alignment's refpos with the path name, position, and
        /// strand the alignment has been surjected to.
        ///
        /// Optionally either allow softclips so that the alignment has a
        /// nonnegative score on the path or require the full-length alignment,
        /// possibly creating a negative score.
        Alignment surject(const Alignment& source,
                          const set<string>& path_names,
                          bool allow_negative_scores = false) const;

        /// a local type that represents a read interval matched to a portion of the alignment path
        using path_chunk_t = pair<pair<string::const_iterator, string::const_iterator>, Path>;

    private:

        /// get the chunks of the alignment path that follow the given reference paths
        unordered_map<path_handle_t, vector<path_chunk_t>>
        extract_overlapping_paths(const PathPositionHandleGraph* graph, const Alignment& source,
                                  const unordered_set<path_handle_t>& surjection_paths) const;

        /// compute the widest interval of path positions that the realigned sequence could align to
        pair<size_t, size_t>
        compute_path_interval(const PathPositionHandleGraph* graph, const Alignment& source, path_handle_t path_handle,
                              const vector<path_chunk_t>& path_chunks) const;

        /// make a linear graph that corresponds to a path interval, possibly duplicating nodes in case of cycles
        unordered_map<id_t, pair<id_t, bool>>
        extract_linearized_path_graph(const PathPositionHandleGraph* graph, MutableHandleGraph* into,
                                      path_handle_t path_handle, size_t first, size_t last) const;

        /// associate a path position and strand to a surjected alignment against this path
        void set_path_position(const PathPositionHandleGraph* graph, const Alignment& surjected,
                               path_handle_t best_path_handle,
                               string& path_name_out, int64_t& path_pos_out, bool& path_rev_out) const;

        /// make a sentinel meant to indicate an unmapped read
        static Alignment make_null_alignment(const Alignment& source);

        /// the graph we're surjecting onto
        const PathPositionHandleGraph* graph = nullptr;
    };
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Christoph Bumiller
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "nv50_ir_graph.h"

namespace nv50_ir {

Graph::Graph()
{
   root = NULL;
   size = 0;
   sequence = 0;
}

Graph::~Graph()
{
   Iterator *iter = this->safeIteratorDFS();

   for (; !iter->end(); iter->next())
      reinterpret_cast<Node *>(iter->get())->cut();

   putIterator(iter);
}

void Graph::insert(Node *node)
{
   if (!root) {
      root = node;
      size = 1;
      node->graph = this;
   } else {
      root->attach(node, Edge::TREE);
   }
}

void Graph::Edge::unlink()
{
   if (origin) {
      prev[0]->next[0] = next[0];
      next[0]->prev[0] = prev[0];
      if (origin->out == this)
         origin->out = (next[0] == this) ? NULL : next[0];

      --origin->outCount;
   }
   if (target) {
      prev[1]->next[1] = next[1];
      next[1]->prev[1] = prev[1];
      if (target->in == this)
         target->in = (next[1] == this) ? NULL : next[1];

      --target->inCount;
   }
}

const char *Graph::Edge::typeStr() const
{
   switch (type) {
   case TREE:    return "tree";
   case FORWARD: return "forward";
   case BACK:    return "back";
   case CROSS:   return "cross";
   case DUMMY:   return "dummy";
   case UNKNOWN:
   default:
      return "unk";
   }
}

Graph::Node::Node(void *priv) : data(priv),
                                in(0), out(0), graph(0),
                                visited(0),
                                inCount(0), outCount(0)
{
   // nothing to do
}

void Graph::Node::attach(Node *node, Edge::Type kind)
{
   Edge *edge = new Edge(this, node, kind);

   // insert head
   if (this->out) {
      edge->next[0] = this->out;
      edge->prev[0] = this->out->prev[0];
      edge->prev[0]->next[0] = edge;
      this->out->prev[0] = edge;
   }
   this->out = edge;

   if (node->in) {
      edge->next[1] = node->in;
      edge->prev[1] = node->in->prev[1];
      edge->prev[1]->next[1] = edge;
      node->in->prev[1] = edge;
   }
   node->in = edge;

   ++this->outCount;
   ++node->inCount;

   assert(this->graph);
   if (!node->graph) {
      node->graph = this->graph;
      ++node->graph->size;
   }

   if (kind == Edge::UNKNOWN)
      graph->classifyEdges();
}

bool Graph::Node::detach(Graph::Node *node)
{
   EdgeIterator ei = this->outgoing();
   for (; !ei.end(); ei.next())
      if (ei.getNode() == node)
         break;
   if (ei.end()) {
      ERROR("no such node attached\n");
      return false;
   }
   delete ei.getEdge();
   return true;
}

// Cut a node from the graph, deleting all attached edges.
void Graph::Node::cut()
{
   if (!graph || (!in && !out))
      return;

   while (out)
      delete out;
   while (in)
      delete in;

   if (graph->root == this)
      graph->root = NULL;
}

Graph::Edge::Edge(Node *org, Node *tgt, Type kind)
{
   target = tgt;
   origin = org;
   type = kind;

   next[0] = next[1] = this;
   prev[0] = prev[1] = this;
}

bool
Graph::Node::reachableBy(Node *node, Node *term)
{
   Stack stack;
   Node *pos;
   const int seq = graph->nextSequence();

   stack.push(node);

   while (stack.getSize()) {
      pos = reinterpret_cast<Node *>(stack.pop().u.p);

      if (pos == this)
         return true;
      if (pos == term)
         continue;

      for (EdgeIterator ei = pos->outgoing(); !ei.end(); ei.next()) {
         if (ei.getType() == Edge::BACK || ei.getType() == Edge::DUMMY)
            continue;
         if (ei.getNode()->visit(seq))
            stack.push(ei.getNode());
      }
   }
   return pos == this;
}

class DFSIterator : public Graph::GraphIterator
{
public:
   DFSIterator(Graph *graph, const bool preorder)
   {
      unsigned int seq = graph->nextSequence();

      nodes = new Graph::Node * [graph->getSize() + 1];
      count = 0;
      pos = 0;
      nodes[graph->getSize()] = 0;

      if (graph->getRoot()) {
         graph->getRoot()->visit(seq);
         search(graph->getRoot(), preorder, seq);
      }
   }

   ~DFSIterator()
   {
      if (nodes)
         delete[] nodes;
   }

   void search(Graph::Node *node, const bool preorder, const int sequence)
   {
      if (preorder)
         nodes[count++] = node;

      for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next())
         if (ei.getNode()->visit(sequence))
            search(ei.getNode(), preorder, sequence);

      if (!preorder)
         nodes[count++] = node;
   }

   virtual bool end() const { return pos >= count; }
   virtual void next() { if (pos < count) ++pos; }
   virtual void *get() const { return nodes[pos]; }

   void reset() { pos = 0; }

protected:
   Graph::Node **nodes;
   int count;
   int pos;
};

Graph::GraphIterator *Graph::iteratorDFS(bool preorder)
{
   return new DFSIterator(this, preorder);
}

Graph::GraphIterator *Graph::safeIteratorDFS(bool preorder)
{
   return this->iteratorDFS(preorder);
}

class CFGIterator : public Graph::GraphIterator
{
public:
   CFGIterator(Graph *graph)
   {
      nodes = new Graph::Node * [graph->getSize() + 1];
      count = 0;
      pos = 0;
      nodes[graph->getSize()] = 0;

      // TODO: argh, use graph->sequence instead of tag and just raise it by > 1
      Iterator *iter;
      for (iter = graph->iteratorDFS(); !iter->end(); iter->next())
         reinterpret_cast<Graph::Node *>(iter->get())->tag = 0;
      graph->putIterator(iter);

      if (graph->getRoot())
         search(graph->getRoot(), graph->nextSequence());
   }

   ~CFGIterator()
   {
      if (nodes)
         delete[] nodes;
   }

   virtual void *get() const { return nodes[pos]; }
   virtual bool end() const { return pos >= count; }
   virtual void next() { if (pos < count) ++pos; }

private:
   void search(Graph::Node *node, const int sequence)
   {
      Stack bb, cross;

      bb.push(node);

      while (bb.getSize()) {
         node = reinterpret_cast<Graph::Node *>(bb.pop().u.p);
         assert(node);
         if (!node->visit(sequence))
            continue;
         node->tag = 0;

         for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next()) {
            switch (ei.getType()) {
            case Graph::Edge::TREE:
            case Graph::Edge::FORWARD:
            case Graph::Edge::DUMMY:
               if (++(ei.getNode()->tag) == ei.getNode()->incidentCountFwd())
                  bb.push(ei.getNode());
               break;
            case Graph::Edge::BACK:
               continue;
            case Graph::Edge::CROSS:
               if (++(ei.getNode()->tag) == 1)
                  cross.push(ei.getNode());
               break;
            default:
               assert(!"unknown edge kind in CFG");
               break;
            }
         }
         nodes[count++] = node;

         if (bb.getSize() == 0)
            cross.moveTo(bb);
      }
   }

private:
   Graph::Node **nodes;
   int count;
   int pos;
};

Graph::GraphIterator *Graph::iteratorCFG()
{
   return new CFGIterator(this);
}

Graph::GraphIterator *Graph::safeIteratorCFG()
{
   return this->iteratorCFG();
}

void Graph::classifyEdges()
{
   DFSIterator *iter;
   int seq;

   for (iter = new DFSIterator(this, true); !iter->end(); iter->next()) {
      Node *node = reinterpret_cast<Node *>(iter->get());
      node->visit(0);
      node->tag = 0;
   }
   putIterator(iter);

   classifyDFS(root, (seq = 0));

   sequence = seq;
}

void Graph::classifyDFS(Node *curr, int& seq)
{
   Graph::Edge *edge;
   Graph::Node *node;

   curr->visit(++seq);
   curr->tag = 1;

   for (edge = curr->out; edge; edge = edge->next[0]) {
      node = edge->target;
      if (edge->type == Edge::DUMMY)
         continue;

      if (node->getSequence() == 0) {
         edge->type = Edge::TREE;
         classifyDFS(node, seq);
      } else
      if (node->getSequence() > curr->getSequence()) {
         edge->type = Edge::FORWARD;
      } else {
         edge->type = node->tag ? Edge::BACK : Edge::CROSS;
      }
   }

   for (edge = curr->in; edge; edge = edge->next[1]) {
      node = edge->origin;
      if (edge->type == Edge::DUMMY)
         continue;

      if (node->getSequence() == 0) {
         edge->type = Edge::TREE;
         classifyDFS(node, seq);
      } else
      if (node->getSequence() > curr->getSequence()) {
         edge->type = Edge::FORWARD;
      } else {
         edge->type = node->tag ? Edge::BACK : Edge::CROSS;
      }
   }

   curr->tag = 0;
}

} // namespace nv50_ir
<commit_msg>nv50/ir: fix leak in removal of graph root<commit_after>/*
 * Copyright 2011 Christoph Bumiller
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "nv50_ir_graph.h"

namespace nv50_ir {

Graph::Graph()
{
   root = NULL;
   size = 0;
   sequence = 0;
}

Graph::~Graph()
{
   Iterator *iter = this->safeIteratorDFS();

   for (; !iter->end(); iter->next())
      reinterpret_cast<Node *>(iter->get())->cut();

   putIterator(iter);
}

void Graph::insert(Node *node)
{
   if (!root) {
      root = node;
      size = 1;
      node->graph = this;
   } else {
      root->attach(node, Edge::TREE);
   }
}

void Graph::Edge::unlink()
{
   if (origin) {
      prev[0]->next[0] = next[0];
      next[0]->prev[0] = prev[0];
      if (origin->out == this)
         origin->out = (next[0] == this) ? NULL : next[0];

      --origin->outCount;
   }
   if (target) {
      prev[1]->next[1] = next[1];
      next[1]->prev[1] = prev[1];
      if (target->in == this)
         target->in = (next[1] == this) ? NULL : next[1];

      --target->inCount;
   }
}

const char *Graph::Edge::typeStr() const
{
   switch (type) {
   case TREE:    return "tree";
   case FORWARD: return "forward";
   case BACK:    return "back";
   case CROSS:   return "cross";
   case DUMMY:   return "dummy";
   case UNKNOWN:
   default:
      return "unk";
   }
}

Graph::Node::Node(void *priv) : data(priv),
                                in(0), out(0), graph(0),
                                visited(0),
                                inCount(0), outCount(0)
{
   // nothing to do
}

void Graph::Node::attach(Node *node, Edge::Type kind)
{
   Edge *edge = new Edge(this, node, kind);

   // insert head
   if (this->out) {
      edge->next[0] = this->out;
      edge->prev[0] = this->out->prev[0];
      edge->prev[0]->next[0] = edge;
      this->out->prev[0] = edge;
   }
   this->out = edge;

   if (node->in) {
      edge->next[1] = node->in;
      edge->prev[1] = node->in->prev[1];
      edge->prev[1]->next[1] = edge;
      node->in->prev[1] = edge;
   }
   node->in = edge;

   ++this->outCount;
   ++node->inCount;

   assert(this->graph);
   if (!node->graph) {
      node->graph = this->graph;
      ++node->graph->size;
   }

   if (kind == Edge::UNKNOWN)
      graph->classifyEdges();
}

bool Graph::Node::detach(Graph::Node *node)
{
   EdgeIterator ei = this->outgoing();
   for (; !ei.end(); ei.next())
      if (ei.getNode() == node)
         break;
   if (ei.end()) {
      ERROR("no such node attached\n");
      return false;
   }
   delete ei.getEdge();
   return true;
}

// Cut a node from the graph, deleting all attached edges.
void Graph::Node::cut()
{
   while (out)
      delete out;
   while (in)
      delete in;

   if (graph) {
      if (graph->root == this)
         graph->root = NULL;
      graph = NULL;
   }
}

Graph::Edge::Edge(Node *org, Node *tgt, Type kind)
{
   target = tgt;
   origin = org;
   type = kind;

   next[0] = next[1] = this;
   prev[0] = prev[1] = this;
}

bool
Graph::Node::reachableBy(Node *node, Node *term)
{
   Stack stack;
   Node *pos;
   const int seq = graph->nextSequence();

   stack.push(node);

   while (stack.getSize()) {
      pos = reinterpret_cast<Node *>(stack.pop().u.p);

      if (pos == this)
         return true;
      if (pos == term)
         continue;

      for (EdgeIterator ei = pos->outgoing(); !ei.end(); ei.next()) {
         if (ei.getType() == Edge::BACK || ei.getType() == Edge::DUMMY)
            continue;
         if (ei.getNode()->visit(seq))
            stack.push(ei.getNode());
      }
   }
   return pos == this;
}

class DFSIterator : public Graph::GraphIterator
{
public:
   DFSIterator(Graph *graph, const bool preorder)
   {
      unsigned int seq = graph->nextSequence();

      nodes = new Graph::Node * [graph->getSize() + 1];
      count = 0;
      pos = 0;
      nodes[graph->getSize()] = 0;

      if (graph->getRoot()) {
         graph->getRoot()->visit(seq);
         search(graph->getRoot(), preorder, seq);
      }
   }

   ~DFSIterator()
   {
      if (nodes)
         delete[] nodes;
   }

   void search(Graph::Node *node, const bool preorder, const int sequence)
   {
      if (preorder)
         nodes[count++] = node;

      for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next())
         if (ei.getNode()->visit(sequence))
            search(ei.getNode(), preorder, sequence);

      if (!preorder)
         nodes[count++] = node;
   }

   virtual bool end() const { return pos >= count; }
   virtual void next() { if (pos < count) ++pos; }
   virtual void *get() const { return nodes[pos]; }

   void reset() { pos = 0; }

protected:
   Graph::Node **nodes;
   int count;
   int pos;
};

Graph::GraphIterator *Graph::iteratorDFS(bool preorder)
{
   return new DFSIterator(this, preorder);
}

Graph::GraphIterator *Graph::safeIteratorDFS(bool preorder)
{
   return this->iteratorDFS(preorder);
}

class CFGIterator : public Graph::GraphIterator
{
public:
   CFGIterator(Graph *graph)
   {
      nodes = new Graph::Node * [graph->getSize() + 1];
      count = 0;
      pos = 0;
      nodes[graph->getSize()] = 0;

      // TODO: argh, use graph->sequence instead of tag and just raise it by > 1
      Iterator *iter;
      for (iter = graph->iteratorDFS(); !iter->end(); iter->next())
         reinterpret_cast<Graph::Node *>(iter->get())->tag = 0;
      graph->putIterator(iter);

      if (graph->getRoot())
         search(graph->getRoot(), graph->nextSequence());
   }

   ~CFGIterator()
   {
      if (nodes)
         delete[] nodes;
   }

   virtual void *get() const { return nodes[pos]; }
   virtual bool end() const { return pos >= count; }
   virtual void next() { if (pos < count) ++pos; }

private:
   void search(Graph::Node *node, const int sequence)
   {
      Stack bb, cross;

      bb.push(node);

      while (bb.getSize()) {
         node = reinterpret_cast<Graph::Node *>(bb.pop().u.p);
         assert(node);
         if (!node->visit(sequence))
            continue;
         node->tag = 0;

         for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next()) {
            switch (ei.getType()) {
            case Graph::Edge::TREE:
            case Graph::Edge::FORWARD:
            case Graph::Edge::DUMMY:
               if (++(ei.getNode()->tag) == ei.getNode()->incidentCountFwd())
                  bb.push(ei.getNode());
               break;
            case Graph::Edge::BACK:
               continue;
            case Graph::Edge::CROSS:
               if (++(ei.getNode()->tag) == 1)
                  cross.push(ei.getNode());
               break;
            default:
               assert(!"unknown edge kind in CFG");
               break;
            }
         }
         nodes[count++] = node;

         if (bb.getSize() == 0)
            cross.moveTo(bb);
      }
   }

private:
   Graph::Node **nodes;
   int count;
   int pos;
};

Graph::GraphIterator *Graph::iteratorCFG()
{
   return new CFGIterator(this);
}

Graph::GraphIterator *Graph::safeIteratorCFG()
{
   return this->iteratorCFG();
}

void Graph::classifyEdges()
{
   DFSIterator *iter;
   int seq;

   for (iter = new DFSIterator(this, true); !iter->end(); iter->next()) {
      Node *node = reinterpret_cast<Node *>(iter->get());
      node->visit(0);
      node->tag = 0;
   }
   putIterator(iter);

   classifyDFS(root, (seq = 0));

   sequence = seq;
}

void Graph::classifyDFS(Node *curr, int& seq)
{
   Graph::Edge *edge;
   Graph::Node *node;

   curr->visit(++seq);
   curr->tag = 1;

   for (edge = curr->out; edge; edge = edge->next[0]) {
      node = edge->target;
      if (edge->type == Edge::DUMMY)
         continue;

      if (node->getSequence() == 0) {
         edge->type = Edge::TREE;
         classifyDFS(node, seq);
      } else
      if (node->getSequence() > curr->getSequence()) {
         edge->type = Edge::FORWARD;
      } else {
         edge->type = node->tag ? Edge::BACK : Edge::CROSS;
      }
   }

   for (edge = curr->in; edge; edge = edge->next[1]) {
      node = edge->origin;
      if (edge->type == Edge::DUMMY)
         continue;

      if (node->getSequence() == 0) {
         edge->type = Edge::TREE;
         classifyDFS(node, seq);
      } else
      if (node->getSequence() > curr->getSequence()) {
         edge->type = Edge::FORWARD;
      } else {
         edge->type = node->tag ? Edge::BACK : Edge::CROSS;
      }
   }

   curr->tag = 0;
}

} // namespace nv50_ir
<|endoftext|>


<commit_before><commit_msg>FIX:  farmhash based hashing number bits computed incorrectly.<commit_after><|endoftext|>


<commit_before>#include    <cstdlib>
#include    <cmath>
#include    <fstream>
#include    <sstream>
#include    <iostream>
#include    <iomanip>
#include    <string>
#include    <vector>
#include    <algorithm>
#include    <exception>
#include    <sys/time.h>
#include    "modules/htmTree.h"
#include    "modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
    //// Initializations ---------------------------------------------
    srand48(1234); // Make sure we have reproducability
    check_args(argc);
    Time t, time; // t for global, time for local
    init_time(t);
    Feat F;
    MTL M;

    // Read parameters file //
    F.readInputFile(argv[1]);
    printFile(argv[1]);
    // Read Secretfile
    // Secret contains the identity of each target: QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF
    Gals Secret;
    init_time_at(time,"# reading Secret file",t);

        Secret=read_Secretfile(F.Secretfile,F);
    printf("# Read %d galaxies from %s \n",Secret.size(),F.Secretfile.c_str());
    print_time(time,"# ... took :");
    std::vector<int> count(10);
    count=count_galaxies(Secret);
    printf(" Number of galaxies by type, QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF\n");
    for(int i=0;i<8;i++){if(count[i]>0)printf (" type %d number  %d  \n",i, count[i]);}
    //read the three input fits files
    init_time_at(time,"# read target, SS, SF files",t);
    MTL Targ=read_MTLfile(F.Targfile,F,0,0);
    MTL SStars=read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF=read_MTLfile(F.SkyFfile,F,0,1);

    if(Targ.size() == 0) {
        std::cerr << "ERROR: No targets found in " << F.Targfile << std::endl;
        myexit(1);
    }

    print_time(time,"# ... took :");
    //combine the three input files
    M=Targ;
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" M size %d \n",M.size());
    F.Ngal=M.size();
    F.Ntarg=Secret.size();
    F.NSSAtars=SStars.size();
    F.NSkyF=SkyF.size();

    //establish priority classes
    init_time_at(time,"# establish priority clasess",t);
    assign_priority_class(M);
    std::vector <int> count_class(M.priority_list.size(),0);
    for(int i;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
        count_class[M[i].priority_class]+=1;
        }
    }
    for(int i;i<M.priority_list.size();++i){
        printf("  class %d  priority %d  number %d\n",i,M.priority_list[i],count_class[i]);
    }
    print_time(time,"# ... took :");

    // fiber positioners
    PP pp;
    pp.read_fiber_positions(F);
    F.Nfiber = pp.fp.size()/2;
    F.Npetal = max(pp.spectrom)+1;
    F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
    pp.get_neighbors(F);
    pp.compute_fibsofsp(F);
    printf("computed neighbors\n");
    std::cout.flush();
    //P tiles in order specified by surveyFile
    Plates P = read_plate_centers(F);
    F.Nplate=P.size();
    printf("# Read %d plates from %s and %d fibers from %s\n",F.Nplate,F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

    // Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
    F.cb = create_cb(); // cb=central body
    F.fh = create_fh(); // fh=fiber holder

    //// Collect available galaxies <-> tilefibers --------------------
    // HTM Tree of galaxies
    const double MinTreeSize = 0.01;
    init_time_at(time,"# Start building HTM tree",t);

    htmTree<struct target> T(M,MinTreeSize);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

    // For plates/fibers, collect available galaxies; done in parallel
    collect_galaxies_for_all(M,T,P,pp,F);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);
    // For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
    collect_available_tilefibers(M,P,F);

    //count number of galaxies in first pass and number not in first pass
   /*
    int totalg=0;
    int inside=0;
    int all_covered=0;
    for(int g=0;g<F.Ntarg;++g)if(M[g].av_tfs.size()>0)++all_covered;
    for(int g=0;g<F.Ntarg;++g){
        Plist v=M[g].av_tfs;
        int done=0;
        for(int i=0;i<v.size()&&done==0;++i){
            if(P[v[i].f].ipass==0){
                ++inside;
                done=1;
            }
        }
        ++totalg;
    }
    printf ("total = %d  inside = %d  covered  %d\n",totalg,inside, all_covered);
    */
    //results_on_inputs("doc/figs/",G,P,F,true);

    //// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);

    print_time(t,"# Start assignment at : ");

    // Make a plan ----------------------------------------------------
    // Plans whole survey without sky fibers, standard stars
    // assumes maximum number of observations needed for QSOs, LRGs

    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list
    //and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){

        bool not_done=true;
        for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){//fiber and therefore plate is used
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                                //and otherwise the position of plate j in list of used plates
                inv_count++;
            }
        }
    }
    F.NUsedplate=A.suborder.size();

    if(F.diagnose)diagnostic(M,Secret,F,A);

    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs

    // Smooth out distribution of free fibers, and increase the number of assignments

    for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
    for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
        redistribute_tf(M,P,pp,F,A,0);
    }
    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);
    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }
    if(F.diagnose)diagnostic(M,Secret,F,A);
    init_time_at(time,"# Begin real time assignment",t);

    //Execute plan, updating targets at intervals
    for(int i=0;i<F.pass_intervals.size();i++){
        printf(" i=%d interval %d \n",i,F.pass_intervals[i]);
    }
    std::vector <int> update_intervals=F.pass_intervals;
    update_intervals.push_back(F.NUsedplate);//to end intervals at last plate
    for(int i=0;i<update_intervals.size();++i){
        printf("i %d  update_interval %d\n",i, update_intervals[i]);
    }
    for(int i=0;i<update_intervals.size()-1;++i){//go plate by used plate
        int starter=update_intervals[i];
        printf("-- interval %d\n",i);
        for (int jused=starter; jused<update_intervals[i+1] && jused<A.suborder.size()-1; jused++) {
            printf(" jused = %d\n",jused);
            std::cout.flush();
            if (0<=jused-F.Analysis) {
                printf(" updating  jused = %d \n",jused);
                update_plan_from_one_obs(jused,Secret,M,P,pp,F,A);
            }
            else printf("\n no update\n");

            printf("did update\n");
            std::cout.flush();
            if (F.PlotPyplotTile && jused%F.PyplotInterval-1==0){
                printf("do pyplot  jused= %d\n",jused);
                std::cout.flush();
                pyplotTile(jused,"doc/figs",Secret,M,P,pp,F,A);
            }
            // Update corrects all future occurrences of wrong QSOs etc and tries to observe something else

        }
        printf("-- redistribute %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- improve %d\n",i);
        improve(M,P,pp,F,A,starter);
        printf("-- improve again %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- diagnose %d\n",i);
        if(F.diagnose)diagnostic(M,Secret,F,A);

    }
    // check on SS and SF

    printf("-- Checking SS/SF\n");
    List SS_hist=initList(11,0);
    List SF_hist=initList(41,0);
    for(int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        for (int p=0;p<F.Npetal;++p){
            int count_SS=0;
            int count_SF=0;
            for (int k=0;k<F.Nfbp;++k){
                int kk=pp.fibers_of_sp[p][k];
                int g=A.TF[j][kk];
                if(g!=-1 && M[g].SS)count_SS++;
                if(g!=-1 && M[g].SF)count_SF++;
            }
            SS_hist[count_SS]++;
            SF_hist[count_SF]++;
        }
    }
    printf(" SS distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SS_hist[i]);
    printf("\n %8d \n",SS_hist[10]);

    printf(" SF distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=10;i<20;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=20;i<30;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=30;i<40;i++)printf("%8d",SF_hist[i]);
    printf("\n %8d \n",SF_hist[40]);

    // Results -------------------------------------------------------
    if (F.PrintAscii){
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            write_FAtile_ascii(A.suborder[jused],F.outDir,M,P,pp,F,A);
        }
    }

    if (F.PrintFits) {
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            fa_write(A.suborder[jused],F.outDir,M,P,pp,F,A); // Write outpu
        }
    }

	display_results("doc/figs/",Secret,M,P,pp,F,A,F.Nplate,true);
	if (F.Verif) A.verif(P,M,pp,F); // Verification that the assignment is sane

    print_time(t,"# Finished !... in");

    return(0);

}
<commit_msg>fix colors for SS SF in pyplot<commit_after>#include    <cstdlib>
#include    <cmath>
#include    <fstream>
#include    <sstream>
#include    <iostream>
#include    <iomanip>
#include    <string>
#include    <vector>
#include    <algorithm>
#include    <exception>
#include    <sys/time.h>
#include    "modules/htmTree.h"
#include    "modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
    //// Initializations ---------------------------------------------
    srand48(1234); // Make sure we have reproducability
    check_args(argc);
    Time t, time; // t for global, time for local
    init_time(t);
    Feat F;
    MTL M;

    // Read parameters file //
    F.readInputFile(argv[1]);
    printFile(argv[1]);
    // Read Secretfile
    // Secret contains the identity of each target: QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF
    Gals Secret;
    init_time_at(time,"# reading Secret file",t);

        Secret=read_Secretfile(F.Secretfile,F);
    printf("# Read %d galaxies from %s \n",Secret.size(),F.Secretfile.c_str());
    print_time(time,"# ... took :");
    std::vector<int> count(10);
    count=count_galaxies(Secret);
    printf(" Number of galaxies by type, QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF\n");
    for(int i=0;i<8;i++){if(count[i]>0)printf (" type %d number  %d  \n",i, count[i]);}
    //read the three input fits files
    init_time_at(time,"# read target, SS, SF files",t);
    MTL Targ=read_MTLfile(F.Targfile,F,0,0);
    MTL SStars=read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF=read_MTLfile(F.SkyFfile,F,0,1);

    if(Targ.size() == 0) {
        std::cerr << "ERROR: No targets found in " << F.Targfile << std::endl;
        myexit(1);
    }

    print_time(time,"# ... took :");
    //combine the three input files
    M=Targ;
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" M size %d \n",M.size());
    F.Ngal=M.size();
    F.Ntarg=Secret.size();
    F.NSSatars=SStars.size();
    F.NSkyF=SkyF.size();

    //establish priority classes
    init_time_at(time,"# establish priority clasess",t);
    assign_priority_class(M);
    std::vector <int> count_class(M.priority_list.size(),0);
    for(int i;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
        count_class[M[i].priority_class]+=1;
        }
    }
    for(int i;i<M.priority_list.size();++i){
        printf("  class %d  priority %d  number %d\n",i,M.priority_list[i],count_class[i]);
    }
    print_time(time,"# ... took :");

    // fiber positioners
    PP pp;
    pp.read_fiber_positions(F);
    F.Nfiber = pp.fp.size()/2;
    F.Npetal = max(pp.spectrom)+1;
    F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
    pp.get_neighbors(F);
    pp.compute_fibsofsp(F);
    printf("computed neighbors\n");
    std::cout.flush();
    //P tiles in order specified by surveyFile
    Plates P = read_plate_centers(F);
    F.Nplate=P.size();
    printf("# Read %d plates from %s and %d fibers from %s\n",F.Nplate,F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

    // Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
    F.cb = create_cb(); // cb=central body
    F.fh = create_fh(); // fh=fiber holder

    //// Collect available galaxies <-> tilefibers --------------------
    // HTM Tree of galaxies
    const double MinTreeSize = 0.01;
    init_time_at(time,"# Start building HTM tree",t);

    htmTree<struct target> T(M,MinTreeSize);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

    // For plates/fibers, collect available galaxies; done in parallel
    collect_galaxies_for_all(M,T,P,pp,F);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);
    // For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
    collect_available_tilefibers(M,P,F);

    //count number of galaxies in first pass and number not in first pass
   /*
    int totalg=0;
    int inside=0;
    int all_covered=0;
    for(int g=0;g<F.Ntarg;++g)if(M[g].av_tfs.size()>0)++all_covered;
    for(int g=0;g<F.Ntarg;++g){
        Plist v=M[g].av_tfs;
        int done=0;
        for(int i=0;i<v.size()&&done==0;++i){
            if(P[v[i].f].ipass==0){
                ++inside;
                done=1;
            }
        }
        ++totalg;
    }
    printf ("total = %d  inside = %d  covered  %d\n",totalg,inside, all_covered);
    */
    //results_on_inputs("doc/figs/",G,P,F,true);

    //// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);

    print_time(t,"# Start assignment at : ");

    // Make a plan ----------------------------------------------------
    // Plans whole survey without sky fibers, standard stars
    // assumes maximum number of observations needed for QSOs, LRGs

    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list
    //and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){

        bool not_done=true;
        for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){//fiber and therefore plate is used
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                                //and otherwise the position of plate j in list of used plates
                inv_count++;
            }
        }
    }
    F.NUsedplate=A.suborder.size();

    if(F.diagnose)diagnostic(M,Secret,F,A);

    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs

    // Smooth out distribution of free fibers, and increase the number of assignments

    for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
    for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
        redistribute_tf(M,P,pp,F,A,0);
    }
    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);
    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }
    if(F.diagnose)diagnostic(M,Secret,F,A);
    init_time_at(time,"# Begin real time assignment",t);

    //Execute plan, updating targets at intervals
    for(int i=0;i<F.pass_intervals.size();i++){
        printf(" i=%d interval %d \n",i,F.pass_intervals[i]);
    }
    std::vector <int> update_intervals=F.pass_intervals;
    update_intervals.push_back(F.NUsedplate);//to end intervals at last plate
    for(int i=0;i<update_intervals.size();++i){
        printf("i %d  update_interval %d\n",i, update_intervals[i]);
    }
    for(int i=0;i<update_intervals.size()-1;++i){//go plate by used plate
        int starter=update_intervals[i];
        printf("-- interval %d\n",i);
        for (int jused=starter; jused<update_intervals[i+1] && jused<A.suborder.size()-1; jused++) {
            printf(" jused = %d\n",jused);
            std::cout.flush();
            if (0<=jused-F.Analysis) {
                printf(" updating  jused = %d \n",jused);
                update_plan_from_one_obs(jused,Secret,M,P,pp,F,A);
            }
            else printf("\n no update\n");

            printf("did update\n");
            std::cout.flush();
            if (F.PlotPyplotTile && jused%F.PyplotInterval-1==0){
                printf("do pyplot  jused= %d\n",jused);
                std::cout.flush();
                pyplotTile(jused,"doc/figs",Secret,M,P,pp,F,A);
            }
            // Update corrects all future occurrences of wrong QSOs etc and tries to observe something else

        }
        printf("-- redistribute %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- improve %d\n",i);
        improve(M,P,pp,F,A,starter);
        printf("-- improve again %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- diagnose %d\n",i);
        if(F.diagnose)diagnostic(M,Secret,F,A);

    }
    // check on SS and SF

    printf("-- Checking SS/SF\n");
    List SS_hist=initList(11,0);
    List SF_hist=initList(41,0);
    for(int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        for (int p=0;p<F.Npetal;++p){
            int count_SS=0;
            int count_SF=0;
            for (int k=0;k<F.Nfbp;++k){
                int kk=pp.fibers_of_sp[p][k];
                int g=A.TF[j][kk];
                if(g!=-1 && M[g].SS)count_SS++;
                if(g!=-1 && M[g].SF)count_SF++;
            }
            SS_hist[count_SS]++;
            SF_hist[count_SF]++;
        }
    }
    printf(" SS distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SS_hist[i]);
    printf("\n %8d \n",SS_hist[10]);

    printf(" SF distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=10;i<20;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=20;i<30;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=30;i<40;i++)printf("%8d",SF_hist[i]);
    printf("\n %8d \n",SF_hist[40]);

    // Results -------------------------------------------------------
    if (F.PrintAscii){
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            write_FAtile_ascii(A.suborder[jused],F.outDir,M,P,pp,F,A);
        }
    }

    if (F.PrintFits) {
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            fa_write(A.suborder[jused],F.outDir,M,P,pp,F,A); // Write outpu
        }
    }

	display_results("doc/figs/",Secret,M,P,pp,F,A,F.Nplate,true);
	if (F.Verif) A.verif(P,M,pp,F); // Verification that the assignment is sane

    print_time(t,"# Finished !... in");

    return(0);

}
<|endoftext|>