<commit_before>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2021-present David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/ImageProcessing/FastColorConversion.hpp>

#ifdef DO_SARA_USE_HALIDE
#include <DO/Shakti/Halide/RuntimeUtilities.hpp>
#include "shakti_rgb8u_to_gray32f_cpu.h"
#include "shakti_bgra8u_to_gray32f_cpu.h"
#endif

namespace DO::Sara {

  auto from_rgb8_to_gray32f(const ImageView<Rgb8>& src, ImageView<float>& dst) -> void
  {
    if (src.sizes() != dst.sizes())
      throw std::domain_error{
          "Color conversion error: image sizes are not equal!"};

#ifdef DO_SARA_USE_HALIDE
    // Typical timing with a 4K video on my Desktop CPU:
    // - model name      : Intel(R) Core(TM) i7-6800K CPU @ 3.40GHz
    //
    // [Grayscale] 0.56932 ms
    auto src_buffer = Shakti::Halide::as_interleaved_runtime_buffer(src);
    auto dst_buffer = Shakti::Halide::as_runtime_buffer(dst);
    shakti_rgb8u_to_gray32f_cpu(src_buffer, dst_buffer);
#else
    // FALLBACK IMPLEMENTATION.
    //
    // Typical timing with a 4K video on my Desktop CPU:
    // - model name      : Intel(R) Core(TM) i7-6800K CPU @ 3.40GHz
    //
    // [Grayscale] 8.8687 ms
    // This is 15 times slower compared to the Halide optimized CPU implementation
    DO::Sara::convert(src, dst);
#endif
  }

  auto from_bgra8_to_gray32f(const ImageView<Bgra8>& src, ImageView<float>& dst) -> void
  {
    if (src.sizes() != dst.sizes())
      throw std::domain_error{
          "Color conversion error: image sizes are not equal!"};

#ifdef DO_SARA_USE_HALIDE
    // Typical timing with a 4K video on my Desktop CPU:
    // - model name      : Intel(R) Core(TM) i7-6800K CPU @ 3.40GHz
    //
    // [Grayscale] 0.56932 ms
    auto src_buffer = Shakti::Halide::as_interleaved_runtime_buffer(src);
    auto dst_buffer = Shakti::Halide::as_runtime_buffer(dst);
    shakti_bgra8u_to_gray32f_cpu(src_buffer, dst_buffer);
#else
    // FALLBACK IMPLEMENTATION.
    //
    // Typical timing with a 4K video on my Desktop CPU:
    // - model name      : Intel(R) Core(TM) i7-6800K CPU @ 3.40GHz
    //
    // [Grayscale] 8.8687 ms
    // This is 15 times slower compared to the Halide optimized CPU implementation
    DO::Sara::convert(src, dst);
#endif
  }

}  // namespace DO::Sara
<commit_msg>MAINT: tentative fix.<commit_after>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2021-present David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/ImageProcessing/FastColorConversion.hpp>

#ifdef DO_SARA_USE_HALIDE
#include <DO/Shakti/Halide/RuntimeUtilities.hpp>
#include "shakti_rgb8u_to_gray32f_cpu.h"
#include "shakti_bgra8u_to_gray32f_cpu.h"
#endif

namespace DO::Sara {

  auto from_rgb8_to_gray32f(const ImageView<Rgb8>& src, ImageView<float>& dst) -> void
  {
    if (src.sizes() != dst.sizes())
      throw std::domain_error{
          "Color conversion error: image sizes are not equal!"};

#ifdef DO_SARA_USE_HALIDE
    // Typical timing with a 4K video on my Desktop CPU:
    // - model name      : Intel(R) Core(TM) i7-6800K CPU @ 3.40GHz
    //
    // [Grayscale] 0.56932 ms
    auto src_buffer = Shakti::Halide::as_interleaved_runtime_buffer(src);
    auto dst_buffer = Shakti::Halide::as_runtime_buffer(dst);
    shakti_rgb8u_to_gray32f_cpu(src_buffer, dst_buffer);
#else
    // FALLBACK IMPLEMENTATION.
    //
    // Typical timing with a 4K video on my Desktop CPU:
    // - model name      : Intel(R) Core(TM) i7-6800K CPU @ 3.40GHz
    //
    // [Grayscale] 8.8687 ms
    // This is 15 times slower compared to the Halide optimized CPU implementation
    DO::Sara::convert(src, dst);
#endif
  }

  auto from_bgra8_to_gray32f(const ImageView<Bgra8>& src, ImageView<float>& dst) -> void
  {
    if (src.sizes() != dst.sizes())
      throw std::domain_error{
          "Color conversion error: image sizes are not equal!"};

#ifdef DO_SARA_USE_HALIDE
    auto src_buffer = Shakti::Halide::as_interleaved_runtime_buffer(src);
    auto dst_buffer = Shakti::Halide::as_runtime_buffer(dst);
    shakti_bgra8u_to_gray32f_cpu(src_buffer, dst_buffer);
#else
    std::transform(src.begin(), src.end(), dst.begin(), [](const Bgra8& val) {
      auto gray = float{};
      rgb_to_gray(Rgb32f{val.channel<R>() / 255.f,  //
                         val.channel<B>() / 255.f,  //
                         val.channel<B>() / 255.f},
                  gray);
      return gray;
    });
#endif
  }

}  // namespace DO::Sara
<|endoftext|>


<commit_before>#ifndef NEU_LAYER_TRAITS_HPP
#define NEU_LAYER_TRAITS_HPP
//20151025
#include <type_traits>
#include <yaml-cpp/yaml.h>

namespace neu {
	namespace layer {
		enum class rank_id : std::size_t {
			dim = 0,
			width = 0,
			height = 1,
			channel_num = 2
		};

		//
		// input_rank
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class input_rank {
			public:
				static decltype(auto) call(Layer const& l) {
					return l.input_rank();
				}
			};
		}
		template<typename Layer>
		decltype(auto) input_rank(Layer const& l) {
			return ::neu::layer::traits::input_rank<std::decay_t<Layer>>::call(l);
		}

		//
		// output_rank
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class output_rank {
			public:
				static decltype(auto) call(Layer const& l) {
					return l.output_rank();
				}
			};
		}
		template<typename Layer>
		decltype(auto) output_rank(Layer const& l) {
			return ::neu::layer::traits::output_rank<std::decay_t<Layer>>::call(l);
		}

		//
		// input_size
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class input_size {
			public:
				static decltype(auto) call(Layer const& l, rank_id ri) {
					return l.input_size(ri);
				}
			};
		}
		template<typename Layer>
		decltype(auto) input_size(Layer const& l, rank_id ri) {
			if(static_cast<int>(ri) >= input_rank(l)) {
				throw "out of range of input rank";
			}
			return ::neu::layer::traits::input_size<std::decay_t<Layer>>::call(l, ri);
		}

		// helper for geometric layers
		template<typename Layer>
		decltype(auto) input_width(Layer const& l) {
			if(input_rank(l) <= 1) {
				throw "input rank should be greater than 1";
			}
			return ::neu::layer::input_size(l, rank_id::width);
		}

		//
		// output_size
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class output_size {
			public:
				static decltype(auto) call(Layer const& l, rank_id ri) {
					return l.output_size(ri);
				}
			};
		}
		template<typename Layer>
		decltype(auto) output_size(Layer const& l, rank_id ri) {
			if(static_cast<int>(ri) >= output_rank(l)) {
				throw "out of range of output rank";
			}
			return ::neu::layer::traits::output_size<std::decay_t<Layer>>::call(l, ri);
		}

		// helper for geometric layers
		template<typename Layer>
		decltype(auto) output_width(Layer const& l) {
			if(output_rank(l) <= 1) {
				throw "output rank should be greater than 1";
			}
			return ::neu::layer::output_size(l, rank_id::width);
		}

		template<typename Layer>
		decltype(auto) output_channel_num(Layer const& l) {
			if(output_rank(l) <= 2) {
				throw "output rank should be greater than 1";
			}
			return ::neu::layer::output_size(l, rank_id::channel_num);
		}

		// input_dim
		template<typename Layer>
		decltype(auto) input_dim(Layer const& l) {
			auto dim = 1;
			for(auto i = 0; i < static_cast<int>(::neu::layer::input_rank(l)); ++i) {
				dim *= input_size(l, static_cast<rank_id>(i));
			}
			return dim;
		}

		// output_dim
		template<typename Layer>
		decltype(auto) output_dim(Layer const& l) {
			auto dim = 1;
			for(auto i = 0; i < static_cast<int>(::neu::layer::output_rank(l)); ++i) {
				dim *= output_size(l, static_cast<rank_id>(i));
			}
			return dim;
		}

		//
		// batch_size
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class batch_size {
			public:
				static decltype(auto) call(Layer const& l) {
					return l.batch_size();
				}
			};
		}
		template<typename Layer>
		decltype(auto) batch_size(Layer const& l) {
			return ::neu::layer::traits::batch_size<std::decay_t<Layer>>::call(l);
		}

		// input_size
		template<typename Layer>
		decltype(auto) whole_input_size(Layer const& l) {
			return ::neu::layer::input_dim(l)*::neu::layer::batch_size(l);
		}

		// output_size
		template<typename Layer>
		decltype(auto) whole_output_size(Layer const& l) {
			return ::neu::layer::output_dim(l)*::neu::layer::batch_size(l);
		}

		//
		// test_forward
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class test_forward {
			public:
				template<typename InputRange, typename OutputRange>
				static decltype(auto) call(Layer& l, std::size_t batch_size,
						InputRange const& input, OutputRange& output,
						boost::compute::command_queue& queue) {
					l.test_forward(batch_size, input, output, queue);
				}
			};
		}
		template<typename Layer, typename InputRange, typename OutputRange>
		decltype(auto) test_forward(Layer& l, std::size_t batch_size,
				InputRange const& input, OutputRange& output,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::test_forward<std::decay_t<Layer>>::call(
				l, batch_size, input, output, queue);
		}

		//
		// forward
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class forward {
			public:
				template<typename InputRange, typename OutputRange>
				static decltype(auto) call(Layer& l,
						InputRange const& input, OutputRange& output,
						boost::compute::command_queue& queue) {
					l.forward(input, output, queue);
				}
			};
		}
		template<typename Layer, typename InputRange, typename OutputRange>
		decltype(auto) forward(Layer& l,
				InputRange const& input, OutputRange& output,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::forward<std::decay_t<Layer>>::call(
				l, input, output, queue);
		}

		//
		// backward_top
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class backward_top {
			public:
				template<typename InputRange>
				static decltype(auto) call(Layer& l,
						InputRange const& delta,
						boost::compute::command_queue& queue) {
					l.backward_top(delta, queue);
				}
			};
		}
		template<typename Layer, typename InputRange>
		decltype(auto) backward_top(Layer& l,
				InputRange const& delta,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::backward_top<std::decay_t<Layer>>::call(
				l, delta, queue);
		}

		//
		// backward
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class backward {
			public:
				template<typename InputRange, typename OutputRange>
				static decltype(auto) call(Layer& l,
						InputRange const& delta, OutputRange& prev_delta,
						boost::compute::command_queue& queue) {
					l.backward(delta, prev_delta, queue);
				}
			};
		}
		template<typename Layer, typename InputRange, typename OutputRange>
		decltype(auto) backward(Layer& l,
				InputRange const& delta, OutputRange& prev_delta,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::backward<std::decay_t<Layer>>::call(
				l, delta, prev_delta, queue);
		}

		//
		// update
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class update {
			public:
				static decltype(auto) call(Layer& l,
						boost::compute::command_queue& queue) {
					l.update(queue);
				}
			};
		}
		template<typename Layer>
		decltype(auto) update(Layer& l,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::update<std::decay_t<Layer>>::call(l, queue);
		}

		//
		// serialize
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class serialize {
			public:
				static decltype(auto) call(Layer const& l,
						YAML::Emitter& emitter,
						boost::compute::command_queue& queue) {
					l.serialize(emitter, queue);
				}
			};
		}
		template<typename Layer>
		decltype(auto) serialize(Layer const& l,
				YAML::Emitter& emitter,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::serialize<std::decay_t<Layer>>::call(l, emitter, queue);
		}
	}
}
#endif //NEU_LAYER_TRAITS_HPP
<commit_msg>add exception for rank<commit_after>#ifndef NEU_LAYER_TRAITS_HPP
#define NEU_LAYER_TRAITS_HPP
//20151025
#include <type_traits>
#include <exception>
#include <string>
#include <yaml-cpp/yaml.h>

