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

#include "stromx/zbar/Scan.h"

#include <stromx/runtime/DataProvider.h>
#include <stromx/runtime/Id2DataPair.h>
#include <stromx/runtime/Image.h>
#include <stromx/runtime/List.h>
#include <stromx/runtime/OperatorException.h>
#include <stromx/runtime/Matrix.h>
#include <stromx/runtime/MatrixDescription.h>
#include <stromx/runtime/ReadAccess.h>
#include <stromx/runtime/Variant.h>

#include "stromx/zbar/Locale.h"

#include <zbar.h>

using namespace stromx::runtime;

namespace stromx
{
namespace zbar
{

const std::string Scan::TYPE("SCAN");

const std::string Scan::PACKAGE(STROMX_ZBAR_PACKAGE_NAME);
const runtime::Version Scan::VERSION(0, 1, 0);

Scan::Scan()
  : OperatorKernel(TYPE, PACKAGE, VERSION, setupInputs(), setupOutputs(), setupParameters())
  , m_zbarScanner(new ::zbar::ImageScanner)
{
}

Scan::~Scan()
{
    delete m_zbarScanner;
}

const runtime::DataRef Scan::getParameter(const unsigned int id) const
{
    switch(id)
    {
    default:
        throw WrongParameterId(id, *this);
    }
}

void Scan::setParameter(const unsigned int id, const runtime::Data& value)
{
    try
    {
        switch(id)
        {
        default:
            throw WrongParameterId(id, *this);
        }
    }
    catch(std::bad_cast&)
    {
        throw WrongParameterType(parameter(id), *this);
    }
}

void Scan::execute(runtime::DataProvider& provider)
{
    Id2DataPair inputMapper(INPUT);
    provider.receiveInputData(inputMapper);
    ReadAccess access(inputMapper.data());

    const runtime::Image & image = access.get<runtime::Image>();
    if (! image.variant().isVariant(runtime::Variant::MONO_8_IMAGE))
        throw runtime::InputError(INPUT, *this, "Wrong input data variant.");

    runtime::List* symbols = new runtime::List();
    DataContainer result(symbols);

    provider.sendOutputData(runtime::Id2DataPair(SYMBOLS, result));
}

const std::vector<const runtime::Description*> Scan::setupInputs()
{
    std::vector<const Description*> inputs;

    runtime::Description* input = new runtime::Description(INPUT, runtime::Variant::MONO_8_IMAGE);
    input->setTitle(L_("Input"));
    inputs.push_back(input);

    return inputs;
}

const std::vector<const runtime::Description*> Scan::setupOutputs()
{
    std::vector<const runtime::Description*> outputs;

    runtime::Description* symbols = new runtime::Description(SYMBOLS, runtime::Variant::LIST);
    symbols->setTitle(L_("Symbols"));
    outputs.push_back(symbols);

    return outputs;
}

const std::vector<const runtime::Parameter*> Scan::setupParameters()
{
    std::vector<const runtime::Parameter*> parameters;

    return parameters;
}

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

#include "stromx/zbar/Scan.h"

#include <stromx/runtime/DataProvider.h>
#include <stromx/runtime/Id2DataPair.h>
#include <stromx/runtime/Image.h>
#include <stromx/runtime/List.h>
#include <stromx/runtime/OperatorException.h>
#include <stromx/runtime/Matrix.h>
#include <stromx/runtime/MatrixDescription.h>
#include <stromx/runtime/ReadAccess.h>
#include <stromx/runtime/String.h>
#include <stromx/runtime/Variant.h>

#include "stromx/zbar/Locale.h"

#include <zbar.h>

using namespace stromx::runtime;

namespace stromx
{
namespace zbar
{

const std::string Scan::TYPE("SCAN");

const std::string Scan::PACKAGE(STROMX_ZBAR_PACKAGE_NAME);
const runtime::Version Scan::VERSION(0, 1, 0);

Scan::Scan()
  : OperatorKernel(TYPE, PACKAGE, VERSION, setupInputs(), setupOutputs(), setupParameters())
  , m_zbarScanner(new ::zbar::ImageScanner)
{
}

Scan::~Scan()
{
    delete m_zbarScanner;
}

const runtime::DataRef Scan::getParameter(const unsigned int id) const
{
    switch(id)
    {
    default:
        throw WrongParameterId(id, *this);
    }
}

void Scan::setParameter(const unsigned int id, const runtime::Data& /*value*/)
{
    try
    {
        switch(id)
        {
        default:
            throw WrongParameterId(id, *this);
        }
    }
    catch(std::bad_cast&)
    {
        throw WrongParameterType(parameter(id), *this);
    }
}

void Scan::execute(runtime::DataProvider& provider)
{
    Id2DataPair inputMapper(INPUT);
    provider.receiveInputData(inputMapper);
    ReadAccess access(inputMapper.data());

    const runtime::Image & image = access.get<runtime::Image>();
    if (! image.variant().isVariant(runtime::Variant::MONO_8_IMAGE))
        throw runtime::InputError(INPUT, *this, "Wrong input data variant.");

    ::zbar::Image zbarImage(image.width(), image.height(), "YUV8", image.data(),
                            image.height() * image.stride());

    ::zbar::ImageScanner scanner;
    scanner.set_config(::zbar::zbar_symbol_type_t(0), ::zbar::ZBAR_CFG_ENABLE, 1);
    scanner.scan(zbarImage);

    runtime::List* symbols = new runtime::List();

    const ::zbar::SymbolSet & zbarSymbols = scanner.get_results();
    for (::zbar::SymbolIterator iter = zbarSymbols.symbol_begin();
         iter != zbarSymbols.symbol_end();
         ++iter)
    {
        symbols->content().push_back(new String(iter->get_data()));
    }

    DataContainer result(symbols);
    provider.sendOutputData(runtime::Id2DataPair(SYMBOLS, result));
}

const std::vector<const runtime::Description*> Scan::setupInputs()
{
    std::vector<const Description*> inputs;

    runtime::Description* input = new runtime::Description(INPUT, runtime::Variant::MONO_8_IMAGE);
    input->setTitle(L_("Input"));
    inputs.push_back(input);

    return inputs;
}

const std::vector<const runtime::Description*> Scan::setupOutputs()
{
    std::vector<const runtime::Description*> outputs;

    runtime::Description* symbols = new runtime::Description(SYMBOLS, runtime::Variant::LIST);
    symbols->setTitle(L_("Symbols"));
    outputs.push_back(symbols);

    return outputs;
}

const std::vector<const runtime::Parameter*> Scan::setupParameters()
{
    std::vector<const runtime::Parameter*> parameters;

    return parameters;
}

}
}
<|endoftext|>


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

#include <algorithm> // min, max
#include "geo/int-point.hh"
#include "geo/int-rect.hh"
#include "geo/int-size.hh"

namespace faint{

IntRect::IntRect(){
  x = y = w = h = 0;
}

IntRect::IntRect(const IntPoint& p0, const IntPoint& p1) :
  x(std::min(p0.x, p1.x)),
  y(std::min(p0.y, p1.y)),
  w(std::abs(p0.x - p1.x) + 1),
  h(std::abs(p0.y - p1.y) + 1)
{}

IntRect::IntRect(const IntPoint& pt, const IntSize& sz)
  : x(pt.x),
    y(pt.y),
    w(sz.w),
    h(sz.h)
{}

IntRect IntRect::EmptyRect(){
  return IntRect();
}

IntSize IntRect::GetSize() const{
  return IntSize(w, h);
}

int IntRect::Left() const{
  return x;
}

int IntRect::Right() const{
  return x + w - 1;
}

int IntRect::Top() const{
  return y;
}

int IntRect::Bottom() const{
  return y + h - 1;
}

IntPoint IntRect::TopLeft() const{
  return IntPoint(x,y);
}

IntPoint IntRect::TopRight() const{
  return IntPoint(Right(),y);
}

IntPoint IntRect::BottomLeft() const{
  return IntPoint(x, Bottom());
}

IntPoint IntRect::BottomRight() const{
  return IntPoint(Right(), Bottom());
}

IntPoint IntRect::MidTop() const{
  return IntPoint(x + w / 2, Top());
}

IntPoint IntRect::MidBottom() const{
  return IntPoint(x + w / 2, Bottom());
}

IntPoint IntRect::MidLeft() const{
  return IntPoint(Left(), y + h / 2);
}

IntPoint IntRect::MidRight() const{
  return IntPoint(Right(), y + h / 2);
}

bool IntRect::Contains(const IntPoint& p) const{
  return p.x >= x && p.y >= y &&
    p.x <= Right() && p.y <= Bottom();
}

void IntRect::MoveTo(const IntPoint& p){
  x = p.x;
  y = p.y;
}

int area(const IntRect& r){
  return r.w * r.h;
}

bool empty(const IntRect& r){
  return r.w == 0 || r.h == 0;
}

IntRect inflated(const IntRect& r, int dx, int dy){
  return IntRect(IntPoint(r.x - dx, r.y - dy),
    IntSize(r.w + 2 * dx, r.h + 2 * dy));
}

IntRect inflated(const IntRect& r, int d){
  return inflated(r, d, d);
}

IntRect deflated(const IntRect& r, int d){
  return IntRect(IntPoint(r.x + d, r.y + d),
    IntSize(r.w - 2 * d, r.h - 2 * d));
}

IntRect intersection(const IntRect& r1, const IntRect& r2) {
  const auto tl = max_coords(r1.TopLeft(), r2.TopLeft());
  const auto br = min_coords(r1.BottomRight(), r2.BottomRight());
  return br.x < tl.x || br.y < tl.y ?
    IntRect::EmptyRect() :
    IntRect(tl, br);
}

IntRect largest(const IntRect& r1, const IntRect& r2){
  return area(r1) <= area(r2) ? r2 : r1;
}

IntRect smallest(const IntRect& r1, const IntRect& r2){
  return area(r2) < area(r1) ? r2 : r1;
}

IntRect translated(const IntRect& r, const IntPoint& p){
  return IntRect(IntPoint(r.x + p.x, r.y + p.y), IntSize(r.w, r.h));
}

bool operator==(const IntRect& r1, const IntRect& r2){
  return
    r1.x == r2.x &&
    r1.y == r2.y &&
    r1.w == r2.w &&
    r1.h == r2.h;
}

bool operator!=(const IntRect& r1, const IntRect& r2){
  return !(r1 == r2);
}

} // namespace
<commit_msg>Using braced initializer for some return values.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <algorithm> // min, max
#include "geo/int-point.hh"
#include "geo/int-rect.hh"
#include "geo/int-size.hh"

namespace faint{

IntRect::IntRect(){
  x = y = w = h = 0;
}

IntRect::IntRect(const IntPoint& p0, const IntPoint& p1) :
  x(std::min(p0.x, p1.x)),
  y(std::min(p0.y, p1.y)),
  w(std::abs(p0.x - p1.x) + 1),
  h(std::abs(p0.y - p1.y) + 1)
{}

IntRect::IntRect(const IntPoint& pt, const IntSize& sz)
  : x(pt.x),
    y(pt.y),
    w(sz.w),
    h(sz.h)
{}

IntRect IntRect::EmptyRect(){
  return {};
}

IntSize IntRect::GetSize() const{
  return {w, h};
}

int IntRect::Left() const{
  return x;
}

int IntRect::Right() const{
  return x + w - 1;
}

int IntRect::Top() const{
  return y;
}

int IntRect::Bottom() const{
  return y + h - 1;
}

IntPoint IntRect::TopLeft() const{
  return {x,y};
}

IntPoint IntRect::TopRight() const{
  return {Right(),y};
}

IntPoint IntRect::BottomLeft() const{
  return {x, Bottom()};
}

IntPoint IntRect::BottomRight() const{
  return {Right(), Bottom()};
}

IntPoint IntRect::MidTop() const{
  return {x + w / 2, Top()};
}

IntPoint IntRect::MidBottom() const{
  return {x + w / 2, Bottom()};
}

IntPoint IntRect::MidLeft() const{
  return {Left(), y + h / 2};
}

IntPoint IntRect::MidRight() const{
  return {Right(), y + h / 2};
}

bool IntRect::Contains(const IntPoint& p) const{
  return
    p.x >= x && p.y >= y &&
    p.x <= Right() && p.y <= Bottom();
}

void IntRect::MoveTo(const IntPoint& p){
  x = p.x;
  y = p.y;
}

int area(const IntRect& r){
  return r.w * r.h;
}

bool empty(const IntRect& r){
  return r.w == 0 || r.h == 0;
}

IntRect inflated(const IntRect& r, int dx, int dy){
  return {IntPoint(r.x - dx, r.y - dy),
    IntSize(r.w + 2 * dx, r.h + 2 * dy)};
}

IntRect inflated(const IntRect& r, int d){
  return inflated(r, d, d);
}

IntRect deflated(const IntRect& r, int d){
  return {IntPoint(r.x + d, r.y + d),
    IntSize(r.w - 2 * d, r.h - 2 * d)};
}

IntRect intersection(const IntRect& r1, const IntRect& r2) {
  const auto tl = max_coords(r1.TopLeft(), r2.TopLeft());
  const auto br = min_coords(r1.BottomRight(), r2.BottomRight());
  return br.x < tl.x || br.y < tl.y ?
    IntRect::EmptyRect() :
    IntRect(tl, br);
}

IntRect largest(const IntRect& r1, const IntRect& r2){
  return area(r1) <= area(r2) ? r2 : r1;
}

IntRect smallest(const IntRect& r1, const IntRect& r2){
  return area(r2) < area(r1) ? r2 : r1;
}

IntRect translated(const IntRect& r, const IntPoint& p){
  return {IntPoint(r.x + p.x, r.y + p.y), IntSize(r.w, r.h)};
}

bool operator==(const IntRect& r1, const IntRect& r2){
  return
    r1.x == r2.x &&
    r1.y == r2.y &&
    r1.w == r2.w &&
    r1.h == r2.h;
}

bool operator!=(const IntRect& r1, const IntRect& r2){
  return !(r1 == r2);
}

} // namespace
<|endoftext|>


<commit_before>/*
Test cases for dkm.hpp

This is just simple test harness without any external dependencies.
*/

#include "../include/dkm.hpp"
#include "opencv2/opencv.hpp"

#include <vector>
#include <array>
#include <tuple>
#include <string>
#include <iterator>
#include <fstream>
#include <iostream>
#include <chrono>
#include <numeric>

cv::Mat load_opencv() {
	std::ifstream file("iris.data.csv");
	std::istream_iterator<std::string> input(file);
	cv::Mat data;
	for (auto it = std::istream_iterator<std::string>(file); it != std::istream_iterator<std::string>(); ++it) {
		auto comma_pos = it->find(",");
		if (comma_pos != std::string::npos) {
			cv::Vec<float, 2> values;
			values[0] = std::stof(it->substr(0, comma_pos));
			values[1] = std::stof(it->substr(comma_pos + 1));
			data.push_back(values);
		}
	}
	// std::copy(std::istream_iterator<float>(file), std::istream_iterator<float>(), data.begin<float>());
	return data;
}

std::chrono::duration<double> profile_opencv(cv::Mat& data, int k) {
	std::cout << "--- Profiling OpenCV kmeans ---" << std::endl;
	std::cout << "done" << std::endl << "Running kmeans...";
	auto start = std::chrono::high_resolution_clock::now();
	cv::Mat centers, labels;
	cv::kmeans(data, k, labels, cv::TermCriteria(cv::TermCriteria::EPS, 0, 0.01), 1, cv::KMEANS_PP_CENTERS, centers);
	auto end = std::chrono::high_resolution_clock::now();
	std::cout << "done" << std::endl;
	return end - start;
}

int main() {
	std::cout << "# BEGINNING PROFILING #\n" << std::endl;
	auto cv_data = load_opencv();
	auto time_opencv = profile_opencv(cv_data, 3);
	std::cout << "OpenCV: " << std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(time_opencv).count() << "ms" << std::endl;

	return 0;
}<commit_msg>Added dkm benchmark.<commit_after>/*
Test cases for dkm.hpp

This is just simple test harness without any external dependencies.
*/

#include "../include/dkm.hpp"
#include "opencv2/opencv.hpp"

#include <vector>
#include <array>
#include <tuple>
#include <string>
#include <iterator>
#include <fstream>
#include <iostream>
#include <chrono>
#include <numeric>

cv::Mat load_opencv() {
	std::ifstream file("iris.data.csv");
	std::istream_iterator<std::string> input(file);
	cv::Mat data;
	for (auto it = std::istream_iterator<std::string>(file); it != std::istream_iterator<std::string>(); ++it) {
		auto comma_pos = it->find(",");
		if (comma_pos != std::string::npos) {
			cv::Vec<float, 2> values;
			values[0] = std::stof(it->substr(0, comma_pos));
			values[1] = std::stof(it->substr(comma_pos + 1));
			data.push_back(values);
		}
	}
	// std::copy(std::istream_iterator<float>(file), std::istream_iterator<float>(), data.begin<float>());
	return data;
}

std::vector<std::array<float, 2>> load_dkm() {
	std::ifstream file("iris.data.csv");
	std::istream_iterator<std::string> input(file);
	std::vector<std::array<float, 2>> data;
	for (auto it = std::istream_iterator<std::string>(file); it != std::istream_iterator<std::string>(); ++it) {
		auto comma_pos = it->find(",");
		if (comma_pos != std::string::npos)
			data.push_back({std::stof(it->substr(0, comma_pos)), std::stof(it->substr(comma_pos + 1))});
	}
	return data;
}

std::chrono::duration<double> profile_opencv(cv::Mat& data, int k) {
	std::cout << "--- Profiling OpenCV kmeans ---" << std::endl;
	std::cout << "Running kmeans...";
	auto start = std::chrono::high_resolution_clock::now();
	cv::Mat centers, labels;
	cv::kmeans(data, k, labels, cv::TermCriteria(cv::TermCriteria::EPS, 0, 0.01), 1, cv::KMEANS_PP_CENTERS, centers);
	(void)centers;
	(void)labels;
	auto end = std::chrono::high_resolution_clock::now();
	std::cout << "done" << std::endl;
	return end - start;
}

std::chrono::duration<double> profile_dkm(std::vector<std::array<float, 2>>& data, int k) {
	std::cout << "--- Profiling OpenCV kmeans ---" << std::endl;
	std::cout << "Running kmeans...";
	auto start = std::chrono::high_resolution_clock::now();
	auto result = dkm::kmeans_lloyd(data, k);
	auto end = std::chrono::high_resolution_clock::now();
	(void)result;
	std::cout << "done" << std::endl;
	return end - start;
}

int main() {
	std::cout << "# BEGINNING PROFILING #\n" << std::endl;
	auto cv_data = load_opencv();
	auto time_opencv = profile_opencv(cv_data, 3);
	auto dkm_data = load_dkm();
	auto time_dkm = profile_dkm(dkm_data, 3);

	std::cout << "OpenCV: " << std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(time_opencv).count() << "ms" << std::endl;
	std::cout << "DKM: " << std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(time_dkm).count() << "ms" << std::endl;

	return 0;
}<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

// The computeRoots function included in this is based on materials
// covered by the following copyright and license:
//
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include <iostream>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <Eigen/Geometry>
#include <bench/BenchTimer.h>

using namespace Eigen;
using namespace std;

template<typename Matrix, typename Roots>
inline void computeRoots(const Matrix& m, Roots& roots)
{
  typedef typename Matrix::Scalar Scalar;
  const Scalar s_inv3 = 1.0/3.0;
  const Scalar s_sqrt3 = internal::sqrt(Scalar(3.0));

  // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0.  The
  // eigenvalues are the roots to this equation, all guaranteed to be
  // real-valued, because the matrix is symmetric.
  Scalar c0 = m(0,0)*m(1,1)*m(2,2) + Scalar(2)*m(0,1)*m(0,2)*m(1,2) - m(0,0)*m(1,2)*m(1,2) - m(1,1)*m(0,2)*m(0,2) - m(2,2)*m(0,1)*m(0,1);
  Scalar c1 = m(0,0)*m(1,1) - m(0,1)*m(0,1) + m(0,0)*m(2,2) - m(0,2)*m(0,2) + m(1,1)*m(2,2) - m(1,2)*m(1,2);
  Scalar c2 = m(0,0) + m(1,1) + m(2,2);

  // Construct the parameters used in classifying the roots of the equation
  // and in solving the equation for the roots in closed form.
  Scalar c2_over_3 = c2*s_inv3;
  Scalar a_over_3 = (c1 - c2*c2_over_3)*s_inv3;
  if (a_over_3 > Scalar(0))
    a_over_3 = Scalar(0);

  Scalar half_b = Scalar(0.5)*(c0 + c2_over_3*(Scalar(2)*c2_over_3*c2_over_3 - c1));

  Scalar q = half_b*half_b + a_over_3*a_over_3*a_over_3;
  if (q > Scalar(0))
    q = Scalar(0);

  // Compute the eigenvalues by solving for the roots of the polynomial.
  Scalar rho = internal::sqrt(-a_over_3);
  Scalar theta = std::atan2(internal::sqrt(-q),half_b)*s_inv3;
  Scalar cos_theta = internal::cos(theta);
  Scalar sin_theta = internal::sin(theta);
  roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta;
  roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta);
  roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta);