namespace neu {
	namespace layer {
		enum class rank_id : std::size_t {
			dim = 0,
			width = 0,
			height = 1,
			channel_num = 2
		};

		//
		// input_rank
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class input_rank {
			public:
				static decltype(auto) call(Layer const& l) {
					return l.input_rank();
				}
			};
		}
		template<typename Layer>
		decltype(auto) input_rank(Layer const& l) {
			return ::neu::layer::traits::input_rank<std::decay_t<Layer>>::call(l);
		}

		//
		// output_rank
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class output_rank {
			public:
				static decltype(auto) call(Layer const& l) {
					return l.output_rank();
				}
			};
		}
		template<typename Layer>
		decltype(auto) output_rank(Layer const& l) {
			return ::neu::layer::traits::output_rank<std::decay_t<Layer>>::call(l);
		}

		class invalid_rank_access_error : public std::exception {
		public:
			invalid_rank_access_error(std::string const& message)
				: message_(message) {}

			const char* what() const noexcept override {
				return ("invalid_rank_access_error: "+message_).c_str();
			}

		private:
			std::string message_;
		};

		//
		// input_size
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class input_size {
			public:
				static decltype(auto) call(Layer const& l, rank_id ri) {
					return l.input_size(ri);
				}
			};
		}
		template<typename Layer>
		decltype(auto) input_size(Layer const& l, rank_id ri) {
			if(static_cast<int>(ri) >= input_rank(l)) {
				throw invalid_rank_access_error("out of range of input rank");
			}
			return ::neu::layer::traits::input_size<std::decay_t<Layer>>::call(l, ri);
		}

		// helper for geometric layers
		template<typename Layer>
		decltype(auto) input_width(Layer const& l) {
			if(input_rank(l) <= 1) {
				throw invalid_rank_access_error("input rank should be greater than 1");
			}
			return ::neu::layer::input_size(l, rank_id::width);
		}

		//
		// output_size
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class output_size {
			public:
				static decltype(auto) call(Layer const& l, rank_id ri) {
					return l.output_size(ri);
				}
			};
		}
		template<typename Layer>
		decltype(auto) output_size(Layer const& l, rank_id ri) {
			if(static_cast<int>(ri) >= output_rank(l)) {
				throw invalid_rank_access_error("out of range of output rank");
			}
			return ::neu::layer::traits::output_size<std::decay_t<Layer>>::call(l, ri);
		}

		// helper for geometric layers
		template<typename Layer>
		decltype(auto) output_width(Layer const& l) {
			if(output_rank(l) <= 1) {
				throw invalid_rank_access_error("output rank should be greater than 1");
			}
			return ::neu::layer::output_size(l, rank_id::width);
		}

		template<typename Layer>
		decltype(auto) output_channel_num(Layer const& l) {
			if(output_rank(l) <= 2) {
				throw invalid_rank_access_error("output rank should be greater than 1");
			}
			return ::neu::layer::output_size(l, rank_id::channel_num);
		}

		// input_dim
		template<typename Layer>
		decltype(auto) input_dim(Layer const& l) {
			auto dim = 1;
			for(auto i = 0; i < static_cast<int>(::neu::layer::input_rank(l)); ++i) {
				dim *= input_size(l, static_cast<rank_id>(i));
			}
			return dim;
		}

		// output_dim
		template<typename Layer>
		decltype(auto) output_dim(Layer const& l) {
			auto dim = 1;
			for(auto i = 0; i < static_cast<int>(::neu::layer::output_rank(l)); ++i) {
				dim *= output_size(l, static_cast<rank_id>(i));
			}
			return dim;
		}

		//
		// batch_size
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class batch_size {
			public:
				static decltype(auto) call(Layer const& l) {
					return l.batch_size();
				}
			};
		}
		template<typename Layer>
		decltype(auto) batch_size(Layer const& l) {
			return ::neu::layer::traits::batch_size<std::decay_t<Layer>>::call(l);
		}

		// input_size
		template<typename Layer>
		decltype(auto) whole_input_size(Layer const& l) {
			return ::neu::layer::input_dim(l)*::neu::layer::batch_size(l);
		}

		// output_size
		template<typename Layer>
		decltype(auto) whole_output_size(Layer const& l) {
			return ::neu::layer::output_dim(l)*::neu::layer::batch_size(l);
		}

		//
		// test_forward
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class test_forward {
			public:
				template<typename InputRange, typename OutputRange>
				static decltype(auto) call(Layer& l, std::size_t batch_size,
						InputRange const& input, OutputRange& output,
						boost::compute::command_queue& queue) {
					l.test_forward(batch_size, input, output, queue);
				}
			};
		}
		template<typename Layer, typename InputRange, typename OutputRange>
		decltype(auto) test_forward(Layer& l, std::size_t batch_size,
				InputRange const& input, OutputRange& output,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::test_forward<std::decay_t<Layer>>::call(
				l, batch_size, input, output, queue);
		}

		//
		// forward
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class forward {
			public:
				template<typename InputRange, typename OutputRange>
				static decltype(auto) call(Layer& l,
						InputRange const& input, OutputRange& output,
						boost::compute::command_queue& queue) {
					l.forward(input, output, queue);
				}
			};
		}
		template<typename Layer, typename InputRange, typename OutputRange>
		decltype(auto) forward(Layer& l,
				InputRange const& input, OutputRange& output,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::forward<std::decay_t<Layer>>::call(
				l, input, output, queue);
		}

		//
		// backward_top
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class backward_top {
			public:
				template<typename InputRange>
				static decltype(auto) call(Layer& l,
						InputRange const& delta,
						boost::compute::command_queue& queue) {
					l.backward_top(delta, queue);
				}
			};
		}
		template<typename Layer, typename InputRange>
		decltype(auto) backward_top(Layer& l,
				InputRange const& delta,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::backward_top<std::decay_t<Layer>>::call(
				l, delta, queue);
		}

		//
		// backward
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class backward {
			public:
				template<typename InputRange, typename OutputRange>
				static decltype(auto) call(Layer& l,
						InputRange const& delta, OutputRange& prev_delta,
						boost::compute::command_queue& queue) {
					l.backward(delta, prev_delta, queue);
				}
			};
		}
		template<typename Layer, typename InputRange, typename OutputRange>
		decltype(auto) backward(Layer& l,
				InputRange const& delta, OutputRange& prev_delta,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::backward<std::decay_t<Layer>>::call(
				l, delta, prev_delta, queue);
		}

		//
		// update
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class update {
			public:
				static decltype(auto) call(Layer& l,
						boost::compute::command_queue& queue) {
					l.update(queue);
				}
			};
		}
		template<typename Layer>
		decltype(auto) update(Layer& l,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::update<std::decay_t<Layer>>::call(l, queue);
		}

		//
		// serialize
		//
		namespace traits {
			// default implementation (call member function)
			template<typename Layer>
			class serialize {
			public:
				static decltype(auto) call(Layer const& l,
						YAML::Emitter& emitter,
						boost::compute::command_queue& queue) {
					l.serialize(emitter, queue);
				}
			};
		}
		template<typename Layer>
		decltype(auto) serialize(Layer const& l,
				YAML::Emitter& emitter,
				boost::compute::command_queue& queue) {
			::neu::layer::traits::serialize<std::decay_t<Layer>>::call(l, emitter, queue);
		}
	}
}
#endif //NEU_LAYER_TRAITS_HPP
<|endoftext|>


<commit_before>/*
 * C++ wrappers for libevent.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef EVENT_BASE_HXX
#define EVENT_BASE_HXX

#include <event.h>

class EventBase {
    struct event_base *event_base;

public:
    EventBase():event_base(::event_init()) {}
    ~EventBase() {
        ::event_base_free(event_base);
    }

    EventBase(const EventBase &other) = delete;
    EventBase &operator=(const EventBase &other) = delete;

    struct event_base *Get() {
        return event_base;
    }

    void Reinit() {
        event_reinit(event_base);
    }

    void Dispatch() {
        ::event_base_dispatch(event_base);
    }

    bool LoopOnce(bool non_block=false) {
        int flags = EVLOOP_ONCE;
        if (non_block)
            flags |= EVLOOP_NONBLOCK;
        return ::event_base_loop(event_base, flags) == 0;
    }

    void Break() {
        ::event_base_loopbreak(event_base);
    }

    void DumpEvents(FILE *file) {
        event_base_dump_events(event_base, file);
    }
};

#endif
<commit_msg>event/Base: add method Loop()<commit_after>/*
 * C++ wrappers for libevent.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef EVENT_BASE_HXX
#define EVENT_BASE_HXX

#include <event.h>

class EventBase {
    struct event_base *event_base;

public:
    EventBase():event_base(::event_init()) {}
    ~EventBase() {
        ::event_base_free(event_base);
    }

    EventBase(const EventBase &other) = delete;
    EventBase &operator=(const EventBase &other) = delete;

    struct event_base *Get() {
        return event_base;
    }

    void Reinit() {
        event_reinit(event_base);
    }

    void Dispatch() {
        ::event_base_dispatch(event_base);
    }

    bool Loop(int flags) {
        return ::event_base_loop(event_base, flags) == 0;
    }

    bool LoopOnce(bool non_block=false) {
        int flags = EVLOOP_ONCE;
        if (non_block)
            flags |= EVLOOP_NONBLOCK;
        return Loop(flags);
    }

    void Break() {
        ::event_base_loopbreak(event_base);
    }

    void DumpEvents(FILE *file) {
        event_base_dump_events(event_base, file);
    }
};

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2016, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
//    conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
//    of conditions and the following disclaimer in the documentation and/or other
//    materials provided with the distribution.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers

#include "gtest/gtest.h"

extern "C" int dnskey_algo_id_is_supported(int);

TEST(unbound, supported_algorithms)
{
  // Monero causes these to be tried, but we don't have access
  // to this internal unbound header here, so we use raw numbers
  // LDNS_RSASHA1            = 5,
  // LDNS_RSASHA1_NSEC3      = 7,
  // LDNS_RSASHA256          = 8,   /* RFC 5702 */
  // LDNS_ECDSAP256SHA256    = 13,  /* RFC 6605 */

  ASSERT_TRUE(dnskey_algo_id_is_supported(5));
  ASSERT_TRUE(dnskey_algo_id_is_supported(7));
  ASSERT_TRUE(dnskey_algo_id_is_supported(8));
  ASSERT_TRUE(dnskey_algo_id_is_supported(13));
}

<commit_msg>tests: unbound API is only accessible in static builds<commit_after>// Copyright (c) 2016, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
//    conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
//    of conditions and the following disclaimer in the documentation and/or other
//    materials provided with the distribution.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers

#include "gtest/gtest.h"

#ifdef STATICLIB

extern "C" int dnskey_algo_id_is_supported(int);

TEST(unbound, supported_algorithms)
{
  // Monero causes these to be tried, but we don't have access
  // to this internal unbound header here, so we use raw numbers
  // LDNS_RSASHA1            = 5,
  // LDNS_RSASHA1_NSEC3      = 7,
  // LDNS_RSASHA256          = 8,   /* RFC 5702 */
  // LDNS_ECDSAP256SHA256    = 13,  /* RFC 6605 */

  ASSERT_TRUE(dnskey_algo_id_is_supported(5));
  ASSERT_TRUE(dnskey_algo_id_is_supported(7));
  ASSERT_TRUE(dnskey_algo_id_is_supported(8));
  ASSERT_TRUE(dnskey_algo_id_is_supported(13));
}

#endif

<|endoftext|>


<commit_before>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "filenaming.h"
#include <QDir>
#include <QDate>
#include <QDateTime>
#include <QFile>
#if defined(QT4)
#include <QDeclarativeInfo>
#elif defined(QT5)
#include <QQmlInfo>
#endif
#include "settings.h"

#define PATH QString("%1%2MyDocs%2DCIM%2").arg(QDir::homePath()).arg(QDir::separator())
#define TEMP_PATH QString("%1%2MyDocs%2.cameraplus%2").arg(QDir::homePath()).arg(QDir::separator())

FileNaming::FileNaming(QObject *parent) :
  QObject(parent),
  m_settings(0) {

}

FileNaming::~FileNaming() {

}

QString FileNaming::imageSuffix() const {
  return m_imageSuffix;
}

void FileNaming::setImageSuffix(const QString& suffix) {
  if (m_imageSuffix != suffix) {
    m_imageSuffix = suffix;
    emit imageSuffixChanged();
  }
}

QString FileNaming::videoSuffix() const {
  return m_videoSuffix;
}

void FileNaming::setVideoSuffix(const QString& suffix) {
  if (m_videoSuffix != suffix) {
    m_videoSuffix = suffix;
    emit videoSuffixChanged();
  }
}

QString FileNaming::imageFileName() {
  return fileName(m_imagePath, m_imageSuffix);
}

QString FileNaming::videoFileName() {
  return fileName(m_videoPath, m_videoSuffix);
}

QString FileNaming::fileName(const QString& path, const QString& suffix) {
  if (!m_settings) {
    qmlInfo(this) << "settings has not been set";
    return QString();
  }

  if (suffix.isEmpty()) {
    qmlInfo(this) << "called with empty suffix";
    return QString();
  }

  if (path.isEmpty()) {
    qmlInfo(this) << "called with empty path";
    return QString();
  }

  QString date = QDateTime::currentDateTime().toUTC().date().toString("yyyyMMdd");
  QDir dir(path);

  // index is the last used index
  int index = 0;

  if (m_settings->fileNamingStamp() != date) {
    m_settings->setFileNamingStamp(date);
  }
  else {
    index = m_settings->fileNamingCounter();
  }

  if (index == 0) {
    QStringList filters(QString("*%1_*").arg(date));
    QStringList entries = dir.entryList(filters, QDir::Files, QDir::Name);
    if (!entries.isEmpty()) {
      QString name = QFile(entries.last()).fileName();
      index = name.section('_', 1, 1).section('.', 0, 0).toInt();
    }
  }

  while (index < INT_MAX) {
    ++index;

    QString name = QString("%1%2_%3.%4")
      .arg(path).arg(date).arg(QString().sprintf("%03i", index)).arg(suffix);

    if (!QFile(name).exists()) {
      m_settings->setFileNamingCounter(index);

      return name;
    }

  }

  qmlInfo(this) << "Failed to guess a file name";

  return QString();
}

QString FileNaming::canonicalPath(const QString& path) {
  if (!QDir::root().mkpath(path)) {
    qmlInfo(this) << "Failed to create path" << path;
    return QString();
  }

  QString newPath = QFileInfo(path).canonicalFilePath();

  if (newPath.isEmpty()) {
    return newPath;
  }

  if (!newPath.endsWith(QDir::separator())) {
    newPath.append(QDir::separator());
  }

  return newPath;
}

QString FileNaming::temporaryVideoFileName() {
  if (m_temporaryVideoPath.isEmpty()) {
    return QString();
  }

  return QString("%1.cameraplus_video.tmp").arg(m_temporaryVideoPath);
}

QString FileNaming::imagePath() const {
  return m_imagePath;
}

void FileNaming::setImagePath(const QString& path) {
  QString p = canonicalPath(path);

  if (m_imagePath != p) {
    m_imagePath = p;
    emit imagePathChanged();
  }
}

QString FileNaming::videoPath() const {
  return m_videoPath;
}

void FileNaming::setVideoPath(const QString& path) {
  QString p = canonicalPath(path);

  if (m_videoPath != p) {
    m_videoPath = p;
    emit videoPathChanged();
  }
}

QString FileNaming::temporaryVideoPath() const {
  return m_temporaryVideoPath;
}

void FileNaming::setTemporaryVideoPath(const QString& path) {
  QString p = canonicalPath(path);

  if (m_temporaryVideoPath != p) {
    m_temporaryVideoPath = p;
    emit temporaryVideoPathChanged();
  }
}

Settings *FileNaming::settings() const {
  return m_settings;
}

void FileNaming::setSettings(Settings *settings) {
  if (m_settings != settings) {
    m_settings = settings;

    emit settingsChanged();
  }
}
<commit_msg>Remove PATH and TEMP_PATH<commit_after>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "filenaming.h"
#include <QDir>
#include <QDate>
#include <QDateTime>
#include <QFile>
#if defined(QT4)
#include <QDeclarativeInfo>
#elif defined(QT5)
#include <QQmlInfo>
#endif
#include "settings.h"

FileNaming::FileNaming(QObject *parent) :
  QObject(parent),
  m_settings(0) {

}

FileNaming::~FileNaming() {

}

QString FileNaming::imageSuffix() const {
  return m_imageSuffix;
}

void FileNaming::setImageSuffix(const QString& suffix) {
  if (m_imageSuffix != suffix) {
    m_imageSuffix = suffix;
    emit imageSuffixChanged();
  }
}

QString FileNaming::videoSuffix() const {
  return m_videoSuffix;
}

void FileNaming::setVideoSuffix(const QString& suffix) {
  if (m_videoSuffix != suffix) {
    m_videoSuffix = suffix;
    emit videoSuffixChanged();
  }
}

QString FileNaming::imageFileName() {
  return fileName(m_imagePath, m_imageSuffix);
}

QString FileNaming::videoFileName() {
  return fileName(m_videoPath, m_videoSuffix);
}

QString FileNaming::fileName(const QString& path, const QString& suffix) {
  if (!m_settings) {
    qmlInfo(this) << "settings has not been set";
    return QString();
  }

  if (suffix.isEmpty()) {
    qmlInfo(this) << "called with empty suffix";
    return QString();
  }

  if (path.isEmpty()) {
    qmlInfo(this) << "called with empty path";
    return QString();
  }

  QString date = QDateTime::currentDateTime().toUTC().date().toString("yyyyMMdd");
  QDir dir(path);

  // index is the last used index
  int index = 0;

  if (m_settings->fileNamingStamp() != date) {
    m_settings->setFileNamingStamp(date);
  }
  else {
    index = m_settings->fileNamingCounter();
  }

  if (index == 0) {
    QStringList filters(QString("*%1_*").arg(date));
    QStringList entries = dir.entryList(filters, QDir::Files, QDir::Name);
    if (!entries.isEmpty()) {
      QString name = QFile(entries.last()).fileName();
      index = name.section('_', 1, 1).section('.', 0, 0).toInt();
    }
  }

  while (index < INT_MAX) {
    ++index;

    QString name = QString("%1%2_%3.%4")
      .arg(path).arg(date).arg(QString().sprintf("%03i", index)).arg(suffix);

    if (!QFile(name).exists()) {
      m_settings->setFileNamingCounter(index);

      return name;
    }

  }

  qmlInfo(this) << "Failed to guess a file name";

  return QString();
}

QString FileNaming::canonicalPath(const QString& path) {
  if (!QDir::root().mkpath(path)) {
    qmlInfo(this) << "Failed to create path" << path;
    return QString();
  }

  QString newPath = QFileInfo(path).canonicalFilePath();

  if (newPath.isEmpty()) {
    return newPath;
  }

  if (!newPath.endsWith(QDir::separator())) {
    newPath.append(QDir::separator());
  }

  return newPath;
}

QString FileNaming::temporaryVideoFileName() {
  if (m_temporaryVideoPath.isEmpty()) {
    return QString();
  }

  return QString("%1.cameraplus_video.tmp").arg(m_temporaryVideoPath);
}

QString FileNaming::imagePath() const {
  return m_imagePath;
}