  // Sort in increasing order.
  if (roots(0) >= roots(1))
    std::swap(roots(0),roots(1));
  if (roots(1) >= roots(2))
  {
    std::swap(roots(1),roots(2));
    if (roots(0) >= roots(1))
      std::swap(roots(0),roots(1));
  }
}

template<typename Matrix, typename Vector>
void eigen33(const Matrix& mat, Matrix& evecs, Vector& evals)
{
  typedef typename Matrix::Scalar Scalar;
  // Scale the matrix so its entries are in [-1,1].  The scaling is applied
  // only when at least one matrix entry has magnitude larger than 1.

  Scalar scale = mat.cwiseAbs()/*.template triangularView<Lower>()*/.maxCoeff();
  scale = std::max(scale,Scalar(1));
  Matrix scaledMat = mat / scale;

  // Compute the eigenvalues
//   scaledMat.setZero();
  computeRoots(scaledMat,evals);

  // compute the eigen vectors
  // **here we assume 3 differents eigenvalues**

  // "optimized version" which appears to be slower with gcc!
//     Vector base;
//     Scalar alpha, beta;
//     base <<   scaledMat(1,0) * scaledMat(2,1),
//               scaledMat(1,0) * scaledMat(2,0),
//              -scaledMat(1,0) * scaledMat(1,0);
//     for(int k=0; k<2; ++k)
//     {
//       alpha = scaledMat(0,0) - evals(k);
//       beta  = scaledMat(1,1) - evals(k);
//       evecs.col(k) = (base + Vector(-beta*scaledMat(2,0), -alpha*scaledMat(2,1), alpha*beta)).normalized();
//     }
//     evecs.col(2) = evecs.col(0).cross(evecs.col(1)).normalized();

  // naive version
  Matrix tmp;
  tmp = scaledMat;
  tmp.diagonal().array() -= evals(0);
  evecs.col(0) = tmp.row(0).cross(tmp.row(1)).normalized();

  tmp = scaledMat;
  tmp.diagonal().array() -= evals(1);
  evecs.col(1) = tmp.row(0).cross(tmp.row(1)).normalized();

  tmp = scaledMat;
  tmp.diagonal().array() -= evals(2);
  evecs.col(2) = tmp.row(0).cross(tmp.row(1)).normalized();

  // Rescale back to the original size.
  evals *= scale;
}