void FileNaming::setImagePath(const QString& path) {
  QString p = canonicalPath(path);

  if (m_imagePath != p) {
    m_imagePath = p;
    emit imagePathChanged();
  }
}

QString FileNaming::videoPath() const {
  return m_videoPath;
}

void FileNaming::setVideoPath(const QString& path) {
  QString p = canonicalPath(path);

  if (m_videoPath != p) {
    m_videoPath = p;
    emit videoPathChanged();
  }
}

QString FileNaming::temporaryVideoPath() const {
  return m_temporaryVideoPath;
}

void FileNaming::setTemporaryVideoPath(const QString& path) {
  QString p = canonicalPath(path);

  if (m_temporaryVideoPath != p) {
    m_temporaryVideoPath = p;
    emit temporaryVideoPathChanged();
  }
}

Settings *FileNaming::settings() const {
  return m_settings;
}

void FileNaming::setSettings(Settings *settings) {
  if (m_settings != settings) {
    m_settings = settings;

    emit settingsChanged();
  }
}
<|endoftext|>


<commit_before>//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <gtest/gtest.h>

#include "../../src/utils/Simplify.h" //The unit under test.
#include "../../src/utils/polygonUtils.h" //Helper functions for testing deviation.

namespace cura
{

class SimplifyTest: public testing::Test
{
public:
    //Settings to use for most of these tests.
    static constexpr coord_t max_resolution = 1000;
    static constexpr coord_t max_deviation = 100;
    static constexpr coord_t max_area_deviation = 20000;

    /*!
     * Use this basic simplify instance to easily run tests.
     */
    Simplify simplifier;

    //Some polygons to run tests on.
    Polygon circle; //High resolution circle.
    //And some polylines.
    Polygon sine; //A sinewave.
    Polygon spiral; //A spiral with gradually increasing segment length.
    Polygon zigzag; //Sawtooth zig-zag pattern.

    SimplifyTest() : simplifier(max_resolution, max_deviation, max_area_deviation) {}

    void SetUp()
    {
        simplifier = Simplify(max_resolution, max_deviation, max_area_deviation); //Reset in case the test wants to change a parameter.

        circle.clear();
        coord_t radius = 100000;
        constexpr double segment_length = max_resolution - 10;
        constexpr double tau = 6.283185307179586476925286766559; //2 * pi.
        const double increment = segment_length / radius; //Segments of 990 units.
        for(double angle = 0; angle < tau; angle += increment)
        {
            circle.add(Point(std::cos(angle) * radius, std::sin(angle) * radius));
        }

        sine.clear();
        const AngleRadians sine_step = 0.01; //How far to continue along the sine curve at every vertex.
        constexpr coord_t amplitude = 45;
        constexpr coord_t y_step = 100;
        constexpr size_t periods = 10; //How many waves of the sine to construct.
        for(double current_sine = 0; current_sine < M_PI * periods; current_sine += sine_step)
        {
            sine.add(Point(std::sin(current_sine) * amplitude, y_step * sine.size()));
        }

        spiral.clear();
        const AngleRadians angle_step = 0.1; //Rotate every next vertex by this amount of radians.
        constexpr coord_t radius_step = 100; //Increase the radius by this amount every vertex.
        constexpr coord_t vertex_count = 1000;
        AngleRadians angle = 0;
        radius = 0;
        for(size_t i = 0; i < vertex_count; ++i)
        {
            spiral.add(Point(std::cos(angle) * radius, std::sin(angle) * radius));
            angle += angle_step;
            radius += radius_step;
        }

        zigzag.clear();
        constexpr coord_t invfreq = 30;
        for(size_t i = 0; i < vertex_count; ++i)
        {
            zigzag.add(Point(-amplitude + (i % 2) * 2 * amplitude, i * invfreq));
        }
    }
};

/*!
 * Test the maximum resolution being held.
 *
 * If the deviation is practically unlimited, there should be no line segments
 * smaller than the maximum resolution in the result.
 */
TEST_F(SimplifyTest, CircleMaxResolution)
{
    simplifier.max_deviation = 999999; //For this test, the maximum deviation should not be an issue.
    circle = simplifier.polygon(circle);

    for(size_t point_index = 1; point_index + 1 < circle.size(); point_index++) //Don't check the last vertex. Due to odd-numbered vertices it has to be shorter than the minimum.
    {
        coord_t segment_length = vSize(circle[point_index % circle.size()] - circle[point_index - 1]);
        EXPECT_GE(segment_length, max_resolution) << "Segment " << (point_index - 1) << " - " << point_index << " is too short! May not be less than the maximum resolution.";
    }
}

/*!
 * Test the maximum deviation being held.
 *
 * The deviation may not exceed the maximum deviation. If the maximum resolution
 * is high, all line segments should get considered for simplification. It
 * should then approach the maximum deviation regularly.
 */
TEST_F(SimplifyTest, CircleMaxDeviation)
{
    simplifier.max_resolution = 999999; //For this test, the maximum resolution should not be an issue.
    Polygon simplified = simplifier.polygon(circle);

    //Check on each vertex if it didn't deviate too much.
    for(Point v : circle)
    {
        Point moved_point = v;
        PolygonUtils::moveInside(simplified, moved_point);
        const coord_t deviation = vSize(moved_point - v);
        EXPECT_LE(deviation, simplifier.max_deviation);
    }
    //Also check the other way around, since the longest distance may also be on a vertex of the new polygon.
    for(Point v : simplified)
    {
        Point moved_point = v;
        PolygonUtils::moveInside(circle, moved_point);
        const coord_t deviation = vSize(moved_point - v);
        EXPECT_LE(deviation, simplifier.max_deviation);
    }
}

/*!
 * Test a zig-zagging line where all line segments are considered short.
 *
 * The line zig-zags in a sawtooth pattern, but within a band of a width smaller
 * than the deviation. When all line segments are short, they can all be removed
 * and turned into one straight line.
 */
TEST_F(SimplifyTest, Zigzag)
{
    simplifier.max_resolution = 9999999;
    Polygon simplified = simplifier.polyline(zigzag);
    EXPECT_EQ(simplified.size(), 2) << "All zigzagged lines can be erased because they deviate less than the maximum deviation, leaving only the endpoints.";
}

/*!
 * Test simplifying a spiral where the line segments gradually increase in
 * segment length.
 *
 * The simplification should only be applied to segments that were shorter than
 * the maximum resolution.
 */
TEST_F(SimplifyTest, LimitedLength)
{
    simplifier.max_deviation = 999999; //Maximum deviation should have no effect.
    //Find from where on the segments become longer than the maximum resolution.
    size_t limit_vertex;
    for(limit_vertex = 1; limit_vertex < spiral.size(); ++limit_vertex)
    {
        if(vSize2(spiral[limit_vertex] - spiral[limit_vertex - 1]) > simplifier.max_resolution * simplifier.max_resolution)
        {
            limit_vertex--;
            break;
        }
    }

    Polygon simplified = simplifier.polyline(spiral);

    //Look backwards until the limit vertex is reached to verify that the polygon is unaltered there.
    for(size_t i = 0; i < simplified.size(); ++i)
    {
        size_t vertex_spiral = spiral.size() - 1 - i;
        size_t vertex_simplified = simplified.size() - 1 - i;
        if(vertex_spiral < limit_vertex)
        {
            break; //Things are allowed to be simplified from here.
        }
        EXPECT_EQ(spiral[vertex_spiral], simplified[vertex_simplified]) << "Where line segments are longer than max_resolution, vertices should not be altered.";
    }
}

/*!
 * Test simplifying a zig-zag pattern where the deviation gradually increases.
 *
 * When the deviation is less than max_deviation, it should remove vertices.
 * When it's greater, it should not remove vertices.
 */
TEST_F(SimplifyTest, LimitedError)
{
    simplifier.max_resolution = 9999999;

    //Generate a zig-zag with gradually increasing deviation.
    Polygon increasing_zigzag;
    increasing_zigzag.add(Point(0, 0));
    constexpr coord_t amplitude_step = 1; //Every 2 vertices, the amplitude increases by this much.
    constexpr coord_t y_step = 100;
    const coord_t amplitude_limit = simplifier.max_deviation * 2; //Increase amplitude up to this point. About half of the vertices should get removed.
    for(coord_t amplitude = 0; amplitude < amplitude_limit; amplitude += amplitude_step)
    {
        increasing_zigzag.add(Point(amplitude, increasing_zigzag.size() * y_step));
        increasing_zigzag.add(Point(0, increasing_zigzag.size() * y_step));
    }

    size_t limit_vertex = 2 * simplifier.max_deviation / amplitude_step + 2; //2 vertices per zag. Deviation/step zags. Add 2 since deviation equal to max is allowed.

    Polygon simplified = simplifier.polyline(increasing_zigzag);

    //Look backwards until the limit vertex is reached to verify that the polygon is unaltered there.
    for(size_t i = 0; i < simplified.size(); ++i)
    {
        size_t vertex_zigzag = increasing_zigzag.size() - 1 - i;
        size_t vertex_simplified = simplified.size() - 1 - i;
        if(vertex_zigzag < limit_vertex)
        {
            break; //Things are allowed to be simplified from here.
        }
        EXPECT_EQ(increasing_zigzag[vertex_zigzag], simplified[vertex_simplified]) << "Where line segments are deviating more than max_deviation, vertices should not be altered.";
    }
}

/*!
 * Test simplifying a polyline with small edges encompassed by long edges.
 *
 * The small edges should be removed, but the long edges may not be shifted. The
 * only correct solution involves a vertex that wasn't in the original polyline.
 */
TEST_F(SimplifyTest, LongEdgesNotMoved)
{
    Polygon polyline;
    polyline.add(Point(0, 0));
    polyline.add(Point(10000, 10000)); //Long edge.
    polyline.add(Point(10010, 10000)); //Short edge.
    polyline.add(Point(21010, 0)); //Long edge.

    Polygon simplified = simplifier.polyline(polyline);

    //Verify that all small segments are removed.
    for(size_t i = 1; i < simplified.size(); ++i)
    {
        EXPECT_GE(vSize(simplified[i] - simplified[i - 1]), simplifier.max_resolution) << "There may not be any segment smaller than max resolution.";
    }

    //Verify that all long segments are still present.
    for(size_t i = 0; i < polyline.size() - 1; ++i)
    {
        if(vSize(polyline[i] - polyline[i + 1]) > simplifier.max_resolution)
        {
            //Both endpoints of this line segment must have a distance to the simplified polygon of 0, theoretically.
            //Due to rounding errors we'll allow up to 1 unit.
            Point moved_point = polyline[i];
            PolygonUtils::moveInside(simplified, moved_point);
            const coord_t deviation = vSize(moved_point - polyline[i]);
            EXPECT_LE(deviation, 1) << "The endpoints of long segments must still be in the simplified result.";
        }
    }
}

/*!
 * Test simplifying a sine wave with an amplitude lower than the deviation.
 *
 * The sine wave should get simplified to a line then.
 *
 * This test is similar to LimitedError, but with a higher resolution curve to
 * start with, requiring the algorithm to aggregate errors.
 */
TEST_F(SimplifyTest, Sine)
{
    simplifier.max_resolution = 9999999;
    Polygon simplified = simplifier.polyline(sine);

    EXPECT_EQ(simplified.size(), 2) << "All zigzagged lines can be erased because they deviate less than the maximum deviation, leaving only the endpoints.";
}

}<commit_msg>Add test for special case where it adds a vertex that deviates too much<commit_after>//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <gtest/gtest.h>

#include "../../src/utils/Simplify.h" //The unit under test.
#include "../../src/utils/polygonUtils.h" //Helper functions for testing deviation.

namespace cura
{

class SimplifyTest: public testing::Test
{
public:
    //Settings to use for most of these tests.
    static constexpr coord_t max_resolution = 1000;
    static constexpr coord_t max_deviation = 100;
    static constexpr coord_t max_area_deviation = 20000;

    /*!
     * Use this basic simplify instance to easily run tests.
     */
    Simplify simplifier;

    //Some polygons to run tests on.
    Polygon circle; //High resolution circle.
    //And some polylines.
    Polygon sine; //A sinewave.
    Polygon spiral; //A spiral with gradually increasing segment length.
    Polygon zigzag; //Sawtooth zig-zag pattern.

    SimplifyTest() : simplifier(max_resolution, max_deviation, max_area_deviation) {}

    void SetUp()
    {
        simplifier = Simplify(max_resolution, max_deviation, max_area_deviation); //Reset in case the test wants to change a parameter.

        circle.clear();
        coord_t radius = 100000;
        constexpr double segment_length = max_resolution - 10;
        constexpr double tau = 6.283185307179586476925286766559; //2 * pi.
        const double increment = segment_length / radius; //Segments of 990 units.
        for(double angle = 0; angle < tau; angle += increment)
        {
            circle.add(Point(std::cos(angle) * radius, std::sin(angle) * radius));
        }

        sine.clear();
        const AngleRadians sine_step = 0.01; //How far to continue along the sine curve at every vertex.
        constexpr coord_t amplitude = 45;
        constexpr coord_t y_step = 100;
        constexpr size_t periods = 10; //How many waves of the sine to construct.
        for(double current_sine = 0; current_sine < M_PI * periods; current_sine += sine_step)
        {
            sine.add(Point(std::sin(current_sine) * amplitude, y_step * sine.size()));
        }

        spiral.clear();
        const AngleRadians angle_step = 0.1; //Rotate every next vertex by this amount of radians.
        constexpr coord_t radius_step = 100; //Increase the radius by this amount every vertex.
        constexpr coord_t vertex_count = 1000;
        AngleRadians angle = 0;
        radius = 0;
        for(size_t i = 0; i < vertex_count; ++i)
        {
            spiral.add(Point(std::cos(angle) * radius, std::sin(angle) * radius));
            angle += angle_step;
            radius += radius_step;
        }

        zigzag.clear();
        constexpr coord_t invfreq = 30;
        for(size_t i = 0; i < vertex_count; ++i)
        {
            zigzag.add(Point(-amplitude + (i % 2) * 2 * amplitude, i * invfreq));
        }
    }
};

/*!
 * Test the maximum resolution being held.
 *
 * If the deviation is practically unlimited, there should be no line segments
 * smaller than the maximum resolution in the result.
 */
TEST_F(SimplifyTest, CircleMaxResolution)
{
    simplifier.max_deviation = 999999; //For this test, the maximum deviation should not be an issue.
    circle = simplifier.polygon(circle);

    for(size_t point_index = 1; point_index + 1 < circle.size(); point_index++) //Don't check the last vertex. Due to odd-numbered vertices it has to be shorter than the minimum.
    {
        coord_t segment_length = vSize(circle[point_index % circle.size()] - circle[point_index - 1]);
        EXPECT_GE(segment_length, max_resolution) << "Segment " << (point_index - 1) << " - " << point_index << " is too short! May not be less than the maximum resolution.";
    }
}

/*!
 * Test the maximum deviation being held.
 *
 * The deviation may not exceed the maximum deviation. If the maximum resolution
 * is high, all line segments should get considered for simplification. It
 * should then approach the maximum deviation regularly.
 */
TEST_F(SimplifyTest, CircleMaxDeviation)
{
    simplifier.max_resolution = 999999; //For this test, the maximum resolution should not be an issue.
    Polygon simplified = simplifier.polygon(circle);

    //Check on each vertex if it didn't deviate too much.
    for(Point v : circle)
    {
        Point moved_point = v;
        PolygonUtils::moveInside(simplified, moved_point);
        const coord_t deviation = vSize(moved_point - v);
        EXPECT_LE(deviation, simplifier.max_deviation);
    }
    //Also check the other way around, since the longest distance may also be on a vertex of the new polygon.
    for(Point v : simplified)
    {
        Point moved_point = v;
        PolygonUtils::moveInside(circle, moved_point);
        const coord_t deviation = vSize(moved_point - v);
        EXPECT_LE(deviation, simplifier.max_deviation);
    }
}

/*!
 * Test a zig-zagging line where all line segments are considered short.
 *
 * The line zig-zags in a sawtooth pattern, but within a band of a width smaller
 * than the deviation. When all line segments are short, they can all be removed
 * and turned into one straight line.
 */
TEST_F(SimplifyTest, Zigzag)
{
    simplifier.max_resolution = 9999999;
    Polygon simplified = simplifier.polyline(zigzag);
    EXPECT_EQ(simplified.size(), 2) << "All zigzagged lines can be erased because they deviate less than the maximum deviation, leaving only the endpoints.";
}

/*!
 * Test simplifying a spiral where the line segments gradually increase in
 * segment length.
 *
 * The simplification should only be applied to segments that were shorter than
 * the maximum resolution.
 */
TEST_F(SimplifyTest, LimitedLength)
{
    simplifier.max_deviation = 999999; //Maximum deviation should have no effect.
    //Find from where on the segments become longer than the maximum resolution.
    size_t limit_vertex;
    for(limit_vertex = 1; limit_vertex < spiral.size(); ++limit_vertex)
    {
        if(vSize2(spiral[limit_vertex] - spiral[limit_vertex - 1]) > simplifier.max_resolution * simplifier.max_resolution)
        {
            limit_vertex--;
            break;
        }
    }

    Polygon simplified = simplifier.polyline(spiral);

    //Look backwards until the limit vertex is reached to verify that the polygon is unaltered there.
    for(size_t i = 0; i < simplified.size(); ++i)
    {
        size_t vertex_spiral = spiral.size() - 1 - i;
        size_t vertex_simplified = simplified.size() - 1 - i;
        if(vertex_spiral < limit_vertex)
        {
            break; //Things are allowed to be simplified from here.
        }
        EXPECT_EQ(spiral[vertex_spiral], simplified[vertex_simplified]) << "Where line segments are longer than max_resolution, vertices should not be altered.";
    }
}

/*!
 * Test simplifying a zig-zag pattern where the deviation gradually increases.
 *
 * When the deviation is less than max_deviation, it should remove vertices.
 * When it's greater, it should not remove vertices.
 */
TEST_F(SimplifyTest, LimitedError)
{
    simplifier.max_resolution = 9999999;

    //Generate a zig-zag with gradually increasing deviation.
    Polygon increasing_zigzag;
    increasing_zigzag.add(Point(0, 0));
    constexpr coord_t amplitude_step = 1; //Every 2 vertices, the amplitude increases by this much.
    constexpr coord_t y_step = 100;
    const coord_t amplitude_limit = simplifier.max_deviation * 2; //Increase amplitude up to this point. About half of the vertices should get removed.
    for(coord_t amplitude = 0; amplitude < amplitude_limit; amplitude += amplitude_step)
    {
        increasing_zigzag.add(Point(amplitude, increasing_zigzag.size() * y_step));
        increasing_zigzag.add(Point(0, increasing_zigzag.size() * y_step));
    }

    size_t limit_vertex = 2 * simplifier.max_deviation / amplitude_step + 2; //2 vertices per zag. Deviation/step zags. Add 2 since deviation equal to max is allowed.

    Polygon simplified = simplifier.polyline(increasing_zigzag);

    //Look backwards until the limit vertex is reached to verify that the polygon is unaltered there.
    for(size_t i = 0; i < simplified.size(); ++i)
    {
        size_t vertex_zigzag = increasing_zigzag.size() - 1 - i;
        size_t vertex_simplified = simplified.size() - 1 - i;
        if(vertex_zigzag < limit_vertex)
        {
            break; //Things are allowed to be simplified from here.
        }
        EXPECT_EQ(increasing_zigzag[vertex_zigzag], simplified[vertex_simplified]) << "Where line segments are deviating more than max_deviation, vertices should not be altered.";
    }
}

/*!
 * Test simplifying a polyline with small edges encompassed by long edges.
 *
 * The small edges should be removed, but the long edges may not be shifted. The
 * only correct solution involves a vertex that wasn't in the original polyline.
 */
TEST_F(SimplifyTest, LongEdgesNotMoved)
{
    Polygon polyline;
    polyline.add(Point(0, 0));
    polyline.add(Point(10000, 10000)); //Long edge.
    polyline.add(Point(10010, 10000)); //Short edge.
    polyline.add(Point(21010, 0)); //Long edge.

    Polygon simplified = simplifier.polyline(polyline);

    //Verify that all small segments are removed.
    for(size_t i = 1; i < simplified.size(); ++i)
    {
        EXPECT_GE(vSize(simplified[i] - simplified[i - 1]), simplifier.max_resolution) << "There may not be any segment smaller than max resolution.";
    }

    //Verify that all long segments are still present.
    for(size_t i = 0; i < polyline.size() - 1; ++i)
    {
        if(vSize(polyline[i] - polyline[i + 1]) > simplifier.max_resolution)
        {
            //Both endpoints of this line segment must have a distance to the simplified polygon of 0, theoretically.
            //Due to rounding errors we'll allow up to 1 unit.
            Point moved_point = polyline[i];
            PolygonUtils::moveInside(simplified, moved_point);
            const coord_t deviation = vSize(moved_point - polyline[i]);
            EXPECT_LE(deviation, 1) << "The endpoints of long segments must still be in the simplified result.";
        }
    }
}

/*!
 * Tests the case where there are small edges between long edges, where it would
 * normally extend the long edges to prevent shifting them. But extending them
 * to their intersection point would create a vertex that deviates too much from
 * the original shape, so the polygons then can't be simplified.
 */
TEST_F(SimplifyTest, LongEdgesButTooMuchDeviation)
{
    Polygon polyline;
    polyline.add(Point(0, 0));
    polyline.add(Point(0, 10000)); //Long edge.
    polyline.add(Point(10, 10000)); //Short edge.
    polyline.add(Point(20, 0)); //Long edge. Intersection with previous long edge is at 0,20000, which is too far.

    Polygon simplified = simplifier.polyline(polyline);

    //Verify that the polyline is unchanged.
    ASSERT_EQ(polyline.size(), simplified.size()) << "The polyline may not have been simplified because that would introduce vertices that deviate too much.";
    for(size_t i = 0; i < polyline.size(); ++i)
    {
        EXPECT_EQ(polyline[i], simplified[i]) << "The position of the vertices may not have been altered since the polyline was not simplified.";
    }

    polyline.pop_back();
    polyline.add(Point(10, 0)); //Replace last vertex with one that makes the two long edges exactly parallel.

    simplified = simplifier.polyline(polyline);

    //Verify that the polyline is again unchanged.
    ASSERT_EQ(polyline.size(), simplified.size()) << "The polyline may not have been simplified because that would introduce vertices that deviate too much.";
    for(size_t i = 0; i < polyline.size(); ++i)
    {
        EXPECT_EQ(polyline[i], simplified[i]) << "The position of the vertices may not have been altered since the polyline was not simplified.";
    }
}

/*!
 * Test simplifying a sine wave with an amplitude lower than the deviation.
 *
 * The sine wave should get simplified to a line then.
 *
 * This test is similar to LimitedError, but with a higher resolution curve to
 * start with, requiring the algorithm to aggregate errors.
 */
TEST_F(SimplifyTest, Sine)
{
    simplifier.max_resolution = 9999999;
    Polygon simplified = simplifier.polyline(sine);

    EXPECT_EQ(simplified.size(), 2) << "All zigzagged lines can be erased because they deviate less than the maximum deviation, leaving only the endpoints.";
}

}<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_GRAD_2F1_HPP
#define STAN_MATH_PRIM_FUN_GRAD_2F1_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/fabs.hpp>
#include <stan/math/prim/fun/inv.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/sign.hpp>
#include <cmath>