int main()
{
  BenchTimer t;
  int tries = 10;
  int rep = 400000;
  typedef Matrix3f Mat;
  typedef Vector3f Vec;
  Mat A = Mat::Random(3,3);
  A = A.adjoint() * A;

  SelfAdjointEigenSolver<Mat> eig(A);
  BENCH(t, tries, rep, eig.compute(A));
  std::cout << "Eigen:  " << t.best() << "s\n";

  Mat evecs;
  Vec evals;
  BENCH(t, tries, rep, eigen33(A,evecs,evals));
  std::cout << "Direct: " << t.best() << "s\n\n";

  std::cerr << "Eigenvalue/eigenvector diffs:\n";
  std::cerr << (evals - eig.eigenvalues()).transpose() << "\n";
  for(int k=0;k<3;++k)
    if(evecs.col(k).dot(eig.eigenvectors().col(k))<0)
      evecs.col(k) = -evecs.col(k);
  std::cerr << evecs - eig.eigenvectors() << "\n\n";
}
<commit_msg>slightly more stable eigen vector computation<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

// The computeRoots function included in this is based on materials
// covered by the following copyright and license:
//
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include <iostream>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <Eigen/Geometry>
#include <bench/BenchTimer.h>

using namespace Eigen;
using namespace std;

template<typename Matrix, typename Roots>
inline void computeRoots(const Matrix& m, Roots& roots)
{
  typedef typename Matrix::Scalar Scalar;
  const Scalar s_inv3 = 1.0/3.0;
  const Scalar s_sqrt3 = internal::sqrt(Scalar(3.0));

  // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0.  The
  // eigenvalues are the roots to this equation, all guaranteed to be
  // real-valued, because the matrix is symmetric.
  Scalar c0 = m(0,0)*m(1,1)*m(2,2) + Scalar(2)*m(0,1)*m(0,2)*m(1,2) - m(0,0)*m(1,2)*m(1,2) - m(1,1)*m(0,2)*m(0,2) - m(2,2)*m(0,1)*m(0,1);
  Scalar c1 = m(0,0)*m(1,1) - m(0,1)*m(0,1) + m(0,0)*m(2,2) - m(0,2)*m(0,2) + m(1,1)*m(2,2) - m(1,2)*m(1,2);
  Scalar c2 = m(0,0) + m(1,1) + m(2,2);

  // Construct the parameters used in classifying the roots of the equation
  // and in solving the equation for the roots in closed form.
  Scalar c2_over_3 = c2*s_inv3;
  Scalar a_over_3 = (c1 - c2*c2_over_3)*s_inv3;
  if (a_over_3 > Scalar(0))
    a_over_3 = Scalar(0);

  Scalar half_b = Scalar(0.5)*(c0 + c2_over_3*(Scalar(2)*c2_over_3*c2_over_3 - c1));

  Scalar q = half_b*half_b + a_over_3*a_over_3*a_over_3;
  if (q > Scalar(0))
    q = Scalar(0);

  // Compute the eigenvalues by solving for the roots of the polynomial.
  Scalar rho = internal::sqrt(-a_over_3);
  Scalar theta = std::atan2(internal::sqrt(-q),half_b)*s_inv3;
  Scalar cos_theta = internal::cos(theta);
  Scalar sin_theta = internal::sin(theta);
  roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta;
  roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta);
  roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta);

  // Sort in increasing order.
  if (roots(0) >= roots(1))
    std::swap(roots(0),roots(1));
  if (roots(1) >= roots(2))
  {
    std::swap(roots(1),roots(2));
    if (roots(0) >= roots(1))
      std::swap(roots(0),roots(1));
  }
}

template<typename Matrix, typename Vector>
void eigen33(const Matrix& mat, Matrix& evecs, Vector& evals)
{
  typedef typename Matrix::Scalar Scalar;
  // Scale the matrix so its entries are in [-1,1].  The scaling is applied
  // only when at least one matrix entry has magnitude larger than 1.

  Scalar scale = mat.cwiseAbs()/*.template triangularView<Lower>()*/.maxCoeff();
  scale = std::max(scale,Scalar(1));
  Matrix scaledMat = mat / scale;

  // Compute the eigenvalues
//   scaledMat.setZero();
  computeRoots(scaledMat,evals);

  // compute the eigen vectors
  // **here we assume 3 differents eigenvalues**

  // "optimized version" which appears to be slower with gcc!
//     Vector base;
//     Scalar alpha, beta;
//     base <<   scaledMat(1,0) * scaledMat(2,1),
//               scaledMat(1,0) * scaledMat(2,0),
//              -scaledMat(1,0) * scaledMat(1,0);
//     for(int k=0; k<2; ++k)
//     {
//       alpha = scaledMat(0,0) - evals(k);
//       beta  = scaledMat(1,1) - evals(k);
//       evecs.col(k) = (base + Vector(-beta*scaledMat(2,0), -alpha*scaledMat(2,1), alpha*beta)).normalized();
//     }
//     evecs.col(2) = evecs.col(0).cross(evecs.col(1)).normalized();

//   // naive version
//   Matrix tmp;
//   tmp = scaledMat;
//   tmp.diagonal().array() -= evals(0);
//   evecs.col(0) = tmp.row(0).cross(tmp.row(1)).normalized();
//
//   tmp = scaledMat;
//   tmp.diagonal().array() -= evals(1);
//   evecs.col(1) = tmp.row(0).cross(tmp.row(1)).normalized();
//
//   tmp = scaledMat;
//   tmp.diagonal().array() -= evals(2);
//   evecs.col(2) = tmp.row(0).cross(tmp.row(1)).normalized();

  // a slighlty more stable version:
  Matrix tmp;
  tmp = scaledMat;
  tmp.diagonal ().array () -= evals (2);
  evecs.col (2) = tmp.row (0).cross (tmp.row (1)).normalized ();
  tmp = scaledMat;
  tmp.diagonal ().array () -= evals (1);
  evecs.col(1) = tmp.row (0).cross(tmp.row (1));
  Scalar n1 = evecs.col(1).norm();
  if(n1<=Eigen::NumTraits<Scalar>::epsilon())
    evecs.col(1) = evecs.col(2).unitOrthogonal();
  else
    evecs.col(1) /= n1;
  evecs.col(0) = evecs.col(2).cross(evecs.col(1));

  // Rescale back to the original size.
  evals *= scale;
}