namespace stan {
namespace math {
  namespace internal {
    template <typename T_p, typename T_log_z,
              typename T_input,
              typename T_log,
              typename T_array, typename T_array_int,
    typename T_sign>
    void calc_lambda(const T_p& p, const T_log_z& log_z,
                     T_array& log_g_old, T_array_int& log_g_old_sign,
                     T_log& log_t_old, T_sign& log_t_old_sign,
                     T_log& log_t_new, T_sign& log_t_new_sign,
                     int k,
                     T_input&a1, T_input&a2, T_input&b1) {
    using T_plain = return_type_t<T_log, T_sign, T_array, T_array_int>;

    log_t_new += log(fabs(p)) + log_z;
    log_t_new_sign = p >= 0.0 ? log_t_new_sign : -log_t_new_sign;

    T_plain term = log_g_old_sign[0] * log_t_old_sign * exp(log_g_old[0] - log_t_old)
              + inv(a1 + k);
    log_g_old[0] = log_t_new + log(fabs(term));
    log_g_old_sign[0] = term >= 0.0 ? log_t_new_sign : -log_t_new_sign;

    term = log_g_old_sign[1] * log_t_old_sign * exp(log_g_old[1] - log_t_old)
           + inv(a2 + k);
    log_g_old[1] = log_t_new + log(fabs(term));
    log_g_old_sign[1] = term >= 0.0 ? log_t_new_sign : -log_t_new_sign;

    term = log_g_old_sign[2] * log_t_old_sign * exp(log_g_old[2] - log_t_old)
           - inv(b1 + k);
    log_g_old[2] = log_t_new + log(fabs(term));
    log_g_old_sign[2] = term >= 0.0 ? log_t_new_sign : -log_t_new_sign;
  }
  } // namespace internal

/**
 * Gradients of the hypergeometric function, 2F1.
 *
 * Calculate the gradients of the hypergeometric function (2F1)
 * as the power series stopping when the series converges
 * to within precision or throwing when the
 * function takes max_steps steps.
 *
 * This power-series representation converges for all gradients
 * under the same conditions as the 2F1 function itself.
 *
 * @tparam T type of arguments and result
 * @param[out] g_a1 g_a1 reference to gradient of 2F1 w.r.t. a1, result.
 * @param[out] g_a2 g_a2 reference to gradient of 2F1 w.r.t. a2, result.
 * @param[out] g_b1 g_b1 reference to gradient of 2F1 w.r.t. b1, result.
 * @param[in] a1 a1 see generalized hypergeometric function definition.
 * @param[in] a2 a2 see generalized hypergeometric function definition.
 * @param[in] b1 b1 see generalized hypergeometric function definition.
 * @param[in] z z see generalized hypergeometric function definition.
 * @param[in] precision magnitude of the increment of the infinite sum
 *   to truncate the sum at.
 * @param[in] max_steps number of steps to take.
 */
template <typename T1, typename T2, typename T3, typename T_z>
void grad_2F1(T1& g_a1, T2& g_a2, T3& g_b1, const T1& a1, const T2& a2,
              const T3& b1, const T_z& z, double precision = 1e-14,
              int max_steps = 1e6) {
  check_2F1_converges("grad_2F1", a1, a2, b1, z);

  using stan::math::value_of_rec;
  using std::exp;
  using std::fabs;
  using std::log;
  using std::max;
  using TP = return_type_t<T1, T2, T3, T_z>;

  g_a1 = 0.0;
  g_a2 = 0.0;
  g_b1 = 0.0;

  TP log_g_old[3];
  for (auto& i : log_g_old) {
    i = NEGATIVE_INFTY;
  }

  TP log_t_old = 0.0;
  TP log_t_new = 0.0;
  int sign_z = sign(z);
  TP log_z = log(fabs(z));

  TP log_precision = log(precision);
  TP log_t_new_sign = 1.0;
  TP log_t_old_sign = 1.0;
  TP log_g_old_sign[3];
  for (TP& x : log_g_old_sign) {
    x = 1.0;
  }

 if (sign_z > 0) {
  for (int k = 0; k <= max_steps; ++k) {
    TP p = ((a1 + k) * (a2 + k) / ((b1 + k) * (1 + k))) ;
    if (p == 0) {
      return;
    }

    internal::calc_lambda(p, log_z,
                log_g_old, log_g_old_sign,
                log_t_old, log_t_old_sign,
                log_t_new,
                log_t_new_sign,
                k,
                a1, a2, b1);

    g_a1 += log_g_old_sign[0] > 0 ? exp(log_g_old[0]) : -exp(log_g_old[0]);
    g_a2 += log_g_old_sign[1] > 0 ? exp(log_g_old[1]) : -exp(log_g_old[1]);
    g_b1 += log_g_old_sign[2] > 0 ? exp(log_g_old[2]) : -exp(log_g_old[2]);

    if (log_g_old[0]
            <= std::max(std::log(std::abs(value_of_rec(g_a1))) + log_precision,
                        log_precision)
        && log_g_old[1] <= std::max(
               std::log(std::abs(value_of_rec(g_a2))) + log_precision,
               log_precision)
        && log_g_old[2] <= std::max(
               std::log(std::abs(value_of_rec(g_b1))) + log_precision,
               log_precision)) {
      return;
    }

    log_t_old = log_t_new;
    log_t_old_sign = log_t_new_sign;

  }
 } else {
  for (int k = 0; k <= max_steps; ++k) {
    TP p = ((a1 + k) * (a2 + k) / ((b1 + k) * (1 + k))) ;
    if (p == 0) {
      return;
    }
    internal::calc_lambda(p, log_z,
                log_g_old, log_g_old_sign,
                log_t_old, log_t_old_sign,
                log_t_new,
                log_t_new_sign,
                k,
                a1, a2, b1);

    if (pow(sign_z, k) > 0) {
         log_t_new += log(fabs(p)) + log_z;
      log_t_new_sign = p >= 0.0 ? log_t_new_sign : -log_t_new_sign;

      g_a1 += log_g_old_sign[0] > 0 ? -exp(log_g_old[0]) : exp(log_g_old[0]);
      g_a2 += log_g_old_sign[1] > 0 ? -exp(log_g_old[1]) : exp(log_g_old[1]);
      g_b1 += log_g_old_sign[2] > 0 ? -exp(log_g_old[2]) : exp(log_g_old[2]);
    }  else {
      g_a1 += log_g_old_sign[0] > 0 ? exp(log_g_old[0]) : -exp(log_g_old[0]);
      g_a2 += log_g_old_sign[1] > 0 ? exp(log_g_old[1]) : -exp(log_g_old[1]);
      g_b1 += log_g_old_sign[2] > 0 ? exp(log_g_old[2]) : -exp(log_g_old[2]);
    }
    if (log_g_old[0]
            <= std::max(std::log(std::abs(value_of_rec(g_a1))) + log_precision,
                        log_precision)
        && log_g_old[1] <= std::max(
               std::log(std::abs(value_of_rec(g_a2))) + log_precision,
               log_precision)
        && log_g_old[2] <= std::max(
               std::log(std::abs(value_of_rec(g_b1))) + log_precision,
               log_precision)) {
      return;
    }
    log_t_old = log_t_new;
    log_t_old_sign = log_t_new_sign;
  }
 }
  throw_domain_error("grad_2F1", "k (internal counter)", max_steps, "exceeded ",
                     " iterations, hypergeometric function gradient "
                     "did not converge.");
  return;
}

}  // namespace math
}  // namespace stan
#endif<commit_msg>[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1<commit_after>#ifndef STAN_MATH_PRIM_FUN_GRAD_2F1_HPP
#define STAN_MATH_PRIM_FUN_GRAD_2F1_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/fabs.hpp>
#include <stan/math/prim/fun/inv.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/sign.hpp>
#include <cmath>