int main()
{
  BenchTimer t;
  int tries = 10;
  int rep = 400000;
  typedef Matrix3f Mat;
  typedef Vector3f Vec;
  Mat A = Mat::Random(3,3);
  A = A.adjoint() * A;

  SelfAdjointEigenSolver<Mat> eig(A);
  BENCH(t, tries, rep, eig.compute(A));
  std::cout << "Eigen:  " << t.best() << "s\n";

  Mat evecs;
  Vec evals;
  BENCH(t, tries, rep, eigen33(A,evecs,evals));
  std::cout << "Direct: " << t.best() << "s\n\n";

  std::cerr << "Eigenvalue/eigenvector diffs:\n";
  std::cerr << (evals - eig.eigenvalues()).transpose() << "\n";
  for(int k=0;k<3;++k)
    if(evecs.col(k).dot(eig.eigenvectors().col(k))<0)
      evecs.col(k) = -evecs.col(k);
  std::cerr << evecs - eig.eigenvectors() << "\n\n";
}
<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    crypto/signencryptfilescontroller.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra 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 2 of the License, or
    (at your option) any later version.

    Kleopatra 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, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "signencryptfilescontroller.h"

#include "signencryptfilestask.h"
#include "certificateresolver.h"

#include <crypto/gui/signencryptfileswizard.h>
#include <crypto/taskcollection.h>

#include <utils/input.h>
#include <utils/output.h>
#include <utils/classify.h>
#include <utils/stl_util.h>
#include <utils/kleo_assert.h>
#include <utils/exception.h>

#include <kmime/kmime_header_parsing.h>

#include <KLocale>
#include <kdebug.h>

#include <QPointer>
#include <QTimer>
#include <QFileInfo>

#include <boost/bind.hpp>

using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;
using namespace GpgME;
using namespace KMime::Types;

class SignEncryptFilesController::Private {
    friend class ::Kleo::Crypto::SignEncryptFilesController;
    SignEncryptFilesController * const q;
public:
    explicit Private( SignEncryptFilesController * qq );
    ~Private();

private:
    void slotWizardOperationPrepared();
    void slotWizardCanceled();
    void slotTaskDone();

private:
    void ensureWizardCreated();
    void ensureWizardVisible();
    void cancelAllTasks();
    void reportError( int err, const QString & details ) {
        emit q->error( err, details );
    }

    void schedule();
    shared_ptr<SignEncryptFilesTask> takeRunnable( GpgME::Protocol proto );

    static void assertValidOperation( unsigned int );
    static QString titleForOperation( unsigned int op );
private:
    std::vector< shared_ptr<SignEncryptFilesTask> > runnable, completed;
    shared_ptr<SignEncryptFilesTask> cms, openpgp;
    QPointer<SignEncryptFilesWizard> wizard;
    unsigned int operation;
    Protocol protocol;
};

SignEncryptFilesController::Private::Private( SignEncryptFilesController * qq )
    : q( qq ),
      runnable(),
      cms(),
      openpgp(),
      wizard(),
      operation( SignAllowed|EncryptAllowed ),
      protocol( UnknownProtocol )
{

}

SignEncryptFilesController::Private::~Private() { kDebug(); }

QString SignEncryptFilesController::Private::titleForOperation( unsigned int op ) {
    const bool signDisallowed = (op & SignMask) == SignDisallowed;
    const bool encryptDisallowed = (op & EncryptMask) == EncryptDisallowed;

    kleo_assert( !signDisallowed || !encryptDisallowed );

    if ( !signDisallowed && encryptDisallowed )
        return i18n( "Sign Files" );

    if ( signDisallowed && !encryptDisallowed )
        return i18n( "Encrypt Files" );

    return i18n( "Sign/Encrypt Files" );
}

SignEncryptFilesController::SignEncryptFilesController( QObject * p )
    : Controller( p ), d( new Private( this ) )
{

}

SignEncryptFilesController::SignEncryptFilesController( const shared_ptr<const ExecutionContext> & ctx, QObject * p )
    : Controller( ctx, p ), d( new Private( this ) )
{

}

SignEncryptFilesController::~SignEncryptFilesController() {
    kDebug();
    if ( d->wizard && !d->wizard->isVisible() )
        delete d->wizard;
        //d->wizard->close(); ### ?
}

void SignEncryptFilesController::setProtocol( Protocol proto ) {
    kleo_assert( d->protocol == UnknownProtocol ||
                 d->protocol == proto );
    d->protocol = proto;
    d->ensureWizardCreated();
    d->wizard->setPresetProtocol( proto );
}

Protocol SignEncryptFilesController::protocol() const {
    return d->protocol;
}

// static
void SignEncryptFilesController::Private::assertValidOperation( unsigned int op ) {
    kleo_assert( ( op & SignMask )    == SignDisallowed    ||
                 ( op & SignMask )    == SignAllowed       ||
                 ( op & SignMask )    == SignForced );
    kleo_assert( ( op & EncryptMask ) == EncryptDisallowed ||
                 ( op & EncryptMask ) == EncryptAllowed    ||
                 ( op & EncryptMask ) == EncryptForced );
    kleo_assert( ( op & ~(SignMask|EncryptMask) ) == 0 );
}

void SignEncryptFilesController::setOperationMode( unsigned int mode ) {
    Private::assertValidOperation( mode );
    d->operation = mode;
    if ( d->wizard )
        d->wizard->setWindowTitle( d->titleForOperation( d->operation ) );
}

void SignEncryptFilesController::setFiles( const QStringList & files ) {
    kleo_assert( !files.empty() );
    d->ensureWizardVisible();
    d->wizard->setFiles( files );
}

void SignEncryptFilesController::Private::slotWizardCanceled() {
    kDebug();
    reportError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") );
}

void SignEncryptFilesController::start() {
    d->ensureWizardVisible();
}

static shared_ptr<SignEncryptFilesTask>
createSignEncryptTaskForFileInfo( const QFileInfo & fi, bool pgp, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & recipients, const std::vector<Key> & signers ) {
    const shared_ptr<SignEncryptFilesTask> task( new SignEncryptFilesTask );
    task->setSign( sign );
    task->setEncrypt( encrypt );
    task->setAsciiArmor( ascii );
    task->setRemoveInputFileOnSuccess( removeUnencrypted );
    if ( sign )
        task->setSigners( signers );
    if ( encrypt )
        task->setRecipients( recipients );

    unsigned int cls = pgp ? Class::OpenPGP : Class::CMS ;
    if ( encrypt )
        cls |= Class::CipherText;
    else if ( sign )
        cls |= Class::DetachedSignature;
    cls |= ascii ? Class::Ascii : Class::Binary ;

    const QString input = fi.absoluteFilePath();
    task->setInputFileName( input );

    const char * ext = outputFileExtension( cls );
    if ( !ext )
        ext = "out"; // ### error out?

    const QString output = input + '.' + ext;
    task->setOutputFileName( output );

    return task;
}

static std::vector< shared_ptr<SignEncryptFilesTask> >
createSignEncryptTasksForFileInfo( const QFileInfo & fi, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & pgpRecipients, const std::vector<Key> & pgpSigners, const std::vector<Key> & cmsRecipients, const std::vector<Key> & cmsSigners ) {
    std::vector< shared_ptr<SignEncryptFilesTask> > result;

    const bool shallPgpSign = sign && !pgpSigners.empty();
    const bool shallPgpEncrypt = encrypt && !pgpRecipients.empty();
    const bool pgp = shallPgpEncrypt && ( !sign || shallPgpSign ) || !encrypt && shallPgpSign;

    const bool shallCmsSign = sign && !cmsSigners.empty();
    const bool shallCmsEncrypt = encrypt && !cmsRecipients.empty();
    const bool cms = shallCmsEncrypt && ( !sign || shallCmsSign ) || !encrypt && shallCmsSign;

    result.reserve( pgp + cms );

    if ( pgp )
        result.push_back( createSignEncryptTaskForFileInfo( fi, true, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners ) );
    if ( cms )
        result.push_back( createSignEncryptTaskForFileInfo( fi, false, sign, encrypt, ascii, removeUnencrypted, cmsRecipients, cmsSigners ) );

    return result;
}

void SignEncryptFilesController::Private::slotWizardOperationPrepared() {

    try {

        kleo_assert( wizard );

        const bool sign = wizard->signingSelected();
        const bool encrypt = wizard->encryptionSelected();

        const bool ascii = wizard->isAsciiArmorEnabled();
        const bool removeUnencrypted = wizard->removeUnencryptedFile();
        const QFileInfoList files = wizard->resolvedFiles();

        std::vector<Key> pgpRecipients, cmsRecipients, pgpSigners, cmsSigners;
        if ( encrypt ) {
            const std::vector<Key> recipients = wizard->resolvedCertificates();
            kdtools::copy_if( recipients.begin(), recipients.end(),
                              std::back_inserter( pgpRecipients ),
                              bind( &Key::protocol, _1 ) == GpgME::OpenPGP );
            kdtools::copy_if( recipients.begin(), recipients.end(),
                              std::back_inserter( cmsRecipients ),
                              bind( &Key::protocol, _1 ) == GpgME::CMS );
            kleo_assert( pgpRecipients.size() + cmsRecipients.size() == recipients.size() );
        }
        if ( sign ) {
            const std::vector<Key> signers = wizard->resolvedSigners();
            kdtools::copy_if( signers.begin(), signers.end(),
                              std::back_inserter( pgpSigners ),
                              bind( &Key::protocol, _1 ) == GpgME::OpenPGP );
            kdtools::copy_if( signers.begin(), signers.end(),
                              std::back_inserter( cmsSigners ),
                              bind( &Key::protocol, _1 ) == GpgME::CMS );
            kleo_assert( pgpSigners.size() + cmsSigners.size() == signers.size() );
        }

        kleo_assert( !files.empty() );

        std::vector< shared_ptr<SignEncryptFilesTask> > tasks;
        tasks.reserve( files.size() );

        Q_FOREACH( const QFileInfo & fi, files ) {
            const std::vector< shared_ptr<SignEncryptFilesTask> > created =
                createSignEncryptTasksForFileInfo( fi, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners, cmsRecipients, cmsSigners );
            tasks.insert( tasks.end(), created.begin(), created.end() );
        }

        kleo_assert( runnable.empty() );

        runnable.swap( tasks );

        int i = 0;

        Q_FOREACH( const shared_ptr<Task> task, runnable )
            connect( task.get(), SIGNAL(result(boost::shared_ptr<const Kleo::Crypto::Task::Result>)),
                     q, SLOT(slotTaskDone()) );

        ensureWizardCreated();
        shared_ptr<TaskCollection> coll( new TaskCollection );
        std::vector<shared_ptr<Task> > tmp;
        std::copy( runnable.begin(), runnable.end(), std::back_inserter( tmp ) );
        coll->setTasks( tmp );
        wizard->setTaskCollection( coll );

        QTimer::singleShot( 0, q, SLOT(schedule()) );

    } catch ( const Kleo::Exception & e ) {
        reportError( e.error().encodedError(), e.message() );
    } catch ( const std::exception & e ) {
        reportError( gpg_error( GPG_ERR_UNEXPECTED ),
                     i18n("Caught unexpected exception in SignEncryptFilesController::Private::slotWizardOperationPrepared: %1",
                          QString::fromLocal8Bit( e.what() ) ) );
    } catch ( ... ) {
        reportError( gpg_error( GPG_ERR_UNEXPECTED ),
                     i18n("Caught unknown exception in SignEncryptFilesController::Private::slotWizardOperationPrepared") );
    }
}

void SignEncryptFilesController::Private::schedule() {

    if ( !cms )
        if ( const shared_ptr<SignEncryptFilesTask> t = takeRunnable( CMS ) ) {
            t->start();
            cms = t;
        }

    if ( !openpgp )
        if ( const shared_ptr<SignEncryptFilesTask> t = takeRunnable( OpenPGP ) ) {
            t->start();
            openpgp = t;
        }

    if ( !cms && !openpgp ) {
        kleo_assert( runnable.empty() );
        emit q->done();
    }

}

shared_ptr<SignEncryptFilesTask> SignEncryptFilesController::Private::takeRunnable( GpgME::Protocol proto ) {
    const std::vector< shared_ptr<SignEncryptFilesTask> >::iterator it
        = std::find_if( runnable.begin(), runnable.end(),
                        bind( &Task::protocol, _1 ) == proto );
    if ( it == runnable.end() )
        return shared_ptr<SignEncryptFilesTask>();

    const shared_ptr<SignEncryptFilesTask> result = *it;
    runnable.erase( it );
    return result;
}

void SignEncryptFilesController::Private::slotTaskDone() {
    assert( q->sender() );

    // We could just delete the tasks here, but we can't use
    // Qt::QueuedConnection here (we need sender()) and other slots
    // might not yet have executed. Therefore, we push completed tasks
    // into a burial container

    if ( q->sender() == cms.get() ) {
        completed.push_back( cms );
        cms.reset();
    } else if ( q->sender() == openpgp.get() ) {
        completed.push_back( openpgp );
        openpgp.reset();
    }

    QTimer::singleShot( 0, q, SLOT(schedule()) );
}

void SignEncryptFilesController::cancel() {
    kDebug();
    try {
        if ( d->wizard )
            d->wizard->close();
        d->cancelAllTasks();
    } catch ( const std::exception & e ) {
        qDebug( "Caught exception: %s", e.what() );
    }
}

void SignEncryptFilesController::Private::cancelAllTasks() {

    // we just kill all runnable tasks - this will not result in
    // signal emissions.
    runnable.clear();

    // a cancel() will result in a call to
    if ( cms )
        cms->cancel();
    if ( openpgp )
        openpgp->cancel();
}

void SignEncryptFilesController::Private::ensureWizardCreated() {
    if ( wizard )
        return;

    std::auto_ptr<SignEncryptFilesWizard> w( new SignEncryptFilesWizard );
    w->setWindowTitle( titleForOperation( operation ) );
    w->setAttribute( Qt::WA_DeleteOnClose );

    connect( w.get(), SIGNAL(operationPrepared()), q, SLOT(slotWizardOperationPrepared()), Qt::QueuedConnection );
    connect( w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection );
    wizard = w.release();
}

void SignEncryptFilesController::Private::ensureWizardVisible() {
    ensureWizardCreated();
    q->bringToForeground( wizard );
}

#include "moc_signencryptfilescontroller.cpp"

<commit_msg>for files, created detached signatures<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    crypto/signencryptfilescontroller.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra 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 2 of the License, or
    (at your option) any later version.

    Kleopatra 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, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "signencryptfilescontroller.h"

#include "signencryptfilestask.h"
#include "certificateresolver.h"

#include <crypto/gui/signencryptfileswizard.h>
#include <crypto/taskcollection.h>

#include <utils/input.h>
#include <utils/output.h>
#include <utils/classify.h>
#include <utils/stl_util.h>
#include <utils/kleo_assert.h>
#include <utils/exception.h>

#include <kmime/kmime_header_parsing.h>

#include <KLocale>
#include <kdebug.h>

#include <QPointer>
#include <QTimer>
#include <QFileInfo>

#include <boost/bind.hpp>

using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;
using namespace GpgME;
using namespace KMime::Types;

class SignEncryptFilesController::Private {
    friend class ::Kleo::Crypto::SignEncryptFilesController;
    SignEncryptFilesController * const q;
public:
    explicit Private( SignEncryptFilesController * qq );
    ~Private();

private:
    void slotWizardOperationPrepared();
    void slotWizardCanceled();
    void slotTaskDone();

private:
    void ensureWizardCreated();
    void ensureWizardVisible();
    void cancelAllTasks();
    void reportError( int err, const QString & details ) {
        emit q->error( err, details );
    }

    void schedule();
    shared_ptr<SignEncryptFilesTask> takeRunnable( GpgME::Protocol proto );

    static void assertValidOperation( unsigned int );
    static QString titleForOperation( unsigned int op );
private:
    std::vector< shared_ptr<SignEncryptFilesTask> > runnable, completed;
    shared_ptr<SignEncryptFilesTask> cms, openpgp;
    QPointer<SignEncryptFilesWizard> wizard;
    unsigned int operation;
    Protocol protocol;
};

SignEncryptFilesController::Private::Private( SignEncryptFilesController * qq )
    : q( qq ),
      runnable(),
      cms(),
      openpgp(),
      wizard(),
      operation( SignAllowed|EncryptAllowed ),
      protocol( UnknownProtocol )
{

}

SignEncryptFilesController::Private::~Private() { kDebug(); }

QString SignEncryptFilesController::Private::titleForOperation( unsigned int op ) {
    const bool signDisallowed = (op & SignMask) == SignDisallowed;
    const bool encryptDisallowed = (op & EncryptMask) == EncryptDisallowed;

    kleo_assert( !signDisallowed || !encryptDisallowed );

    if ( !signDisallowed && encryptDisallowed )
        return i18n( "Sign Files" );

    if ( signDisallowed && !encryptDisallowed )
        return i18n( "Encrypt Files" );

    return i18n( "Sign/Encrypt Files" );
}

SignEncryptFilesController::SignEncryptFilesController( QObject * p )
    : Controller( p ), d( new Private( this ) )
{

}

SignEncryptFilesController::SignEncryptFilesController( const shared_ptr<const ExecutionContext> & ctx, QObject * p )
    : Controller( ctx, p ), d( new Private( this ) )
{

}

SignEncryptFilesController::~SignEncryptFilesController() {
    kDebug();
    if ( d->wizard && !d->wizard->isVisible() )
        delete d->wizard;
        //d->wizard->close(); ### ?
}

void SignEncryptFilesController::setProtocol( Protocol proto ) {
    kleo_assert( d->protocol == UnknownProtocol ||
                 d->protocol == proto );
    d->protocol = proto;
    d->ensureWizardCreated();
    d->wizard->setPresetProtocol( proto );
}

Protocol SignEncryptFilesController::protocol() const {
    return d->protocol;
}

// static
void SignEncryptFilesController::Private::assertValidOperation( unsigned int op ) {
    kleo_assert( ( op & SignMask )    == SignDisallowed    ||
                 ( op & SignMask )    == SignAllowed       ||
                 ( op & SignMask )    == SignForced );
    kleo_assert( ( op & EncryptMask ) == EncryptDisallowed ||
                 ( op & EncryptMask ) == EncryptAllowed    ||
                 ( op & EncryptMask ) == EncryptForced );
    kleo_assert( ( op & ~(SignMask|EncryptMask) ) == 0 );
}