namespace stan {
namespace math {
namespace internal {
template <typename T_p, typename T_log_z, typename T_input, typename T_log,
          typename T_array, typename T_array_int, typename T_sign>
void calc_lambda(const T_p& p, const T_log_z& log_z, T_array& log_g_old,
                 T_array_int& log_g_old_sign, T_log& log_t_old,
                 T_sign& log_t_old_sign, T_log& log_t_new,
                 T_sign& log_t_new_sign, int k, T_input& a1, T_input& a2,
                 T_input& b1) {
  using T_plain = return_type_t<T_log, T_sign, T_array, T_array_int>;

  log_t_new += log(fabs(p)) + log_z;
  log_t_new_sign = p >= 0.0 ? log_t_new_sign : -log_t_new_sign;

  T_plain term
      = log_g_old_sign[0] * log_t_old_sign * exp(log_g_old[0] - log_t_old)
        + inv(a1 + k);
  log_g_old[0] = log_t_new + log(fabs(term));
  log_g_old_sign[0] = term >= 0.0 ? log_t_new_sign : -log_t_new_sign;

  term = log_g_old_sign[1] * log_t_old_sign * exp(log_g_old[1] - log_t_old)
         + inv(a2 + k);
  log_g_old[1] = log_t_new + log(fabs(term));
  log_g_old_sign[1] = term >= 0.0 ? log_t_new_sign : -log_t_new_sign;

  term = log_g_old_sign[2] * log_t_old_sign * exp(log_g_old[2] - log_t_old)
         - inv(b1 + k);
  log_g_old[2] = log_t_new + log(fabs(term));
  log_g_old_sign[2] = term >= 0.0 ? log_t_new_sign : -log_t_new_sign;
}
}  // namespace internal

/**
 * Gradients of the hypergeometric function, 2F1.
 *
 * Calculate the gradients of the hypergeometric function (2F1)
 * as the power series stopping when the series converges
 * to within precision or throwing when the
 * function takes max_steps steps.
 *
 * This power-series representation converges for all gradients
 * under the same conditions as the 2F1 function itself.
 *
 * @tparam T type of arguments and result
 * @param[out] g_a1 g_a1 reference to gradient of 2F1 w.r.t. a1, result.
 * @param[out] g_a2 g_a2 reference to gradient of 2F1 w.r.t. a2, result.
 * @param[out] g_b1 g_b1 reference to gradient of 2F1 w.r.t. b1, result.
 * @param[in] a1 a1 see generalized hypergeometric function definition.
 * @param[in] a2 a2 see generalized hypergeometric function definition.
 * @param[in] b1 b1 see generalized hypergeometric function definition.
 * @param[in] z z see generalized hypergeometric function definition.
 * @param[in] precision magnitude of the increment of the infinite sum
 *   to truncate the sum at.
 * @param[in] max_steps number of steps to take.
 */
template <typename T1, typename T2, typename T3, typename T_z>
void grad_2F1(T1& g_a1, T2& g_a2, T3& g_b1, const T1& a1, const T2& a2,
              const T3& b1, const T_z& z, double precision = 1e-14,
              int max_steps = 1e6) {
  check_2F1_converges("grad_2F1", a1, a2, b1, z);

  using stan::math::value_of_rec;
  using std::exp;
  using std::fabs;
  using std::log;
  using std::max;
  using TP = return_type_t<T1, T2, T3, T_z>;

  g_a1 = 0.0;
  g_a2 = 0.0;
  g_b1 = 0.0;

  TP log_g_old[3];
  for (auto& i : log_g_old) {
    i = NEGATIVE_INFTY;
  }

  TP log_t_old = 0.0;
  TP log_t_new = 0.0;
  int sign_z = sign(z);
  TP log_z = log(fabs(z));

  TP log_precision = log(precision);
  TP log_t_new_sign = 1.0;
  TP log_t_old_sign = 1.0;
  TP log_g_old_sign[3];
  for (TP& x : log_g_old_sign) {
    x = 1.0;
  }

  if (sign_z > 0) {
    for (int k = 0; k <= max_steps; ++k) {
      TP p = ((a1 + k) * (a2 + k) / ((b1 + k) * (1 + k)));
      if (p == 0) {
        return;
      }

      internal::calc_lambda(p, log_z, log_g_old, log_g_old_sign, log_t_old,
                            log_t_old_sign, log_t_new, log_t_new_sign, k, a1,
                            a2, b1);

      g_a1 += log_g_old_sign[0] > 0 ? exp(log_g_old[0]) : -exp(log_g_old[0]);
      g_a2 += log_g_old_sign[1] > 0 ? exp(log_g_old[1]) : -exp(log_g_old[1]);
      g_b1 += log_g_old_sign[2] > 0 ? exp(log_g_old[2]) : -exp(log_g_old[2]);

      if (log_g_old[0] <= std::max(
              std::log(std::abs(value_of_rec(g_a1))) + log_precision,
              log_precision)
          && log_g_old[1] <= std::max(
                 std::log(std::abs(value_of_rec(g_a2))) + log_precision,
                 log_precision)
          && log_g_old[2] <= std::max(
                 std::log(std::abs(value_of_rec(g_b1))) + log_precision,
                 log_precision)) {
        return;
      }

      log_t_old = log_t_new;
      log_t_old_sign = log_t_new_sign;
    }
  } else {
    for (int k = 0; k <= max_steps; ++k) {
      TP p = ((a1 + k) * (a2 + k) / ((b1 + k) * (1 + k)));
      if (p == 0) {
        return;
      }
      internal::calc_lambda(p, log_z, log_g_old, log_g_old_sign, log_t_old,
                            log_t_old_sign, log_t_new, log_t_new_sign, k, a1,
                            a2, b1);

      if (pow(sign_z, k) > 0) {
        log_t_new += log(fabs(p)) + log_z;
        log_t_new_sign = p >= 0.0 ? log_t_new_sign : -log_t_new_sign;

        g_a1 += log_g_old_sign[0] > 0 ? -exp(log_g_old[0]) : exp(log_g_old[0]);
        g_a2 += log_g_old_sign[1] > 0 ? -exp(log_g_old[1]) : exp(log_g_old[1]);
        g_b1 += log_g_old_sign[2] > 0 ? -exp(log_g_old[2]) : exp(log_g_old[2]);
      } else {
        g_a1 += log_g_old_sign[0] > 0 ? exp(log_g_old[0]) : -exp(log_g_old[0]);
        g_a2 += log_g_old_sign[1] > 0 ? exp(log_g_old[1]) : -exp(log_g_old[1]);
        g_b1 += log_g_old_sign[2] > 0 ? exp(log_g_old[2]) : -exp(log_g_old[2]);
      }
      if (log_g_old[0] <= std::max(
              std::log(std::abs(value_of_rec(g_a1))) + log_precision,
              log_precision)
          && log_g_old[1] <= std::max(
                 std::log(std::abs(value_of_rec(g_a2))) + log_precision,
                 log_precision)
          && log_g_old[2] <= std::max(
                 std::log(std::abs(value_of_rec(g_b1))) + log_precision,
                 log_precision)) {
        return;
      }
      log_t_old = log_t_new;
      log_t_old_sign = log_t_new_sign;
    }
  }
  throw_domain_error("grad_2F1", "k (internal counter)", max_steps, "exceeded ",
                     " iterations, hypergeometric function gradient "
                     "did not converge.");
  return;
}

}  // namespace math
}  // namespace stan
#endif<|endoftext|>


<commit_before>#include <wiringPi.h>
#include <unistd.h>
#include <iostream>
#include <signal.h>

const int MOTOR_CW = 24;
const int MOTOR_ACW = 25;

void signal_handler(int sig) {
	std::cout << "Stopping Motor" << std::endl;
	digitalWrite(MOTOR_CW, 0);
	digitalWrite(MOTOR_ACW, 0);
	exit(sig);
}

void count_encoder() {
	piLock(1);
	encoder_count++;
	piUnlock(1);
}

int main(int argc, char* argv[]) {
	if (argc < 2) {
		std::cout << "Usage is boom_test [max_count]" << std::endl;
		return -1;
	}
	signal(SIGINT, signal_handler);
	wiringPiSetup();

	pinMode(MOTOR_CW, OUTPUT);
	pinMode(MOTOR_ACW, OUTPUT);

	digitalWrite(MOTOR_CW, 1);
	digitalWrite(MOTOR_ACW, 0);
	int max = atoi(argv[0]);
	int count = 0;
	while (count < max) {
		piLock(1);
		count = encoder_count;
		piUnlock(1);
		std::cout << "COUNT: " << count << std::endl;
		std::cout << "DIST: " << 0.126 * ((double) count / 600) << " m" << std::endl;
	}
}
<commit_msg>Debugging Boom_Test<commit_after>#include <wiringPi.h>
#include <stdlib.h>
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <signal.h>

const int MOTOR_CW = 24;
const int MOTOR_ACW = 25;

void signal_handler(int sig) {
	std::cout << "Stopping Motor" << std::endl;
	digitalWrite(MOTOR_CW, 0);
	digitalWrite(MOTOR_ACW, 0);
	exit(sig);
}

int encoder_count = 0;

void count_encoder() {
	piLock(1);
	encoder_count++;
	piUnlock(1);
}

int main(int argc, char* argv[]) {
	if (argc < 2) {
		std::cout << "Usage is boom_test [max_count]" << std::endl;
		return -1;
	}
	signal(SIGINT, signal_handler);
	wiringPiSetup();

	pinMode(MOTOR_CW, OUTPUT);
	pinMode(MOTOR_ACW, OUTPUT);

	digitalWrite(MOTOR_CW, 1);
	digitalWrite(MOTOR_ACW, 0);
	int max = atoi(argv[0]);
	int count = 0;
	while (count < max) {
		piLock(1);
		count = encoder_count;
		piUnlock(1);
		std::cout << "COUNT: " << count << std::endl;
		std::cout << "DIST: " << 0.126 * ((double) count / 600) << " m" << std::endl;
	}
}
<|endoftext|>