void SignEncryptFilesController::setOperationMode( unsigned int mode ) {
    Private::assertValidOperation( mode );
    d->operation = mode;
    if ( d->wizard )
        d->wizard->setWindowTitle( d->titleForOperation( d->operation ) );
}

void SignEncryptFilesController::setFiles( const QStringList & files ) {
    kleo_assert( !files.empty() );
    d->ensureWizardVisible();
    d->wizard->setFiles( files );
}

void SignEncryptFilesController::Private::slotWizardCanceled() {
    kDebug();
    reportError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") );
}

void SignEncryptFilesController::start() {
    d->ensureWizardVisible();
}

static shared_ptr<SignEncryptFilesTask>
createSignEncryptTaskForFileInfo( const QFileInfo & fi, bool pgp, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & recipients, const std::vector<Key> & signers ) {
    const shared_ptr<SignEncryptFilesTask> task( new SignEncryptFilesTask );
    task->setSign( sign );
    task->setEncrypt( encrypt );
    task->setAsciiArmor( ascii );
    task->setRemoveInputFileOnSuccess( removeUnencrypted );
    if ( sign ) {
        task->setSigners( signers );
        task->setDetachedSignature( true );
    }
    if ( encrypt )
        task->setRecipients( recipients );

    unsigned int cls = pgp ? Class::OpenPGP : Class::CMS ;
    if ( encrypt )
        cls |= Class::CipherText;
    else if ( sign )
        cls |= Class::DetachedSignature;
    cls |= ascii ? Class::Ascii : Class::Binary ;

    const QString input = fi.absoluteFilePath();
    task->setInputFileName( input );

    const char * ext = outputFileExtension( cls );
    if ( !ext )
        ext = "out"; // ### error out?

    const QString output = input + '.' + ext;
    task->setOutputFileName( output );

    return task;
}

static std::vector< shared_ptr<SignEncryptFilesTask> >
createSignEncryptTasksForFileInfo( const QFileInfo & fi, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & pgpRecipients, const std::vector<Key> & pgpSigners, const std::vector<Key> & cmsRecipients, const std::vector<Key> & cmsSigners ) {
    std::vector< shared_ptr<SignEncryptFilesTask> > result;

    const bool shallPgpSign = sign && !pgpSigners.empty();
    const bool shallPgpEncrypt = encrypt && !pgpRecipients.empty();
    const bool pgp = shallPgpEncrypt && ( !sign || shallPgpSign ) || !encrypt && shallPgpSign;

    const bool shallCmsSign = sign && !cmsSigners.empty();
    const bool shallCmsEncrypt = encrypt && !cmsRecipients.empty();
    const bool cms = shallCmsEncrypt && ( !sign || shallCmsSign ) || !encrypt && shallCmsSign;

    result.reserve( pgp + cms );

    if ( pgp )
        result.push_back( createSignEncryptTaskForFileInfo( fi, true, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners ) );
    if ( cms )
        result.push_back( createSignEncryptTaskForFileInfo( fi, false, sign, encrypt, ascii, removeUnencrypted, cmsRecipients, cmsSigners ) );

    return result;
}

void SignEncryptFilesController::Private::slotWizardOperationPrepared() {

    try {

        kleo_assert( wizard );

        const bool sign = wizard->signingSelected();
        const bool encrypt = wizard->encryptionSelected();

        const bool ascii = wizard->isAsciiArmorEnabled();
        const bool removeUnencrypted = wizard->removeUnencryptedFile();
        const QFileInfoList files = wizard->resolvedFiles();

        std::vector<Key> pgpRecipients, cmsRecipients, pgpSigners, cmsSigners;
        if ( encrypt ) {
            const std::vector<Key> recipients = wizard->resolvedCertificates();
            kdtools::copy_if( recipients.begin(), recipients.end(),
                              std::back_inserter( pgpRecipients ),
                              bind( &Key::protocol, _1 ) == GpgME::OpenPGP );
            kdtools::copy_if( recipients.begin(), recipients.end(),
                              std::back_inserter( cmsRecipients ),
                              bind( &Key::protocol, _1 ) == GpgME::CMS );
            kleo_assert( pgpRecipients.size() + cmsRecipients.size() == recipients.size() );
        }
        if ( sign ) {
            const std::vector<Key> signers = wizard->resolvedSigners();
            kdtools::copy_if( signers.begin(), signers.end(),
                              std::back_inserter( pgpSigners ),
                              bind( &Key::protocol, _1 ) == GpgME::OpenPGP );
            kdtools::copy_if( signers.begin(), signers.end(),
                              std::back_inserter( cmsSigners ),
                              bind( &Key::protocol, _1 ) == GpgME::CMS );
            kleo_assert( pgpSigners.size() + cmsSigners.size() == signers.size() );
        }

        kleo_assert( !files.empty() );

        std::vector< shared_ptr<SignEncryptFilesTask> > tasks;
        tasks.reserve( files.size() );

        Q_FOREACH( const QFileInfo & fi, files ) {
            const std::vector< shared_ptr<SignEncryptFilesTask> > created =
                createSignEncryptTasksForFileInfo( fi, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners, cmsRecipients, cmsSigners );
            tasks.insert( tasks.end(), created.begin(), created.end() );
        }

        kleo_assert( runnable.empty() );

        runnable.swap( tasks );

        int i = 0;

        Q_FOREACH( const shared_ptr<Task> task, runnable )
            connect( task.get(), SIGNAL(result(boost::shared_ptr<const Kleo::Crypto::Task::Result>)),
                     q, SLOT(slotTaskDone()) );

        ensureWizardCreated();
        shared_ptr<TaskCollection> coll( new TaskCollection );
        std::vector<shared_ptr<Task> > tmp;
        std::copy( runnable.begin(), runnable.end(), std::back_inserter( tmp ) );
        coll->setTasks( tmp );
        wizard->setTaskCollection( coll );

        QTimer::singleShot( 0, q, SLOT(schedule()) );

    } catch ( const Kleo::Exception & e ) {
        reportError( e.error().encodedError(), e.message() );
    } catch ( const std::exception & e ) {
        reportError( gpg_error( GPG_ERR_UNEXPECTED ),
                     i18n("Caught unexpected exception in SignEncryptFilesController::Private::slotWizardOperationPrepared: %1",
                          QString::fromLocal8Bit( e.what() ) ) );
    } catch ( ... ) {
        reportError( gpg_error( GPG_ERR_UNEXPECTED ),
                     i18n("Caught unknown exception in SignEncryptFilesController::Private::slotWizardOperationPrepared") );
    }
}

void SignEncryptFilesController::Private::schedule() {

    if ( !cms )
        if ( const shared_ptr<SignEncryptFilesTask> t = takeRunnable( CMS ) ) {
            t->start();
            cms = t;
        }

    if ( !openpgp )
        if ( const shared_ptr<SignEncryptFilesTask> t = takeRunnable( OpenPGP ) ) {
            t->start();
            openpgp = t;
        }

    if ( !cms && !openpgp ) {
        kleo_assert( runnable.empty() );
        emit q->done();
    }

}

shared_ptr<SignEncryptFilesTask> SignEncryptFilesController::Private::takeRunnable( GpgME::Protocol proto ) {
    const std::vector< shared_ptr<SignEncryptFilesTask> >::iterator it
        = std::find_if( runnable.begin(), runnable.end(),
                        bind( &Task::protocol, _1 ) == proto );
    if ( it == runnable.end() )
        return shared_ptr<SignEncryptFilesTask>();

    const shared_ptr<SignEncryptFilesTask> result = *it;
    runnable.erase( it );
    return result;
}

void SignEncryptFilesController::Private::slotTaskDone() {
    assert( q->sender() );

    // We could just delete the tasks here, but we can't use
    // Qt::QueuedConnection here (we need sender()) and other slots
    // might not yet have executed. Therefore, we push completed tasks
    // into a burial container

    if ( q->sender() == cms.get() ) {
        completed.push_back( cms );
        cms.reset();
    } else if ( q->sender() == openpgp.get() ) {
        completed.push_back( openpgp );
        openpgp.reset();
    }

    QTimer::singleShot( 0, q, SLOT(schedule()) );
}

void SignEncryptFilesController::cancel() {
    kDebug();
    try {
        if ( d->wizard )
            d->wizard->close();
        d->cancelAllTasks();
    } catch ( const std::exception & e ) {
        qDebug( "Caught exception: %s", e.what() );
    }
}

void SignEncryptFilesController::Private::cancelAllTasks() {

    // we just kill all runnable tasks - this will not result in
    // signal emissions.
    runnable.clear();

    // a cancel() will result in a call to
    if ( cms )
        cms->cancel();
    if ( openpgp )
        openpgp->cancel();
}

void SignEncryptFilesController::Private::ensureWizardCreated() {
    if ( wizard )
        return;

    std::auto_ptr<SignEncryptFilesWizard> w( new SignEncryptFilesWizard );
    w->setWindowTitle( titleForOperation( operation ) );
    w->setAttribute( Qt::WA_DeleteOnClose );

    connect( w.get(), SIGNAL(operationPrepared()), q, SLOT(slotWizardOperationPrepared()), Qt::QueuedConnection );
    connect( w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection );
    wizard = w.release();
}

void SignEncryptFilesController::Private::ensureWizardVisible() {
    ensureWizardCreated();
    q->bringToForeground( wizard );
}

#include "moc_signencryptfilescontroller.cpp"

<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                         OpenSim:  GCVSplineSet.cpp                         *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Frank C. Anderson                                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

/* Note: This code was originally developed by Realistic Dynamics Inc.
 * Author: Frank C. Anderson
 */

// INCLUDES
#include "GCVSplineSet.h"
#include "GCVSpline.h"
#include "Storage.h"

//=============================================================================
// DESTRUCTOR AND CONSTRUCTORS
//=============================================================================
//_____________________________________________________________________________

using namespace OpenSim;
/**
 * Destructor.
 */
GCVSplineSet::~GCVSplineSet()
{
}

//_____________________________________________________________________________
/**
 * Default constructor.
 */
GCVSplineSet::
GCVSplineSet()
{
    setNull();
}
//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines from file.
 *
 * @param aFileName Name of the file.
 */
GCVSplineSet::
GCVSplineSet(const char *aFileName) :
    FunctionSet(aFileName)
{
    setNull();
}
//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines based on the states
 * stored in an Storage object.
 *
 * Each column in the Storage object is fit with a spline of the specified
 * degree and is named the name of its corresponding column label.  Note that
 * column labels in the storage object are assumed to be tab delimited.
 *
 * @param aDegree Degree of the constructed splines (1, 3, 5, or 7).
 * @param aStore Storage object.
 * @param aErrorVariance Estimate of the variance of the error in the data to
 * be fit.  If negative, the variance will be estimated.  If 0.0, the fit will
 * try to fit the data points exactly- no smoothing.  If
 * positive, the fits will be smoothed according to the specified variance.
 * The larger the error variance, the more the smoothing.  Note that this is
 * the error variance assumed for each column in the Storage.  If different
 * variances should be set for the various columns, you will need to
 * construct each GCVSpline individually.
 * @see Storage
 * @see GCVSpline
 */
GCVSplineSet::
GCVSplineSet(int aDegree,const Storage *aStore,double aErrorVariance)
{
    setNull();
    if(aStore==NULL) return;
    setName(aStore->getName());

    // CAPACITY
    StateVector *vec = aStore->getStateVector(0);
    if(vec==NULL) return;
    ensureCapacity(2*vec->getSize());

    // CONSTRUCT
    construct(aDegree,aStore,aErrorVariance);
}

//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines based on the states
 * stored in a TimeSeriesTable.
 *
 * Each column in the TimeSeriesTable is fit with a spline of the specified
 * degree and is named the name of its corresponding column label.
 *
 * @param table TimeSeriesTable object.
 * @param labels Columns to use from TimeSeriesTable.
 * @param degree Degree of the constructed splines (1, 3, 5, or 7).
 * @param aErrorVariance Estimate of the variance of the error in the data to
 * be fit.  If negative, the variance will be estimated.  If 0.0, the fit will
 * try to fit the data points exactly- no smoothing.  If
 * positive, the fits will be smoothed according to the specified variance.
 * The larger the error variance, the more the smoothing.  Note that this is
 * the error variance assumed for each column in the Storage.  If different
 * variances should be set for the various columns, you will need to
 * construct each GCVSpline individually.
 * @see Storage
 * @see GCVSpline
 */
GCVSplineSet::
GCVSplineSet(const TimeSeriesTable& table,
             const std::vector<std::string>& labels,
             int degree,
             double errorVariance) {
    const auto& time = table.getIndependentColumn();
    auto labelsToUse = labels;
    if (labelsToUse.empty()) labelsToUse = table.getColumnLabels();
    for (const auto& label : labelsToUse) {
        const auto& column = table.getDependentColumn(label);
        adoptAndAppend(new GCVSpline(degree, column.size(), time.data(),
                                     &column[0], label, errorVariance));
    }
}

//=============================================================================
// CONSTRUCTION
//=============================================================================
//_____________________________________________________________________________
/**
 * Set all member variables to NULL values.
 */
void GCVSplineSet::
setNull()
{
}
//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines based on the states
 * stored in an Storage object.
 *
 * @param aDegree Degree of the constructed splines (1, 3, 5, or 7).
 * @param aStore Storage object.
 * @param aErrorVariance Error variance for the data.
 */
void GCVSplineSet::
construct(int aDegree,const Storage *aStore,double aErrorVariance)
{
    if(aStore==NULL) return;

    // DESCRIPTION
    setDescription(aStore->getDescription());

    // GET COLUMN NAMES
    const Array<std::string> &labels = aStore->getColumnLabels();
    char tmp[32];
    std::string name;

    // LOOP THROUGH THE STATES
    int nTime=1,nData=1;
    double *times=NULL,*data=NULL;
    GCVSpline *spline;
    //printf("GCVSplineSet.construct:  constructing splines...\n");
    for(int i=0;nData>0;i++) {

        // GET TIMES AND DATA
        nTime = aStore->getTimeColumn(times,i);
        nData = aStore->getDataColumn(i,data);

        // CHECK
        if(nTime!=nData) {
            std::cout << "\nGCVSplineSet.construct: ERR- number of times (" << nTime << ")"
                  << " and number of data (" << nData << ") don't agree.\n";
            break;
        }
        if(nData==0) break;

        // GET COLUMN NAME
        // Note that state i is in column i+1
        if(i+1 < labels.getSize()) {
            name = labels[i+1];
        } else {
            sprintf(tmp,"data_%d",i);
            name = tmp;
        }

        // CONSTRUCT SPLINE
        //printf("%s\t",name);
        spline = new GCVSpline(aDegree,nData,times,data,name,aErrorVariance);
        SimTK::Function* fp = spline->createSimTKFunction();
        delete fp;

        // ADD SPLINE
        adoptAndAppend(spline);
    }
    //printf("\n%d splines constructed.\n\n",i);

    // CLEANUP
    if(times!=NULL) delete[] times;
    if(data!=NULL) delete[] data;
}

//=============================================================================
// SET AND GET
//=============================================================================
//_____________________________________________________________________________
/**
 * Get the function at a specified index.
 *
 * @param aIndex Index of the desired function:  0 <= aIndex < getSize().
 * @return Function at index aIndex.  If aIndex is not value NULL is returned.
 */
GCVSpline* GCVSplineSet::
getGCVSpline(int aIndex) const
{
    GCVSpline& func = (GCVSpline&)get(aIndex);
    return(&func);
}

//=============================================================================
// UTILITY
//=============================================================================
//_____________________________________________________________________________
/**
 * Construct a storage object (see Storage) for this spline \set\ or for some
 * derivative of this spline set.
 *
 * @param aDerivOrder Derivative order.  0 constructs from the spline,
 * 1 constructs from the first derivative of the spline, 2 constructs from
 * the second derivative of the spline, etc.
 * @param aDX Spacing of the data points in the independent variable.  If
 * negative the spacing of the independent variable is taken from the
 * original data, as determined from the first non-NULL spline in the set.
 * aDX has a default value of -1.
 * @return Storage object.  If a valid storage object cannot be constructed
 * NULL is returned.
 * @see Storage
 */
Storage* GCVSplineSet::
constructStorage(int aDerivOrder,double aDX)
{
    if(aDerivOrder<0) return(NULL);
    if(getSize()<=0) return(NULL);

    // GET FIRST NON-NULL SPLINE
    GCVSpline *spl;
    int n = getSize();
    for(int i=0;i<n;i++) {
        spl = getGCVSpline(i);
        if(spl!=NULL) break;
    }
    if(spl==NULL) return(NULL);

    // HOW MANY X STEPS
    double xRange = getMaxX() - getMinX();
    int nSteps;
    if(aDX<=0.0) {
        nSteps = spl->getSize();
    } else {
        nSteps = 10 + (int)(xRange/aDX);
    }

    // CONSTRUCT STORAGE OBJECT
    std::string name="";
    if(aDerivOrder==0) {
        name=getName()+"_GCVSpline";
    } else {
        char temp[10];
        sprintf(temp, "%d", aDerivOrder);
        name=getName()+"_GCVSpline_Deriv_"+std::string(temp);
    }
    Storage *store = new Storage(nSteps,name);

    // DESCRIPTION
    store->setDescription(getDescription());

    // SET COLUMN LABELS
    GCVSpline *spline;
    Array<std::string> labels;
    labels.append("time");
    for(int i=0;i<n;i++) {
        spline = getGCVSpline(i);
        if(spline==NULL) {
            char cName[32];
            sprintf(cName,"data_%d",i);
            labels.append(std::string(cName));
        } else {
            labels.append(spline->getName());
        }
    }
    store->setColumnLabels(labels);

    // SET STATES
    Array<double> y(0.0,n);

    // LOOP THROUGH THE DATA
    // constant increments
    if(aDX>0.0) {
        for(double x=getMinX(); x<=getMaxX(); x+=aDX) {
            evaluate(y,aDerivOrder,x);
            store->append(x,n,&y[0]);
        }

    // original independent variable increments
    } else {

        const Array<double> &xOrig = spl->getX();
        for(int ix=0;ix<nSteps;ix++) {

            // ONLY WITHIN BOUNDS OF THE SET
            if(xOrig[ix]<getMinX()) continue;
            if(xOrig[ix]>getMaxX()) break;

            evaluate(y,aDerivOrder,xOrig[ix]);
            store->append(xOrig[ix],n,&y[0]);
        }
    }

    return(store);
}

double GCVSplineSet::getMinX() const
{
    double min = SimTK::Infinity;

    for (int i=0; i<getSize(); i++) {
        const GCVSpline* spl = getGCVSpline(i);
        if (spl && spl->getMinX() < min)
            min = spl->getMinX();
    }

    return min;
}

double GCVSplineSet::getMaxX() const
{
    double max = -SimTK::Infinity;

    for (int i=0; i<getSize(); i++) {
        const GCVSpline* spl = getGCVSpline(i);
        if (spl && spl->getMaxX() > max)
            max = spl->getMaxX();
    }

    return max;
}
<commit_msg>Fix comments. [skip ci]<commit_after>/* -------------------------------------------------------------------------- *
 *                         OpenSim:  GCVSplineSet.cpp                         *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Frank C. Anderson                                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

/* Note: This code was originally developed by Realistic Dynamics Inc.
 * Author: Frank C. Anderson
 */