<commit_before>/*
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <QStringList>
#include "gdlhandler.h"
#include "gluonobject.h"
#include "gluonobjectfactory.h"

using namespace Gluon;

template<> GDLHandler* KSingleton<GDLHandler>::m_instance = 0;

GDLHandler::GDLHandler()
{
}

GDLHandler::~GDLHandler()
{
}

GluonObject *
GDLHandler::instantiateObject(QString className)
{
    GluonObject * newObject = GluonObjectFactory::instance()->instantiateObjectByName(className);
    if(!newObject)
        newObject = new GluonObject();

    return newObject;
}

GluonObject *
GDLHandler::createObject(QStringList objectStringList, QObject * parent)
{
    GluonObject * createdObject = 0;
    int index = 0;
    QString currentPropertyName;
    foreach(const QString &item, objectStringList)
    {
        switch(index)
        {
            case 0:
                // Object type
                createdObject = instantiateObject(item);
                createdObject->setParent(parent);
                break;
            case 1:
                // Object name
                createdObject->setName(item);
                break;
            default:
                // Everything else
                if(currentPropertyName.isEmpty())
                {
                    if(item.startsWith('{'))
                    {
                        // Items are parented automatically - see case 0 above
                        QList<GluonObject *> childList = parseGDL(item, createdObject);
                    }
                    else
                    {
                        currentPropertyName = item;
                    }
                }
                else
                {
                    // Set the property with the current string as the value, and finally clear the property name
                    createdObject->setPropertyFromString(currentPropertyName, item);
                    currentPropertyName.clear();
                }
                break;
        }
        ++index;
    }
    return createdObject;
}

QList<QStringList>
GDLHandler::tokenizeObject(QString objectString)
{
    QList<QStringList> tokenizedObject;

    bool inItem = false;
    bool inName = false;
    bool inValue = false;
    bool inChild = false;
    bool inObjectDefinition = false;
    bool beingEscaped = false;
    int extraBracketCounter = 0;
    QString currentString;
    QStringList currentItem;

    QString::const_iterator i;
    for(i = objectString.begin(); i != objectString.end(); ++i)
    {
        if(!inItem)
        {
            if(i->isSpace())
            {
                // Just do nothing - whitespace should be ignored outside of items
            }
            else if(i->toLower() == '{')
            {
                inItem = true;
            }
        }
        else
        {
            if(!inValue && !inName && !inChild && !inObjectDefinition)
            {
                if(!currentString.isEmpty())
                {
                    currentItem.append(currentString.trimmed());
                    currentString.clear();
                }

                // Ignore whitespace as instructed, rar!
                if(!i->isSpace())
                {
                    if(i->toLower() == '}')
                    {
                        // Once we hit an end, we should stop looking at this item
                        // In other words - add the item to the list of items and make a new stringlist to work on...
                        QStringList theItem(currentItem);
                        tokenizedObject.append(theItem);
                        currentItem.clear();
                    }
                    else if(i->toLower() == '{')
                    {
                        // If we hit a start while already inside an item, we should simply start adding stuff
                        // until we hit the correct ending again
                        inChild = true;
                    }
                    else
                    {
                        // Once you hit something, start reading the object definition
                        inObjectDefinition = true;
                    }
                }
            }

            if(inObjectDefinition)
            {
                if(!inName && !inValue)
                {
                    // Ignore spaces between the start { and the object type
                    if(!i->isSpace())
                        inName = true;
                }
                else if(inName)
                {
                    if(i->toLower() == '(')
                    {
                        currentItem.append(currentString.trimmed());
                        currentString.clear();
                        inName = false;
                        inValue = true;
                    }
                    else
                        currentString += i->unicode();
                }
                else // meaning inValue
                {
                    if(i->toLower() == ')')
                    {
                        currentItem.append(currentString.trimmed());
                        currentString.clear();
                        inValue = false;
                        inObjectDefinition = false;
                    }
                    else
                        currentString += i->unicode();
                }
            }
            else if(inChild)
            {
                if(i->toLower() == '\\' && !beingEscaped)
                    beingEscaped = true;
                else
                {
                    currentString += i->unicode();
                    if(!beingEscaped)
                    {
                        if(i->toLower() == '{')
                        {
                            ++extraBracketCounter;
                        }
                        if(i->toLower() == '}')
                        {
                            --extraBracketCounter;
                            if(extraBracketCounter == -1)
                            {
                                // Now we're ready to look for more values, yay! ;)
                                extraBracketCounter = 0;
                                inChild = false;
                            }
                        }
                    }
                    else
                        beingEscaped = false;
                }
            }
            else if(inName)
            {
                // Read name until we hit a space, and after that, start reading the value...
                if(!i->isSpace())
                {
                    currentString += i->unicode();
                }
                else
                {
                    inName = false;
                    inValue = true;
                }
            }
            else if(inValue)
            {
                if(i->toLower() == '\\' && !beingEscaped)
                    beingEscaped = true;
                else
                {
                    // Read the value until the value ends, wooh! ;)
                    currentString += i->unicode();
                    if(!beingEscaped && i->toLower() == ')')
                    {
                        inValue = false;
                    }
                    beingEscaped = false;
                }
            }
        }
    }

    return tokenizedObject;
}

QList<GluonObject *>
GDLHandler::parseGDL(const QString parseThis, QObject * parent)
{
    QList<GluonObject *> thisObjectList;

    QList<QStringList> tokenizedObject = tokenizeObject(parseThis);
    foreach(const QStringList &item, tokenizedObject)
    {
        GluonObject * currentObject = createObject(item, parent);
        thisObjectList.append(currentObject);
    }

    return thisObjectList;
}

QString
serializeGDL(QList<GluonObject *> serializeThis)
{
    QString serializedData;
    return serializedData;
}
<commit_msg>Add debug output to GDL handler.<commit_after>/*
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <QStringList>
#include <QDebug>
#include "gdlhandler.h"
#include "gluonobject.h"
#include "gluonobjectfactory.h"

using namespace Gluon;

template<> GDLHandler* KSingleton<GDLHandler>::m_instance = 0;

GDLHandler::GDLHandler()
{
}

GDLHandler::~GDLHandler()
{
}

GluonObject *
GDLHandler::instantiateObject(QString className)
{
    GluonObject * newObject = GluonObjectFactory::instance()->instantiateObjectByName(className);
    if(!newObject)
        newObject = new GluonObject();

    return newObject;
}

GluonObject *
GDLHandler::createObject(QStringList objectStringList, QObject * parent)
{
    GluonObject * createdObject = 0;
    int index = 0;
    QString currentPropertyName;
    foreach(const QString &item, objectStringList)
    {
        switch(index)
        {
            case 0:
                // Object type
                createdObject = instantiateObject(item);
                createdObject->setParent(parent);
                break;
            case 1:
                // Object name
                createdObject->setName(item);
                break;
            default:
                // Everything else
                if(currentPropertyName.isEmpty())
                {
                    if(item.startsWith('{'))
                    {
                        // Items are parented automatically - see case 0 above
                        QList<GluonObject *> childList = parseGDL(item, createdObject);
                    }
                    else
                    {
                        currentPropertyName = item;
                    }
                }
                else
                {
                    // Set the property with the current string as the value, and finally clear the property name
                    createdObject->setPropertyFromString(currentPropertyName, item);
                    currentPropertyName.clear();
                }
                break;
        }
        ++index;
    }
    return createdObject;
}

QList<QStringList>
GDLHandler::tokenizeObject(QString objectString)
{
    QList<QStringList> tokenizedObject;

    bool inItem = false;
    bool inName = false;
    bool inValue = false;
    bool inChild = false;
    bool inObjectDefinition = false;
    bool beingEscaped = false;
    int extraBracketCounter = 0;
    QString currentString;
    QStringList currentItem;

    QString::const_iterator i;
    for(i = objectString.begin(); i != objectString.end(); ++i)
    {
        if(!inItem)
        {
            if(i->isSpace())
            {
                // Just do nothing - whitespace should be ignored outside of items
            }
            else if(i->toLower() == '{')
            {
                qDebug() << "Found opening bracket";
                inItem = true;
            }
        }
        else
        {
            if(!inValue && !inName && !inChild && !inObjectDefinition)
            {
                if(!currentString.isEmpty())
                {
                    currentItem.append(currentString.trimmed());
                    currentString.clear();
                }

                // Ignore whitespace as instructed, rar!
                if(!i->isSpace())
                {
                    if(i->toLower() == '}')
                    {
                        // Once we hit an end, we should stop looking at this item
                        // In other words - add the item to the list of items and make a new stringlist to work on...
                        qDebug() << "Found closing bracket";
                        QStringList theItem(currentItem);
                        tokenizedObject.append(theItem);
                        currentItem.clear();
                    }
                    else if(i->toLower() == '{')
                    {
                        // If we hit a start while already inside an item, we should simply start adding stuff
                        // until we hit the correct ending again
                        qDebug() << "Found child object";
                        inChild = true;
                    }
                    else
                    {
                        // Once you hit something, start reading the object definition
                        inObjectDefinition = true;
                    }
                }
            }

            if(inObjectDefinition)
            {
                if(!inName && !inValue)
                {
                    // Ignore spaces between the start { and the object type
                    if(!i->isSpace())
                        inName = true;
                }
                else if(inName)
                {
                    if(i->toLower() == '(')
                    {
                        currentItem.append(currentString.trimmed());
                        qDebug() << "Name:" << currentString;
                        currentString.clear();
                        inName = false;
                        inValue = true;
                    }
                    else
                        currentString += i->unicode();
                }
                else // meaning inValue
                {
                    if(i->toLower() == ')')
                    {
                        currentItem.append(currentString.trimmed());
                        currentString.clear();
                        qDebug() << "Value:" << currentString;
                        inValue = false;
                        inObjectDefinition = false;
                    }
                    else
                        currentString += i->unicode();
                }
            }
            else if(inChild)
            {
                if(i->toLower() == '\\' && !beingEscaped)
                    beingEscaped = true;
                else
                {
                    currentString += i->unicode();
                    if(!beingEscaped)
                    {
                        if(i->toLower() == '{')
                        {
                            ++extraBracketCounter;
                        }
                        if(i->toLower() == '}')
                        {
                            --extraBracketCounter;
                            if(extraBracketCounter == -1)
                            {
                                // Now we're ready to look for more values, yay! ;)
                                extraBracketCounter = 0;
                                inChild = false;
                                qDebug() << "End child" << currentString;
                            }
                        }
                    }
                    else
                        beingEscaped = false;
                }
            }
            else if(inName)
            {
                // Read name until we hit a space, and after that, start reading the value...
                if(!i->isSpace())
                {
                    currentString += i->unicode();
                    qDebug() << "Name:" << i->unicode();
                }
                else
                {
                    inName = false;
                    inValue = true;
                }
            }
            else if(inValue)
            {
                if(i->toLower() == '\\' && !beingEscaped)
                    beingEscaped = true;
                else
                {
                    // Read the value until the value ends, wooh! ;)
                    currentString += i->unicode();
                    if(!beingEscaped && i->toLower() == ')')
                    {
                        inValue = false;
                        qDebug() << currentString;
                    }
                    beingEscaped = false;
                }
            }
        }
    }

    return tokenizedObject;
}

QList<GluonObject *>
GDLHandler::parseGDL(const QString parseThis, QObject * parent)
{
    qDebug() << "Begin parsing data";

    QList<GluonObject *> thisObjectList;

    QList<QStringList> tokenizedObject = tokenizeObject(parseThis);

    qDebug() << tokenizedObject;

    foreach(const QStringList &item, tokenizedObject)
    {
        GluonObject * currentObject = createObject(item, parent);
        thisObjectList.append(currentObject);
    }

    qDebug() << "End parsing data";
    return thisObjectList;
}

QString
serializeGDL(QList<GluonObject *> serializeThis)
{
    QString serializedData;
    return serializedData;
}
<|endoftext|>