// INCLUDES
#include "GCVSplineSet.h"
#include "GCVSpline.h"
#include "Storage.h"

//=============================================================================
// DESTRUCTOR AND CONSTRUCTORS
//=============================================================================
//_____________________________________________________________________________

using namespace OpenSim;
/**
 * Destructor.
 */
GCVSplineSet::~GCVSplineSet()
{
}

//_____________________________________________________________________________
/**
 * Default constructor.
 */
GCVSplineSet::
GCVSplineSet()
{
    setNull();
}
//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines from file.
 *
 * @param aFileName Name of the file.
 */
GCVSplineSet::
GCVSplineSet(const char *aFileName) :
    FunctionSet(aFileName)
{
    setNull();
}
//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines based on the states
 * stored in an Storage object.
 *
 * Each column in the Storage object is fit with a spline of the specified
 * degree and is named the name of its corresponding column label.  Note that
 * column labels in the storage object are assumed to be tab delimited.
 *
 * @param aDegree Degree of the constructed splines (1, 3, 5, or 7).
 * @param aStore Storage object.
 * @param aErrorVariance Estimate of the variance of the error in the data to
 * be fit.  If negative, the variance will be estimated.  If 0.0, the fit will
 * try to fit the data points exactly- no smoothing.  If
 * positive, the fits will be smoothed according to the specified variance.
 * The larger the error variance, the more the smoothing.  Note that this is
 * the error variance assumed for each column in the Storage.  If different
 * variances should be set for the various columns, you will need to
 * construct each GCVSpline individually.
 * @see Storage
 * @see GCVSpline
 */
GCVSplineSet::
GCVSplineSet(int aDegree,const Storage *aStore,double aErrorVariance)
{
    setNull();
    if(aStore==NULL) return;
    setName(aStore->getName());

    // CAPACITY
    StateVector *vec = aStore->getStateVector(0);
    if(vec==NULL) return;
    ensureCapacity(2*vec->getSize());

    // CONSTRUCT
    construct(aDegree,aStore,aErrorVariance);
}

//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines based on the states
 * stored in a TimeSeriesTable.
 *
 * Each column in the TimeSeriesTable is fit with a spline of the specified
 * degree and is named the name of its corresponding column label.
 *
 * @param table TimeSeriesTable object.
 * @param labels Columns to use from TimeSeriesTable.
 * @param degree Degree of the constructed splines (1, 3, 5, or 7).
 * @param aErrorVariance Estimate of the variance of the error in the data to
 * be fit.  If negative, the variance will be estimated.  If 0.0, the fit will
 * try to fit the data points exactly- no smoothing.  If
 * positive, the fits will be smoothed according to the specified variance.
 * The larger the error variance, the more the smoothing.  Note that this is
 * the error variance assumed for each column in the TimeSeriesTable.  If
 * different variances should be set for the various columns, you will need to
 * construct each GCVSpline individually.
 * @see TimeSeriesTable.
 * @see GCVSpline
 */
GCVSplineSet::
GCVSplineSet(const TimeSeriesTable& table,
             const std::vector<std::string>& labels,
             int degree,
             double errorVariance) {
    const auto& time = table.getIndependentColumn();
    auto labelsToUse = labels;
    if (labelsToUse.empty()) labelsToUse = table.getColumnLabels();
    for (const auto& label : labelsToUse) {
        const auto& column = table.getDependentColumn(label);
        adoptAndAppend(new GCVSpline(degree, column.size(), time.data(),
                                     &column[0], label, errorVariance));
    }
}

//=============================================================================
// CONSTRUCTION
//=============================================================================
//_____________________________________________________________________________
/**
 * Set all member variables to NULL values.
 */
void GCVSplineSet::
setNull()
{
}
//_____________________________________________________________________________
/**
 * Construct a set of generalized cross-validated splines based on the states
 * stored in an Storage object.
 *
 * @param aDegree Degree of the constructed splines (1, 3, 5, or 7).
 * @param aStore Storage object.
 * @param aErrorVariance Error variance for the data.
 */
void GCVSplineSet::
construct(int aDegree,const Storage *aStore,double aErrorVariance)
{
    if(aStore==NULL) return;

    // DESCRIPTION
    setDescription(aStore->getDescription());

    // GET COLUMN NAMES
    const Array<std::string> &labels = aStore->getColumnLabels();
    char tmp[32];
    std::string name;

    // LOOP THROUGH THE STATES
    int nTime=1,nData=1;
    double *times=NULL,*data=NULL;
    GCVSpline *spline;
    //printf("GCVSplineSet.construct:  constructing splines...\n");
    for(int i=0;nData>0;i++) {

        // GET TIMES AND DATA
        nTime = aStore->getTimeColumn(times,i);
        nData = aStore->getDataColumn(i,data);

        // CHECK
        if(nTime!=nData) {
            std::cout << "\nGCVSplineSet.construct: ERR- number of times (" << nTime << ")"
                  << " and number of data (" << nData << ") don't agree.\n";
            break;
        }
        if(nData==0) break;

        // GET COLUMN NAME
        // Note that state i is in column i+1
        if(i+1 < labels.getSize()) {
            name = labels[i+1];
        } else {
            sprintf(tmp,"data_%d",i);
            name = tmp;
        }

        // CONSTRUCT SPLINE
        //printf("%s\t",name);
        spline = new GCVSpline(aDegree,nData,times,data,name,aErrorVariance);
        SimTK::Function* fp = spline->createSimTKFunction();
        delete fp;

        // ADD SPLINE
        adoptAndAppend(spline);
    }
    //printf("\n%d splines constructed.\n\n",i);

    // CLEANUP
    if(times!=NULL) delete[] times;
    if(data!=NULL) delete[] data;
}

//=============================================================================
// SET AND GET
//=============================================================================
//_____________________________________________________________________________
/**
 * Get the function at a specified index.
 *
 * @param aIndex Index of the desired function:  0 <= aIndex < getSize().
 * @return Function at index aIndex.  If aIndex is not value NULL is returned.
 */
GCVSpline* GCVSplineSet::
getGCVSpline(int aIndex) const
{
    GCVSpline& func = (GCVSpline&)get(aIndex);
    return(&func);
}

//=============================================================================
// UTILITY
//=============================================================================
//_____________________________________________________________________________
/**
 * Construct a storage object (see Storage) for this spline \set\ or for some
 * derivative of this spline set.
 *
 * @param aDerivOrder Derivative order.  0 constructs from the spline,
 * 1 constructs from the first derivative of the spline, 2 constructs from
 * the second derivative of the spline, etc.
 * @param aDX Spacing of the data points in the independent variable.  If
 * negative the spacing of the independent variable is taken from the
 * original data, as determined from the first non-NULL spline in the set.
 * aDX has a default value of -1.
 * @return Storage object.  If a valid storage object cannot be constructed
 * NULL is returned.
 * @see Storage
 */
Storage* GCVSplineSet::
constructStorage(int aDerivOrder,double aDX)
{
    if(aDerivOrder<0) return(NULL);
    if(getSize()<=0) return(NULL);

    // GET FIRST NON-NULL SPLINE
    GCVSpline *spl;
    int n = getSize();
    for(int i=0;i<n;i++) {
        spl = getGCVSpline(i);
        if(spl!=NULL) break;
    }
    if(spl==NULL) return(NULL);

    // HOW MANY X STEPS
    double xRange = getMaxX() - getMinX();
    int nSteps;
    if(aDX<=0.0) {
        nSteps = spl->getSize();
    } else {
        nSteps = 10 + (int)(xRange/aDX);
    }

    // CONSTRUCT STORAGE OBJECT
    std::string name="";
    if(aDerivOrder==0) {
        name=getName()+"_GCVSpline";
    } else {
        char temp[10];
        sprintf(temp, "%d", aDerivOrder);
        name=getName()+"_GCVSpline_Deriv_"+std::string(temp);
    }
    Storage *store = new Storage(nSteps,name);

    // DESCRIPTION
    store->setDescription(getDescription());

    // SET COLUMN LABELS
    GCVSpline *spline;
    Array<std::string> labels;
    labels.append("time");
    for(int i=0;i<n;i++) {
        spline = getGCVSpline(i);
        if(spline==NULL) {
            char cName[32];
            sprintf(cName,"data_%d",i);
            labels.append(std::string(cName));
        } else {
            labels.append(spline->getName());
        }
    }
    store->setColumnLabels(labels);

    // SET STATES
    Array<double> y(0.0,n);

    // LOOP THROUGH THE DATA
    // constant increments
    if(aDX>0.0) {
        for(double x=getMinX(); x<=getMaxX(); x+=aDX) {
            evaluate(y,aDerivOrder,x);
            store->append(x,n,&y[0]);
        }

    // original independent variable increments
    } else {

        const Array<double> &xOrig = spl->getX();
        for(int ix=0;ix<nSteps;ix++) {

            // ONLY WITHIN BOUNDS OF THE SET
            if(xOrig[ix]<getMinX()) continue;
            if(xOrig[ix]>getMaxX()) break;

            evaluate(y,aDerivOrder,xOrig[ix]);
            store->append(xOrig[ix],n,&y[0]);
        }
    }

    return(store);
}

double GCVSplineSet::getMinX() const
{
    double min = SimTK::Infinity;

    for (int i=0; i<getSize(); i++) {
        const GCVSpline* spl = getGCVSpline(i);
        if (spl && spl->getMinX() < min)
            min = spl->getMinX();
    }

    return min;
}

double GCVSplineSet::getMaxX() const
{
    double max = -SimTK::Infinity;

    for (int i=0; i<getSize(); i++) {
        const GCVSpline* spl = getGCVSpline(i);
        if (spl && spl->getMaxX() > max)
            max = spl->getMaxX();
    }

    return max;
}
<|endoftext|>