#define BOOST_TEST_MODULE TestSolvers
#include <boost/test/unit_test.hpp>
#include <amgcl/backend/viennacl.hpp>

#include "test_solver.hpp"

BOOST_AUTO_TEST_SUITE( test_solvers )

BOOST_AUTO_TEST_CASE(test_viennacl_backend)
{
    test_backend< amgcl::backend::viennacl< viennacl::compressed_matrix<double> > >();
    test_backend< amgcl::backend::viennacl< viennacl::ell_matrix<double> > >();
    test_backend< amgcl::backend::viennacl< viennacl::hyb_matrix<double> > >();
}

BOOST_AUTO_TEST_SUITE_END()


// Copyright 2018 The Simons Foundation, Inc. - All Rights Reserved.
//
// 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.

#ifndef NETKET_ABSTRACTLAYER_HH
#define NETKET_ABSTRACTLAYER_HH

#include <Eigen/Dense>
#include <Utils/lookup.hpp>
#include <complex>
#include <fstream>
#include <random>
#include <vector>

namespace netket {
/**
  Abstract class for Neural Network layer.
*/
template <typename T>
class AbstractLayer {
 public:
  using VectorType = Eigen::Matrix<T, Eigen::Dynamic, 1>;
  using MatrixType = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
  using StateType = T;
  using LookupType = std::vector<VectorType>;
  using VectorRefType = Eigen::Ref<VectorType>;
  using VectorConstRefType = Eigen::Ref<const VectorType>;

  /**
  Member function returning the name of the layer.
  @return Name of Layer.
  */
  virtual std::string Name() const = 0;
  /**
  Member function returning the number of inputs a layer takes.
  @return Number of Inputs into the Layer.
  */
  virtual int Ninput() const = 0;

  /**
  Member function returning the number of outputs from the layer.
  @return Number of Outputs from the Layer.
  */
  virtual int Noutput() const = 0;

  /**
  Member function returning the number of variational parameters.
  @return Number of variational parameters in the Layer.
  */
  virtual int Npar() const = 0;

  /**
  Member function writing the current set of parameters in the machine.
  @param pars is where the layer parameters are written into.
  @param start_idx is the index of the vector pars to start writing from.
  */
  virtual void GetParameters(VectorRefType pars) const = 0;

  /**
  Member function setting the current set of parameters in the layer.
  @param pars is where the layer parameters are to be read from.
  @param start_idx is the index of the vector pars to start reading from.
  */
  virtual void SetParameters(VectorConstRefType pars) = 0;

  /**
  Member function providing a random initialization of the parameters.
  @param seed is the see of the random number generator.
  @param sigma is the variance of the gaussian.
  */
  virtual void InitRandomPars(int seed, double sigma) = 0;

  /**
  Member function to update the lookuptable which stores the theta of
  each layer. "Summary: This function uses input, input_changes and new_input
  to generate theta which in turn gives output on application of the nonlinear
  transformation. output_changes and new_output keeps track of how the
  output of the layer has changed due to changes in the input."
  @param input is a vector in the lookuptable storing the output from the
  previous layer. This would be the old input to the current layer.
  @param input_changes is a std::vector containing the nodes of the input
  which has changed.
  @param new_input is a vector containing the new values at the changed
  input nodes.
  @param theta is a vector in the lookuptable storing the output of the
  layer before the nonlinear function is applied.
  @param output is a vector in the lookuptable storing the previous output of
  the current layer.
  @param output_changes is a vector containing the nodes of the output which has
  changed.
  @param new_output is a vector storing the new output of the layer.
  */
  virtual void UpdateLookup(const VectorType &input,
                            const std::vector<int> &input_changes,
                            const VectorType &new_input,
                            const VectorType &output,
                            std::vector<int> &output_changes,
                            VectorType &new_output) = 0;

  /**
  Member function to feedforward through the layer. Writes the output into
  output
  @param input a constant reference to the input to the layer
  @param output reference to the output vector.
  */
  virtual void Forward(const VectorType &input, VectorType &output) = 0;

  /**
  Member function to perform backpropagation to compute derivates.
  @param prev_layer_output a constant reference to the output from previous
  layer.
  @param this_layer_output a constant reference to the output from the current
  layer.
  @param next_layer_data a constant reference to the derivative dL/dA where A is
  the activations of the current layer and L is the the final output of the
  Machine: L = log(psi(v))
  @param din a constant reference to the derivative of the input from the
  current layer.
  @param der a constant reference to the derivatives wrt to the parameters in
  the machine.
  */
  virtual void Backprop(const VectorType &prev_layer_output,
                        const VectorType &this_layer_output,
                        const VectorType &dout, VectorType &din,
                        VectorRefType der) = 0;

  virtual void to_json(json &j) const = 0;

  virtual void from_json(const json &j) = 0;

  /**
  destructor
  */
  virtual ~AbstractLayer() {}
};
}  // namespace netket

#endif


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

// Adapted from GLAS implementation by Karl Meerbergen and Toon Knappen

#ifndef MTL_VEC_VEC_TIMES_ASGN_EXPR_INCLUDE
#define MTL_VEC_VEC_TIMES_ASGN_EXPR_INCLUDE

#include <boost/static_assert.hpp>

#include <boost/numeric/mtl/vector/vec_vec_aop_expr.hpp>
#include <boost/numeric/mtl/utility/ashape.hpp>
#include <boost/numeric/mtl/operation/sfunctor.hpp>

namespace mtl { namespace vector {

// Model of VectorExpression
template <class E1, class E2>
struct vec_vec_times_asgn_expr
  : public vec_vec_aop_expr< E1, E2, mtl::sfunctor::times_assign<typename E1::value_type, typename E2::value_type> >
{
    typedef vec_vec_aop_expr< E1, E2, mtl::sfunctor::times_assign<typename E1::value_type, typename E2::value_type> > base;
    vec_vec_times_asgn_expr( E1& v1, E2 const& v2 )
	: base( v1, v2 )
    {}
};

} } // Namespace mtl::vector

#endif


#include "cnn/nodes.h"
#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/timing.h"
#include "cnn/rnn.h"
#include "cnn/gru.h"
#include "cnn/lstm.h"
#include "cnn/dict.h"
#include "cnn/expr.h"

#include <iostream>
#include <fstream>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

#include <unordered_map>
#include <unordered_set>

using namespace std;
using namespace cnn;

cnn::real pdrop = 0.5;
bool eval = false;
bool verbose = false;
unsigned INPUT_DIM = 64;
unsigned HIDDEN_DIM = 150;
unsigned TAG_HIDDEN_DIM = 64;
unsigned LABEL_SIZE = 2;

unsigned INPUT_VOCAB_SIZE = 0;

cnn::Dict word_dict;

int kSOS;
int kEOS;
int kUNK;

unordered_map<string, vector<cnn::real> > pretrained_embeddings;
vector<cnn::real> averaged_vec;

cnn::real epsilon = 0.001;
cnn::real beta = 1;

template<class T1, class T2>
struct PairCmp
{
    bool operator()(const pair<T1, T2>& a, const pair<T1, T2>& b)
    {
        return a.second > b.second;
    }
};
class Example {
public:
    vector<vector<string> > words; //multiple sents
    vector<vector<int> > word_ids; //sent_ids
    int ylabel;
};

bool ReadExample(ifstream& fin, Example& example);

/**
* Read Word Embeddings and normalize them
* @param input_file pretrained embeddings file path
* */

void ReadEmbeddings(const string& input_file)
{
    ifstream fin(input_file);
    assert(fin);
    string line;
    bool first = true;
    while(getline(fin, line))
    {
        istringstream sin(line);
        string word;
        sin>>word;
        cnn::real value;
        vector<cnn::real> vecs;
        cnn::real sum = 0.000001;
        while(sin>>value)
        {
            vecs.push_back(value);
            sum += value * value;
        }
        if(first)
        {
            first = false;
            INPUT_DIM = vecs.size();
            averaged_vec.resize(INPUT_DIM, 0.0);
        }
        //normalize to one
        sum = sqrt(sum);
        for(int j = 0; j < INPUT_DIM; j++)
        {
            averaged_vec[j] += vecs[j];
            vecs[j] /= sum;
        }
        pretrained_embeddings[word] = vecs;
        //word_dict.Convert(word);
    }
    fin.close();
    cnn::real sum = 0.000001;
    for(int j = 0; j < INPUT_DIM; j++)
    {
        averaged_vec[j] /= pretrained_embeddings.size();
        sum += averaged_vec[j] * averaged_vec[j];
    }
    sum = sqrt(sum);
    for(int j = 0; j < INPUT_DIM; j++)
    {
        averaged_vec[j] /= sum ;
    }
    cerr<<"Pretrained Embeddings: "<< pretrained_embeddings.size()<<endl;
}

void ReadCorpus(const string& input_file,
                vector<Example>& examples,
                cnn::Dict& wordDict,
                int& tlines,
                int& ttoks,
                bool isTrain = true,
                int cut_off = 1)
{
    ifstream fin(input_file);
    if(!fin) {
        cerr<<"Cannot open file: "<< input_file << endl;
        exit(0);
    }

    unordered_map<string, int> word_counts;
    int tokens = 0, types = 0;
    while(true)
    {
        Example example;
        if(!ReadExample(fin,  example)) break;
        tlines++;
        for(int t = 0; t< (int)example.words.size(); t++)
        {
            auto& title = example.words[t];
            if(isTrain)
            {
                for(int j = 0; j < (int)title.size(); j++)
                {
                    auto& word = title[j];
                    auto iter = word_counts.find(word);
                    if( iter == word_counts.end())
                    {
                        word_counts.insert(make_pair(word, 1));
                        types++;
                    }
                    else {
                        iter->second++;
                    }
                    tokens++;
                }
            }
            ttoks += title.size();
        }
        examples.push_back(example);
    }
    fin.close();

    if(isTrain)
    {
        cerr<<"[LOG] Before Pruning there are "<<  tokens << " words and " <<types<< " types."<<endl;
        std::vector<pair<string, int>> pairs;
        for (auto itr = word_counts.begin(); itr != word_counts.end(); ++itr)
            pairs.push_back(*itr);

        sort(pairs.begin(), pairs.end(), PairCmp<string, int>());

        //int top_k = 24 * 1000; //24 k
        int remaining_tokens = 0, remaining_types = 0;
        int type_count = 0;
        for(auto iter = pairs.begin(); iter != pairs.end(); iter++)
        {
            type_count++;
            //if(type_count > top_k) break;
            if(iter->second >= cut_off && cnn::rand01() < 0.5)
                //if(pretrained_embeddings.find( iter->first) != pretrained_embeddings.end() )
            {
                //cerr<< iter->first << "\t" << iter->second<<endl;
                wordDict.Convert(iter->first);
                remaining_tokens += iter->second;
                remaining_types++;
            }
        }
        cerr<<"[LOG] After Pruning there are "<<  remaining_tokens << " words and " << remaining_types<< " types."<<endl;
        cerr<<"[LOG] WordDict Size: "<< wordDict.size() << endl;
        wordDict.Freeze();
    }

    for(unsigned sent_index = 0; sent_index < examples.size(); sent_index++)
    {
        auto& example = examples[sent_index];
        int num_titles = example.words.size();
        example.word_ids.resize(num_titles);

        for(int title_index = 0; title_index < num_titles; title_index++)
        {
            example.word_ids[title_index].resize( example.words[title_index].size() );

            for(unsigned word_index = 0; word_index < example.words[title_index].size(); word_index++)
            {
                int wordId = wordDict.Convert( example.words[title_index][word_index] );

                if(wordId == -1)
                {
                    wordId = kUNK;
                    //cerr<<"kUNK ";
                }
                example.word_ids[title_index][word_index] = wordId;
                //cerr<< example.words[title_index][word_index]<<" ";
            }
            //cerr<<endl;
        }
        //cerr<< endl;
    }
    //cerr<<endl;
}
/*
void computeLRP(cnn::real Rf, const vector<cnn::real>& w, const vector<cnn::real>& s, cnn::real b, vector<cnn::real>& Rs)
{
    //implement equation (2) to equation (6) of alex's note
    assert(w.size() == s.size());
    cnn::real sum = b;
    for(unsigned k = 0; k< s.size(); k++)
        sum += w[k] * s[k];
    cnn::real append = epsilon * (sum > 0? 1: -1);
    sum += append;
    Rs.resize(s.size(), 0);
    for(unsigned k = 0; k< s.size(); k++)
        Rs[k] = Rf * w[k] * s[k] / sum;
}*/
void computeLRP_R2(cnn::real Rf, const vector<cnn::real>& w, const vector<cnn::real>& s, cnn::real b, vector<cnn::real>& Rs)
{
    //implement equation (2) to equation (6) of alex's note
    assert(w.size() == s.size());
    cnn::real sum_positive = std::max(b, 0.0f);
    cnn::real sum_negative = std::min(b, 0.0f);
    for(unsigned k = 0; k< s.size(); k++)
    {
        sum_positive += std::max(w[k] * s[k], 0.0f);
        sum_negative += std::min(w[k] * s[k], 0.0f);
    }
    Rs.resize(s.size(), 0);
    if(sum_positive == 0.0)
        sum_positive = epsilon;
    if(sum_negative == 0.0)
        sum_negative = epsilon;
    for(unsigned k = 0; k< s.size(); k++)
        Rs[k] = Rf * ((1+beta) * std::max(w[k] * s[k], 0.0f) / sum_positive - beta * std::min(w[k] *s[k], 0.0f) / sum_negative);
}
/*
void computeLRPforSum(float Rf, const vector<cnn::real>& s, vector<cnn::real>& Rs)
{
    Rs.resize(s.size(), 0);
    cnn::real sum = 0;
    for(unsigned k = 0; k< s.size(); k++)
        sum += s[k];
    cnn::real append = epsilon * (sum > 0? 1: -1);
    sum += append;
    for(unsigned k = 0; k< s.size(); k++)
        Rs[k] = Rf  * s[k] / sum;
}*/

void computeLRPforSum_R2(float Rf, const vector<cnn::real>& s, vector<cnn::real>& Rs)
{
    Rs.resize(s.size(), 0);
    cnn::real sum_positive = 0;
    cnn::real sum_negative = 0;
    if(sum_positive == 0.0)
        sum_positive = epsilon;
    if(sum_negative == 0.0)
        sum_negative = epsilon;
    for(unsigned k = 0; k< s.size(); k++)
    {
        sum_positive += std::max(s[k], 0.0f);
        sum_negative += std::min(s[k], 0.0f);
    }
    for(unsigned k = 0; k< s.size(); k++)
        Rs[k] = Rf  * ( (1+beta) *  std::max(s[k],0.0f) / sum_positive - beta * std::min(s[k], 0.0f)/sum_negative);
}

struct TitleEncoder {
    LookupParameters* p_word;  //

    Parameters* p_output_w;
    Parameters* p_output_b;
    Parameters* p_fed_o;
    Parameters* p_fed_o_b;

    explicit TitleEncoder(Model& model)
    {
        p_word = model.add_lookup_parameters(INPUT_VOCAB_SIZE, {INPUT_DIM});

        p_output_w = model.add_parameters({TAG_HIDDEN_DIM, INPUT_DIM});
        p_output_b = model.add_parameters({TAG_HIDDEN_DIM});

        p_fed_o = model.add_parameters({LABEL_SIZE, TAG_HIDDEN_DIM});
        p_fed_o_b = model.add_parameters({LABEL_SIZE});

        for( size_t  word_index = 0; word_index <  INPUT_VOCAB_SIZE; word_index++)
        {
            auto word_iter = pretrained_embeddings.find( word_dict.Convert(word_index) );
            if(word_iter != pretrained_embeddings.end())
            {
                ((LookupParameters*)p_word)->Initialize(word_index, word_iter->second);
            }
            else {
                ((LookupParameters*)p_word)->Initialize(word_index, averaged_vec);
            }
        }
    }

    Expression buildGraph(ComputationGraph&cg, const Example& example)
    {
        vector<Expression> title_exps;

        for(size_t title_index = 0; title_index < example.words.size(); title_index++)
        {
            auto& insent = example.word_ids[title_index];

            const unsigned slen = insent.size();

            vector<Expression> i_words;

            for (unsigned t = 0; t < insent.size(); ++t)
            {
                Expression i_word_t = const_lookup(cg,p_word,insent[t]);
                if (!eval) {
                    i_word_t = dropout(i_word_t, pdrop);
                }
                if(insent[t] != kUNK)
                    i_words.push_back(i_word_t);
            }
            if(i_words.size() > 1 )
            {
                //关键是这个地方
                title_exps.push_back( sum_cols(tanh(kmh_ngram(concatenate_cols(i_words), 2))) );
            }
            else if(i_words.size()> 0) {
                //这个地方用得到每个words
                title_exps.push_back(average(i_words));
            }
        }
        //这个地方用得到每个title_exps的
        Expression example_rep = average(title_exps);
        Expression param_tW = parameter(cg, p_output_w);
        Expression param_tb = parameter(cg, p_output_b);
        //Dropout可以不用管
        if(!eval)
            example_rep = dropout(example_rep, pdrop);
        //Expression i_output = rectify(param_tW * example_rep + param_tb);
        Expression i_output = tanh(param_tW * example_rep + param_tb);
        //得到example_rep的相关度也没有问题了
        if(verbose)
        {
            cg.incremental_forward();
            cerr<<(*i_output.value())<<endl;
        }

        Expression param_oW = parameter(cg, p_fed_o);
        Expression param_ob = parameter(cg, p_fed_o_b);
        Expression output_h = param_oW * i_output + param_ob;
        //f(x) 对于涨能得到多少, 对于跌能多少，应该没有问题了。
        return output_h;
    }

    Expression buildLRPGraph(ComputationGraph&cg, const Example& example)
    {
        vector<Expression> title_exps;
        vector<vector<Expression> > title_words;
        vector<Expression> title_cols;

        for(size_t title_index = 0; title_index < example.words.size(); title_index++)
        {
            auto& insent = example.word_ids[title_index];

            const unsigned slen = insent.size();

            vector<Expression> i_words;

            for (unsigned t = 0; t < insent.size(); ++t)
            {
                Expression i_word_t = const_lookup(cg,p_word,insent[t]);
                if (!eval) {
                    i_word_t = dropout(i_word_t, pdrop);
                }
                if(insent[t] != kUNK)
                    i_words.push_back(i_word_t);
            }
            if(i_words.size() > 1 )
            {
                title_words.push_back(i_words);
                //关键是这个地方
                Expression current_col = tanh(kmh_ngram(concatenate_cols(i_words), 2));
                title_exps.push_back(sum_cols(current_col) );
                title_cols.push_back(current_col);
            }
            else if(i_words.size()> 0) {
                //这个地方用得到每个words
                title_exps.push_back(average(i_words));
                title_words.push_back(i_words);
            }
        }
        //这个地方用得到每个title_exps的
        Expression example_rep = average(title_exps);
        Expression param_tW = parameter(cg, p_output_w);
        Expression param_tb = parameter(cg, p_output_b);
        //Dropout可以不用管
        if(!eval)
            example_rep = dropout(example_rep, pdrop);
        //Expression i_output = rectify(param_tW * example_rep + param_tb);
        Expression i_output = tanh(param_tW * example_rep + param_tb);
        //得到example_rep的相关度也没有问题了
        if(verbose)
        {
            cg.incremental_forward();
            cerr<<(*i_output.value())<<endl;
        }

        Expression param_oW = parameter(cg, p_fed_o);
        Expression param_ob = parameter(cg, p_fed_o_b);
        Expression output_h = param_oW * i_output + param_ob;
        //===============LRP==============================
        //Step 1: Get Rf
        auto feature_vector  = as_vector(cg.incremental_forward());
        cnn::real final_r_f = feature_vector[1] - feature_vector[0]; //预测涨的相关性, 如果final_r_f 大于0， 那么就预测涨
        //cerr<<"final_f: " << final_r_f  << "\t" << feature_vector[1]<< endl;
        //Step 2: Get R_i_output
        auto param_ob_values = as_vector(param_ob.value());
        auto param_oW_values = *(param_oW.value());
        auto i_output_values = as_vector(i_output.value());
        /*
        cnn::real sum = b_values[1];
        for(int i = 0; i< TAG_HIDDEN_DIM; i++)
            sum += param_oW_values(1, i) * i_output_values[i];
        cerr<<"comp: " << sum << "\t" << feature_vector[1] << endl; //几乎相等了
        */
        vector<cnn::real> w(TAG_HIDDEN_DIM);
        for(unsigned i = 0; i< TAG_HIDDEN_DIM; i++)
            w[i] = param_oW_values(1,i);
        vector<cnn::real> R_i_output;
        computeLRP_R2(final_r_f, w, i_output_values, param_ob_values[1], R_i_output);
        /*copy(R_i_output.begin(), R_i_output.end(), ostream_iterator<cnn::real>(cerr, " "));
        cerr<< endl;*/
        //Step 3: Get R_example_rep
        auto param_tW_values = *(param_tW.value());
        auto param_tb_values = as_vector(param_tb.value());
        auto example_rep_values = as_vector(example_rep.value());
        vector<cnn::real> R_example_rep(INPUT_DIM, 0);
        for(unsigned i = 0; i< TAG_HIDDEN_DIM; i++)
        {
            vector<cnn::real> temp_R_example_rep;
            vector<cnn::real> sw(INPUT_DIM);
            for(unsigned j = 0; j< INPUT_DIM; j++)
                sw[j] = param_tW_values(i,j);
            computeLRP_R2(R_i_output[i], sw, example_rep_values, param_tb_values[i], temp_R_example_rep);
            for(unsigned j = 0; j< INPUT_DIM; j++)
                R_example_rep[j] += temp_R_example_rep[j];
        }
        /*copy(R_example_rep.begin(), R_example_rep.end(), ostream_iterator<cnn::real>(cerr, " "));
        cerr<< endl;*/
        //Step 4: Get R_title_exps, using Equations (12) to Equations (16)
        //Expression example_rep = average(title_exps);
        vector<vector<cnn::real> > title_exps_values(title_exps.size()), R_title_exps(title_exps.size());
        for(unsigned i = 0; i< title_exps.size(); i++)
        {
            title_exps_values[i] = as_vector(title_exps[i].value());
            R_title_exps[i].resize(INPUT_DIM, 0.0);
        }
        for(unsigned i = 0; i< INPUT_DIM; i++)
        {
            vector<cnn::real> s(title_exps.size());
            for(unsigned j = 0; j< title_exps.size(); j++)
                s[j] = title_exps_values[j][i];
            vector<cnn::real> temp_R_s(title_exps.size());
            computeLRPforSum_R2(R_example_rep[i], s, temp_R_s);
            for(unsigned j = 0; j< title_exps.size(); j++)
                R_title_exps[j][i] += temp_R_s[j];
        }
        /*for(unsigned i = 0; i< title_exps.size(); i++) //这个地方把标题的每一维度加起来可以实现得到每个标题的相关性
        {
            copy(R_title_exps[i].begin(), R_title_exps[i].end(), ostream_iterator<cnn::real>(cerr, " "));
            cerr<< endl;
        }*/
        //Step 5: Get R_i_words
        size_t real_title_index = 0, title_col_index = 0;
        unordered_map<unsigned, vector<cnn::real> > R_words;
        for(size_t title_index = 0; title_index < example.words.size(); title_index++)
        {
            auto& insent = example.word_ids[title_index];

            vector<unsigned> selected_words; //选中的词

            for (unsigned t = 0; t < insent.size(); ++t)
            {
                if(insent[t] != kUNK)
                    selected_words.push_back(insent[t]);
            }
            if(selected_words.size() > 1 )
            {
                vector<Expression>& i_words  = title_words[real_title_index];
                Expression& current_col = title_cols[title_col_index];
                //title_exps.push_back( sum_cols(tanh(kmh_ngram(concatenate_cols(i_words), 2))) );
                //title_exps -> sum_cols
                //title_exps[real_title_index][i] = sum_j(current_col[i,j])
                auto current_col_values = *(current_col.value());
                assert(current_col_values.cols() == i_words.size() -1);
                vector<vector<cnn::real> > R_current_col(INPUT_DIM);
                unsigned num_cols = current_col_values.cols(); //列数
                for(size_t row_index = 0; row_index < INPUT_DIM; row_index++)
                {
                    vector<cnn::real> s(num_cols);
                    for(unsigned col_index = 0; col_index < num_cols ; col_index++)
                        s[col_index] = current_col_values(row_index, col_index);
                    vector<cnn::real> temp_R_s(num_cols);
                    computeLRPforSum_R2(R_title_exps[real_title_index][row_index], s, temp_R_s);
                    R_current_col[row_index] = temp_R_s;
                }
                //sum->kmh_ngram->i_words
                vector<vector<cnn::real> > i_words_values(i_words.size()), R_i_words(i_words.size());
                for(unsigned i = 0; i< i_words.size(); i++)
                {
                    i_words_values[i] = as_vector(i_words[i].value());
                    R_i_words[i].resize(INPUT_DIM, 0.0);
                }
                unsigned ngram = 2;
                for(size_t row_index = 0; row_index < INPUT_DIM; row_index++)
                {
                    for(size_t col_index = 0; col_index < num_cols-ngram+1; col_index++)
                    {
                        vector<cnn::real> s(ngram);
                        for(unsigned ngram_index = 0; ngram_index < ngram; ngram_index++)
                            s[ngram_index] = i_words_values[col_index + ngram_index][row_index];
                        vector<cnn::real> temp_R_s(ngram);
                        computeLRPforSum_R2(R_current_col[row_index][col_index], s, temp_R_s);
                        for(unsigned ngram_index = 0; ngram_index < ngram; ngram_index++)
                            R_i_words[col_index+ngram_index][row_index] += temp_R_s[ngram_index];
                    }
                }
                //加到每个词的身上
                for(unsigned i = 0; i< R_i_words.size(); i++)
                {
                    unsigned word = selected_words[i];
                    auto iter = R_words.find(word);
                    if(iter  == R_words.end())
                    {
                        R_words[word] = R_i_words[i];
                    }
                    else {
                        for(unsigned j = 0; j<INPUT_DIM; j++)
                            iter->second[j] += R_i_words[i][j];
                    }
                }

                real_title_index ++;
                title_col_index++;
            }
            else if(selected_words.size()> 0) {
                //title_exps.push_back(average(i_words));
                vector<Expression>& i_words  = title_words[real_title_index];
                vector<vector<cnn::real> > i_words_values(i_words.size()), R_i_words(i_words.size());
                for(unsigned i = 0; i< i_words.size(); i++)
                {
                    i_words_values[i] = as_vector(i_words[i].value());
                    R_i_words[i].resize(INPUT_DIM, 0.0);
                }
                for(unsigned i = 0; i< INPUT_DIM; i++)
                {
                    vector<cnn::real> s(i_words.size());
                    for(unsigned j = 0; j< i_words.size(); j++)
                        s[j] = i_words_values[j][i];
                    vector<cnn::real> temp_R_s(i_words.size());
                    computeLRPforSum_R2(R_title_exps[real_title_index][i], s, temp_R_s);
                    for(unsigned j = 0; j< i_words.size(); j++)
                        R_i_words[j][i] += temp_R_s[j];
                }
                //加到每个词的身上
                for(unsigned i = 0; i< R_i_words.size(); i++)
                {
                    unsigned word = selected_words[i];
                    auto iter = R_words.find(word);
                    if(iter  == R_words.end())
                    {
                        R_words[word] = R_i_words[i];
                    }
                    else {
                        for(unsigned j = 0; j<INPUT_DIM; j++)
                            iter->second[j] += R_i_words[i][j];
                    }
                }
                real_title_index ++;
            }
        }
        //6, Get sum of R_words for each word according to equation 17
        vector<pair<unsigned, cnn::real> > R_sum_words;
        for(auto& item: R_words)
        {
            auto& scores = item.second;
            cnn::real sum_score = 0;
            for(auto& score: scores)
                sum_score += score;
            R_sum_words.push_back(make_pair(item.first, sum_score));
        }
        sort(R_sum_words.begin(), R_sum_words.end(), PairCmp<unsigned, cnn::real>());
        for(auto& item: R_sum_words)
        {
            cerr<< word_dict.Convert(item.first) << "\t" << item.second << endl;
        }
        cerr<< "===" << endl;
        return output_h;
    }
};

bool IsCurrentPredictionCorrection(ComputationGraph& cg, int y_true) {
    auto v = as_vector(cg.incremental_forward());
    assert(v.size() > 1);
    int besti = 0;
    cnn::real best = v[0];
    for (unsigned i = 1; i < v.size(); ++i)
        if (v[i] > best) {
            best = v[i];
            besti = i;
        }
    if(verbose)
    {
        cerr<<"prob: ";
        copy(v.begin(), v.end(), ostream_iterator<cnn::real>(cerr, " "));
        cerr<<endl;
    }
    return (besti == y_true);
}
Expression HingeLoss(const Expression& y_pred, int y_true) {
    Expression hl = hinge(y_pred, y_true, 10.0f);
    return hl;
}

Expression CrossEntropyLoss(const Expression& y_pred, int y_true) {
    Expression lp = log_softmax(y_pred);
    Expression nll = -pick(lp, y_true);
    return nll;
}

bool ReadExample(ifstream& fin, Example& example)
{
    string label_str,line;
    int num_titles;
    if(!getline(fin, line)) return false;
    istringstream sin(line);
    sin>>label_str>>num_titles;
    //cout<<label_str<<", "<<num_titles<<endl;
    if(label_str=="+1") example.ylabel = 1;
    else example.ylabel = 0;
    example.words.resize(num_titles);

    for(int i = 0; i< num_titles; i++)
    {
        if(!getline(fin, line))
            return false;
        istringstream wsin(line);
        string word;
        while(wsin>>word)
            example.words[i].push_back(word);
    }
    return true;
    //copy(data.begin(), data.end(), ostream_iterator<cnn::real>(cout, " "));
    //cout<<endl;
}

int main(int argc, char** argv) {
    cnn::Initialize(argc, argv, 4);
    if (argc != 5 && argc != 6) {
        cerr << "Usage: " << argv[0] << " code vec train dev [model.params]\n";
        return 1;
    }
    kSOS = word_dict.Convert("<s>");
    kEOS = word_dict.Convert("</s>");
    kUNK = word_dict.Convert("|unk|");

    string stock_code = argv[1];
    vector<Example> training_examples, dev_examples;

    int tlc = 0;
    int ttoks = 0;
    cerr << "Reading Pretrained Word Vectors ... " << argv[2] << endl;
    ReadEmbeddings(argv[2]);

    cerr << "Reading training data from " << argv[3] << "...\n";

    ReadCorpus(argv[3], training_examples, word_dict, tlc, ttoks, true, 1);
    cerr << tlc << " lines, " << ttoks << " tokens, " << word_dict.size() << " types\n";
    INPUT_VOCAB_SIZE = word_dict.size();
    word_dict.SetUnk("|unk|");

    int dlc = 0;
    int dtoks = 0;
    cerr << "Reading dev data from " << argv[4] << "...\n";
    ReadCorpus(argv[4], dev_examples, word_dict, dlc, dtoks, false, 0);
    cerr << dlc << " lines, " << dtoks << " tokens\n";

    ostringstream os;
    os << stock_code<<".hier.avg"
       << '_' << INPUT_DIM
       << '_' << TAG_HIDDEN_DIM
       << '_' << pdrop;

    const string fname = os.str();
    cerr << "Parameters will be written to: " << fname << endl;
    cnn::real best = 0;

    Model model;
    bool use_momentum = false;
    Trainer* sgd = nullptr;
    if (use_momentum)
        sgd = new MomentumSGDTrainer(&model);
    //sgd = new AdagradTrainer(&model);
    else
        sgd = new SimpleSGDTrainer(&model, 1e-4);
    //sgd = new SimpleSGDTrainer(&model);

    TitleEncoder titleEncoder(model);

    if(argc == 6)
    {
        string fname = argv[5];
        ifstream in(fname);
        boost::archive::text_iarchive ia(in);
        ia >> model;

        cnn::real dcorr = 0;
        cnn::real dloss = 0;
        eval = true;
        //verbose = true;
        int dev_index = 0;
        for (auto& sent : dev_examples) {
            dev_index ++;
            const int y = sent.ylabel;
            ComputationGraph cg;
            //cerr<< "begin " << dev_index << endl;
            Expression y_pred =  titleEncoder.buildLRPGraph(cg, sent);
            if (IsCurrentPredictionCorrection(cg, y)) {
                dcorr++;
                cerr<< dev_index << " "<< y <<" "<<y<< endl;
            }
            else {
                cerr<< dev_index <<" " << y <<" "<<1-y << endl;
            }
            CrossEntropyLoss(y_pred, y);
            //cerr << "DEVLINE: " << dtags << endl;
            dloss += as_scalar(cg.incremental_forward());
        }
        cerr<<"Loss:"<< dloss/ dev_examples.size() << endl;
        cerr<<"Accuracy:"<< dcorr <<"/" << dev_examples.size()<<" "<< dcorr/dev_examples.size() << endl;
        return 0;
    }

    //unsigned report_every_i = min(100, int(training_examples.size()));
    unsigned report_every_i = int(training_examples.size());
    //unsigned si = training_examples.size();
    unsigned si = 1000;
    vector<unsigned> order(training_examples.size());
    for (unsigned i = 0; i < order.size(); ++i) order[i] = i;

    bool first = true;
    int report = 0;
    unsigned lines = 0;
    while(1) {//you should kill the program by hand during training
        Timer iteration("completed in");
        cnn::real loss = 0;
        for (unsigned i = 0; i < report_every_i; ++i) {
            //if (si == training_examples.size()) {
            if (si == 1000) {
                si = 0;
                if (first) {
                    first = false;
                }
                else {
                    sgd->update_epoch();
                }
                cerr << "**SHUFFLE\n";
                shuffle(order.begin(), order.end(), *rndeng);
                cerr << "**finish shuffle\n";
            }
            if(order[si] == 0)
                verbose = true;
            else
                verbose = false;

            // build graph for this instance
            ComputationGraph cg;
            auto& sentx_y = training_examples[order[si]];
            const int y = sentx_y.ylabel;
            //cerr << "LINE: " << order[si] << endl;
            Expression y_pred = titleEncoder.buildGraph(cg, sentx_y);
            CrossEntropyLoss(y_pred, y);
            loss += as_scalar(cg.forward());
            cg.backward();
            sgd->update(1.0);
            ++si;
            ++lines;
        }
        sgd->status();
        cerr << " E = " << (loss / lines) <<" ";

        // show score on dev data?
        report++;
        if (1) {
            cnn::real dloss = 0;
            cnn::real dcorr = 0;
            eval = true;
            for (auto& sent : dev_examples) {
                const int y = sent.ylabel;
                ComputationGraph cg;
                Expression y_pred =  titleEncoder.buildGraph(cg, sent);
                if (IsCurrentPredictionCorrection(cg, y)) dcorr++;
                CrossEntropyLoss(y_pred, y);
                dloss += as_scalar(cg.incremental_forward());
            }
            cnn::real acc = dcorr / dev_examples.size();
            if (acc >= best) {
                best = acc;
                ofstream out(fname);
                boost::archive::text_oarchive oa(out);
                oa << model;
            }
            cerr << "\n***DEV [epoch=" << (lines / (cnn::real)training_examples.size()) << "] E = " << (dloss / dev_examples.size())  << " acc=" << acc << ' '<<endl;
        }
        eval = false;
    }
    delete sgd;
}


//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_OPERATOR_FUNCTIONS_IS_EQUAL_HPP_INCLUDED
#define BOOST_SIMD_OPERATOR_FUNCTIONS_IS_EQUAL_HPP_INCLUDED

#include <boost/simd/include/functor.hpp>

namespace boost { namespace simd
{
  namespace tag
  {
   /*!
     @brief is_equal generic tag

     Represents the is_equal function in generic contexts.

     @par Models:
        Hierarchy
   **/
    struct is_equal_ : ext::elementwise_<is_equal_>
    {
      /// @brief Parent hierarchy
      typedef ext::elementwise_<is_equal_> parent;
      template<class... Args>
      static BOOST_FORCEINLINE BOOST_AUTO_DECLTYPE dispatch(Args&&... args)
      BOOST_AUTO_DECLTYPE_BODY( dispatching_is_equal_( ext::adl_helper(), static_cast<Args&&>(args)... ) )
    };
  }
  namespace ext
  {
   template<class Site>
   BOOST_FORCEINLINE generic_dispatcher<tag::is_equal_, Site> dispatching_is_equal_(adl_helper, boost::dispatch::meta::unknown_<Site>, ...)
   {
     return generic_dispatcher<tag::is_equal_, Site>();
   }
   template<class... Args>
   struct impl_is_equal_;
  }
  /*!
    Returns True or False
    according a0 and a1 are equal or not. Infix notation can be used with operator '=='

    @par Semantic:

    For every parameters of types respectively T0, T1:

    @code
    as_logical<T0> r = is_equal(a0,a1);
    @endcode

    is similar to:

    @code
    as_logical<T0> r = a0 == a1;
    @endcode

    @par Alias:
    @c eq, @c is_eq

    @see  @funcref{is_not_equal}, @funcref{is_eqz}, @funcref{is_equal_with_equal_nans}
    @param a0

    @param a1

    @return a logical value
  **/
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::is_equal_, is_equal, 2 )
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::is_equal_, eq,       2 )
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::is_equal_, is_eq,    2 )
} }

#include <boost/simd/operator/specific/common.hpp>

#endif


// This file is part of snark, a generic and flexible library for robotics research
// Copyright (c) 2011 The University of Sydney
// 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 University of Sydney nor the
//    names of its contributors may be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
// GRANTED BY THIS LICENSE.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
// HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "disparity.h"
#include <boost/thread/thread_time.hpp>

namespace snark { namespace imaging {

disparity::disparity ( const snark::imaging::camera_parser& left, const snark::imaging::camera_parser& right, unsigned int width, unsigned int height, const comma::csv::options& csv, bool input_rectified ):
    m_rotation( right.rotation() * left.rotation().transpose() ),
    m_translation( right.translation() - left.translation() ),
    m_rectify( left.camera(), left.distortion(), right.camera(), right.distortion(), width, height, m_rotation, m_translation, input_rectified ),
    m_input_rectified( input_rectified ),
    m_serialization( csv.fields, csv.format() )
{

}

disparity::disparity ( const camera_parser& left, const camera_parser& right,
                 const cv::Mat& left_x, const cv::Mat& left_y, const cv::Mat& right_x, const cv::Mat& right_y,
                 const comma::csv::options& csv, bool input_rectified ):
    m_rotation( Eigen::Matrix3d::Identity() ),
    m_translation( right.translation() - left.translation() ),
    m_rectify( left.camera(), right.camera(), m_translation, left_x, left_y, right_x, right_y, input_rectified ),
    m_input_rectified( input_rectified ),
    m_serialization( csv.fields, csv.format() )
{

}

void disparity::process( const cv::Mat& left, const cv::Mat& right, const cv::StereoSGBM& sgbm, boost::posix_time::ptime time )
{
    snark::imaging::point_cloud cloud( sgbm );

    cv::Mat disparity;
    if (!m_input_rectified)
    {
        cv::Mat leftRectified = m_rectify.remap_left( left );
        cv::Mat rightRectified = m_rectify.remap_right( right );
        disparity = cloud.get_disparity( leftRectified, rightRectified );
    }
    else
    {
        disparity = cloud.get_disparity( left, right );
    }

    m_serialization.write( std::cout, std::make_pair( time, disparity ) );
}

} }


/*
    This file is part of Nori, a simple educational ray tracer

    Copyright (c) 2012 by Wenzel Jakob and Steve Marschner.

    Nori is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License Version 3
    as published by the Free Software Foundation.

    Nori 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 <nori/parser.h>
#include <Eigen/Geometry>
#include <QFileInfo>
#include <QtGui>
#include <QtXml>
#include <QtXmlPatterns>
#include <stack>

NORI_NAMESPACE_BEGIN

class NoriParser : public QXmlDefaultHandler {
public:
	/// Set of supported XML tags
	enum ETag {
		/* Object classes */
		EScene                = NoriObject::EScene,
		EMesh                 = NoriObject::EMesh,
		EBSDF                 = NoriObject::EBSDF,
		ELuminaire            = NoriObject::ELuminaire,
		ECamera               = NoriObject::ECamera,
		EMedium               = NoriObject::EMedium,
		EPhaseFunction        = NoriObject::EPhaseFunction,
		EIntegrator           = NoriObject::EIntegrator,
		ESampler              = NoriObject::ESampler,
		ETest                 = NoriObject::ETest,
                EEvaluator            = NoriObject::EEvaluator,
		EReconstructionFilter = NoriObject::EReconstructionFilter,

		/* Properties */
		EBoolean = NoriObject::EClassTypeCount,
		EInteger,
		EFloat,
		EString,
		EPoint,
		EVector,
		EColor,
		ETransform,
		ETranslate,
		ERotate,
		EScale,
		ELookAt
	};

	NoriParser() : m_root(NULL) {
		/* Mapping from tag names to tag IDs */
		m_tags["scene"]      = EScene;
		m_tags["mesh"]       = EMesh;
		m_tags["bsdf"]       = EBSDF;
		m_tags["luminaire"]  = ELuminaire;
		m_tags["camera"]     = ECamera;
		m_tags["medium"]     = EMedium;
		m_tags["phase"]      = EPhaseFunction;
		m_tags["integrator"] = EIntegrator;
		m_tags["sampler"]    = ESampler;
		m_tags["rfilter"]    = EReconstructionFilter;
		m_tags["test"]       = ETest;
                m_tags["evaluator"]  = EEvaluator;
		m_tags["boolean"]    = EBoolean;
		m_tags["integer"]    = EInteger;
		m_tags["float"]      = EFloat;
		m_tags["string"]     = EString;
		m_tags["point"]      = EPoint;
		m_tags["vector"]     = EVector;
		m_tags["color"]      = EColor;
		m_tags["transform"]  = ETransform;
		m_tags["translate"]  = ETranslate;
		m_tags["rotate"]     = ERotate;
		m_tags["scale"]      = EScale;
		m_tags["lookat"]     = ELookAt;
	}

	struct ParserContext {
		QXmlAttributes attr;
		PropertyList propList;
		std::vector<NoriObject *> children;

		inline ParserContext(const QXmlAttributes &attr) : attr(attr) { }
	};

	float parseFloat(const QString &str) const {
		bool success;
		float result = str.toFloat(&success);
		if (!success)
			throw NoriException(QString("Unable to parse floating point value '%1'!").arg(str));
		return result;
	}

	Vector3f parseVector(const QString &str) const {
		QRegExp re("[\\s,]+");
		QStringList list = str.split(re);
		if (list.size() != 3)
			throw NoriException(QString("Cannot parse 3-vector '%1'!").arg(str));

		Vector3f result;
		for (int i=0; i<3; ++i)
			result[i] = parseFloat(list[i]);
		return result;
	}

        Eigen::Affine3f parseTransform(const QString &str) const {
                QRegExp re1("[\\s]*;[\\s]*");
		QStringList rows = str.split(re1);
		if (rows.size() != 4)
			throw NoriException(QString("Cannot parse affine transform '%1'!").arg(str));

                Eigen::Affine3f transform;
		for (int i=0; i<4; ++i){
                        QRegExp re2("[\\s,]+");
                        QStringList list = rows[i].split(re2);
                        if (list.size() != 4)
                                throw NoriException(QString("Cannot parse transform row '%1'!").arg(rows[i]));
                        for(int j=0; j < 4; ++j) transform(i, j) = parseFloat(list[j]);
                }
                return transform;
        }

	bool startElement(const QString & /* unused */, const QString &name,
		const QString& /* unused */, const QXmlAttributes &attr) {

		ParserContext ctx(attr);

		if (name == "transform")
			m_transform.setIdentity();
		else if (name == "scene")
			ctx.attr.append("type", "", "type", "scene");

		m_context.push_back(ctx);
		return true;
	}

	bool endElement(const QString & /* unused */, const QString &name,
			const QString& /* unused */) {
		std::map<QString, ETag>::const_iterator it = m_tags.find(name);
		ParserContext &context = m_context.back();

		if (it == m_tags.end())
			throw NoriException(QString("Encountered an unknown tag '%1'!").arg(name));

		int tag = (int) it->second;

		if (tag < NoriObject::EClassTypeCount) {
			/* This is an object, first instantiate it */
			NoriObject *obj = NoriObjectFactory::createInstance(
				context.attr.value("type"),
				context.propList
			);

			if (obj->getClassType() != (int) tag)
				throw NoriException(QString("Unexpectedly constructed an object "
					"of type <%1> (expected type <%2>): %3")
				.arg(NoriObject::classTypeName(obj->getClassType()))
				.arg(NoriObject::classTypeName((NoriObject::EClassType) tag))
				.arg(obj->toString()));

			/* Add all children */
			for (size_t i=0; i<context.children.size(); ++i) {
				obj->addChild(context.children[i]);
				context.children[i]->setParent(obj);
			}

			/* Activate / configure the object */
			obj->activate();

			/* Add it to its parent, if there is one */
			if (m_context.size() >= 2)
				m_context[m_context.size() - 2].children.push_back(obj);
			else
				m_root = obj;
		} else {
			/* This is a property */
			PropertyList &propList = m_context[m_context.size() - 2].propList;
			bool success;

			switch (tag) {
				case EString: {
						propList.setString(context.attr.value("name"),
							context.attr.value("value"));
					}
					break;

				case EInteger: {
						QString value = context.attr.value("value");
						int result = value.toInt(&success);
						if (!success)
							throw NoriException(QString("Unable to parse integer value '%1'!").arg(value));
						propList.setInteger(context.attr.value("name"), result);
					}
					break;

				case EFloat: {
						QString value = context.attr.value("value");
						float result = value.toFloat(&success);
						if (!success)
							throw NoriException(QString("Unable to parse float value '%1'!").arg(value));
						propList.setFloat(context.attr.value("name"), result);
					}
					break;

				case EBoolean: {
						QString value = context.attr.value("value").toLower();
						if (value != "true" && value != "false")
							throw NoriException(QString("Unable to parse boolean value '%1'!").arg(value));
						propList.setBoolean(context.attr.value("name"), value == QString("true"));
					}
					break;

				case EPoint: {
						Vector3f v = parseVector(context.attr.value("value"));
						propList.setPoint(context.attr.value("name"), Point3f(v));
					}
					break;

				case EVector: {
						Vector3f v = parseVector(context.attr.value("value"));
						propList.setVector(context.attr.value("name"), v);
					}
					break;

				case EColor: {
						Vector3f v = parseVector(context.attr.value("value"));
						propList.setColor(context.attr.value("name"), Color3f(v.x(), v.y(), v.z()));
					}
					break;

				case ETransform: {
						QString direct = context.attr.value("value");
						if(direct.length() > 0) m_transform = parseTransform(direct); // TODO warning if we replace stuff!
						propList.setTransform(context.attr.value("name"),
							Transform(m_transform.matrix()));
					}
					break;

				case ETranslate: {
						Vector3f v = parseVector(context.attr.value("value"));
						m_transform = Eigen::Translation<float, 3>(v.x(), v.y(), v.z()) * m_transform;
					}
					break;

				case EScale: {
						Vector3f v = parseVector(context.attr.value("value"));
						m_transform = Eigen::DiagonalMatrix<float, 3>(v) * m_transform;
					}
					break;

				case ERotate: {
						float angle = degToRad(parseFloat(context.attr.value("angle")));
						Vector3f axis = parseVector(context.attr.value("axis")).normalized();
						m_transform = Eigen::AngleAxis<float>(angle, axis) * m_transform;
					}
					break;

				case ELookAt: {
						Point3f origin = parseVector(context.attr.value("origin"));
						Point3f target = parseVector(context.attr.value("target"));
						Vector3f up     = parseVector(context.attr.value("up")).normalized();

						Vector3f dir = (target - origin).normalized();
						Vector3f left = up.normalized().cross(dir);
						Vector3f newUp = dir.cross(left);

						Eigen::Matrix4f trafo;
						trafo << left, newUp, dir, origin,
							      0, 0, 0, 1;

						m_transform = Eigen::Affine3f(trafo) * m_transform;
					}
					break;

			}
		}

		m_context.pop_back();
		return true;
	}

	inline NoriObject *getRoot() const {
		return m_root;
	}
private:
	std::map<QString, ETag> m_tags;
	std::vector<ParserContext> m_context;
	Eigen::Affine3f m_transform;
	NoriObject *m_root;
};

/// Handle XML schema verification errors
class NoriMessageHandler : public QAbstractMessageHandler {
public:
	void handleMessage(QtMsgType type, const QString &descr,
			const QUrl &, const QSourceLocation &loc) {
		const char *typeName;
		switch (type) {
			case QtDebugMsg: typeName = "Debug"; break;
			case QtWarningMsg: typeName = "Warning"; break;
			case QtCriticalMsg: typeName = "Critical"; break;
			case QtFatalMsg:
			default: typeName = "Fatal"; break;
		}

		/* Convert the HTML error message to plain text */
		QXmlStreamReader xml(descr);
		QString text;
		while (!xml.atEnd())
			if (xml.readNext() == QXmlStreamReader::Characters)
				text += xml.text();

		cerr << typeName << ": " << qPrintable(text);
		if (!loc.isNull())
			cerr << " (line " << loc.line() << ", col " << loc.column() << ")";
		cerr << endl;
	}
};

NoriObject *loadScene(const QString &filename) {
	NoriParser parser;
	QFile schemaFile(":/schema.xsd");
	QXmlSchema schema;

	#if !defined(PLATFORM_WINDOWS)
		/* Fixes number parsing on some machines (notably those with locale ru_RU) */
		setlocale(LC_NUMERIC, "C");
	#endif

	NoriMessageHandler handler;
	schema.setMessageHandler(&handler);
	if (!schemaFile.open(QIODevice::ReadOnly))
		throw NoriException("Unable to open the XML schema!");
	if (!schema.load(schemaFile.readAll()))
		throw NoriException("Unable to parse the XML schema!");

	QXmlSchemaValidator validator(schema);
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly))
		throw NoriException(QString("Unable to open the file \"%1\"").arg(filename));
	if (!validator.validate(&file))
		throw NoriException(QString("Unable to validate the file \"%1\"").arg(filename));

        // register the base directory
        NoriObjectFactory::setBasedir(QFileInfo(file).absoluteDir().path());

	QXmlInputSource source(&file);
	file.seek(0);
	QXmlSimpleReader reader;
	reader.setContentHandler(&parser);
	if (!reader.parse(source))
		throw NoriException(QString("Unable to parse the file \"%1\"").arg(filename));

	return parser.getRoot();
}

NORI_NAMESPACE_END


#ifndef ABSTRACT_INTERFACE_HH
#define ABSTRACT_INTERFACE_HH

#include <memory>
#include <iostream>
#include <boost/signals2.hpp>
#include <string>
#include <cmath>
#include <vector>

#include <dune/grid/config.h>
#include "linalg/triplet.hh"

namespace Kaskade
{
  /**
   * @file
   * @brief  Interfaces for function space oriented algorithms
   * @author Anton Schiela
   */
  /** \addtogroup abstract*/
  /**@{*/

  /// Abstract Vector for function space algorithms
  class AbstractFunctionSpaceElement
  {
  public:
    // No copy constructor.
    AbstractFunctionSpaceElement(AbstractFunctionSpaceElement const &) = delete;

    virtual ~AbstractFunctionSpaceElement() {}

    /// *this += alpha*l
    AbstractFunctionSpaceElement& axpy(double alpha, AbstractFunctionSpaceElement const& l, int component)
    {
      if(this==&l)
      {
        std::vector<double> alphaV(nComponents(),alpha+1.0);
        return doscale(alphaV);
      }
      else
        return doaxpy(alpha, l, component);
    }

    AbstractFunctionSpaceElement& axpy(double alpha, AbstractFunctionSpaceElement const&l, std::string const role)
    {
      return axpy_role(alpha,l,role);
    }

    AbstractFunctionSpaceElement& axpy_role(double alpha, AbstractFunctionSpaceElement const&l, std::string const role)
    {
      for(int i=0; i<nComponents(); ++i)
      {
        if(getRole(i)==role) axpy(alpha,l,i);
      }
      return *this;
    }

    /// *this += alpha*l
    AbstractFunctionSpaceElement& axpy(double alpha, AbstractFunctionSpaceElement const& l)
    {
      if(this==&l)
      {
        std::vector<double> alphaV(nComponents(),alpha+1.0);
        return doscale(alphaV);
      }
      else
        return doaxpy_(alpha, l);
    }

    /// Assignment
    AbstractFunctionSpaceElement& operator=(AbstractFunctionSpaceElement const& v)
    {
      if(this!=&v) return doassign(v);
      return *this;
    }

    /// Basic vector arithmetic
    AbstractFunctionSpaceElement& operator+=(AbstractFunctionSpaceElement const& v) { return doaxpy_(1.0,v); }
    /// Basic vector arithmetic
    AbstractFunctionSpaceElement& operator-=(AbstractFunctionSpaceElement const& v) { return doaxpy_(-1.0,v); }
    /// Basic vector arithmetic
    AbstractFunctionSpaceElement& operator*=(double lambda)
    {
      std::vector<double> lambdaV(nComponents(),lambda);
      return doscale(lambdaV);
    }

    /// Scaling each component of the vector separately
    AbstractFunctionSpaceElement& operator*=(std::vector<double>const& lambda)
    {
      return doscale(lambda);
    }

    /// Interpret *this as a dual vector, and apply it to v
    /** Duality is currently not represented by types, hence users have to make
  sure that the dual pairing <*this,v> is mathematically meaningful. The standard
 implementation of the dual pairing in Bridge::Vector is
 the dot-product between the coordinate representations of *this and v.
 For that *this should be the result of AbstractLinearization::evald
     */
    double applyAsDualTo(AbstractFunctionSpaceElement const& v, int component) const
    {
      return doapplyAsDualTo(v,component,component+1);
    }

    double applyAsDualTo(AbstractFunctionSpaceElement const& v) const
    {
      return doapplyAsDualTo(v,0,nComponents());
    }

    double applyAsDualTo(AbstractFunctionSpaceElement const& v, std::string const& role) const
    {
      return applyAsDualTo_role(v,role);
    }

    double applyAsDualTo_role(AbstractFunctionSpaceElement const&v, std::string const role) const
    {
      double res(0.0);
      for(int i=0; i<nComponents(); ++i)
      {
        if(getRole(i)==role) res+=applyAsDualTo(v,i);
      }
      return res;
    }

    virtual std::string getRole(int component) const = 0;

    /// Shallow swap
    void swap(AbstractFunctionSpaceElement& v) { doswap(v); }

    virtual int nComponents() const = 0;

    /// Optional output
    virtual void writeToFile(std::string const& file, bool append, int order=1) const {}

    /// Optional output
    virtual void print(std::string const& message="") const { std::cout << "AbstractFunctionSpaceElement: No printing available!" << std::endl;}

    /// Construction of a vector of the same type
    virtual std::unique_ptr<AbstractFunctionSpaceElement> clone() const = 0;

    /// Construction of a vector of the same type
    virtual std::unique_ptr<AbstractFunctionSpaceElement> initZeroVector() const = 0;

  private:
    /// Interface for implementation
    virtual AbstractFunctionSpaceElement& doaxpy(double alpha, AbstractFunctionSpaceElement const& l, int component) = 0;
    virtual AbstractFunctionSpaceElement& doaxpy_(double alpha, AbstractFunctionSpaceElement const& l) = 0;
    /// Interface for implementation
    virtual AbstractFunctionSpaceElement& doscale(std::vector<double> const& lambda) = 0;
    /// Interface for implementation
    virtual AbstractFunctionSpaceElement& doassign(AbstractFunctionSpaceElement const& l) = 0;
    /// Interface for implementation
    virtual void doswap(AbstractFunctionSpaceElement& l) = 0;
    virtual double doapplyAsDualTo(AbstractFunctionSpaceElement const& v,int vbegin, int vend) const = 0;

  protected:
    AbstractFunctionSpaceElement() {}
  };

  /// Abstract linearization.
  /** Given a nonlinear functional, this class represents second order information at the point of linearization
   */
  class AbstractLinearization
  {
  public:
    /// Evaluate functional
    virtual double eval() const = 0;
    /// Evaluate L1 norm of integrand
    virtual double evalL1norm() const = 0;
    /// Evaluate derivative
    virtual void evald(AbstractFunctionSpaceElement &g, int rbegin=0, int rend=-1) const = 0;
    /// Evaluate hessian times second argument: y = y+ddf*x
    void ddxpy(AbstractFunctionSpaceElement& y, AbstractFunctionSpaceElement const& x, int rbegin=0, int rend=-1, int cbegin=0, int cend=-1) const
    {
      d2axpy(1.0,y,x,rbegin,rend,cbegin,cend);
    }
    /// Evaluate hessian times second argument: y = y+ddf*x
    void ddtxpy(AbstractFunctionSpaceElement& y, AbstractFunctionSpaceElement const& x, int rbegin=0, int rend=-1, int cbegin=0, int cend=-1) const
    {
      d2taxpy(1.0,y,x,rbegin,rend,cbegin,cend);
    }
    /// Evaluate hessian times second argument: y = y+a*ddf*x
    virtual void d2axpy(double a, AbstractFunctionSpaceElement& y, AbstractFunctionSpaceElement const& x, int rbegin=0, int rend=-1, int cbegin=0, int cend=-1) const = 0;
    /// Evaluate hessian times second argument: y = y+a*ddf*x
    virtual void d2taxpy(double a, AbstractFunctionSpaceElement& y, AbstractFunctionSpaceElement const& x, int rbegin=0, int rend=-1, int cbegin=0, int cend=-1) const = 0;
    /// Access matrix representation if available.
    virtual void getMatrixBlocks(MatrixAsTriplet<double>& mat, int rbegin=0, int rend=-1, int cbegin=0, int cend=-1) const = 0;//{ assert(!"not implemented"); }
    /// Get point of linearization
    virtual AbstractFunctionSpaceElement const& getOrigin() const = 0;

    virtual void precompute() = 0;

    virtual void flush() = 0;

    virtual ~AbstractLinearization() {}
  };

  class AbstractPreconditioner
  {
  public:
    virtual void setLinearization(AbstractLinearization&) = 0;
    virtual void apply(AbstractFunctionSpaceElement const& x, AbstractFunctionSpaceElement& Px) = 0;
  };

  /// Abstract connection.
  /**
   * Connect signal to flush() (in general for invalidating assembled data on grid refinement)
   */
  class AbstractFlushConnection
  {
  public:
    virtual ~AbstractFlushConnection(){}
    virtual void connectToSignalForFlush(boost::signals2::signal<void()>&) = 0;
  };

  class AbstractConnectedLinearization : public AbstractLinearization, public AbstractFlushConnection
  {};

  /// Representation of a nonlinear functional
  class AbstractFunctional
  {
  public:
    virtual double evaluate(AbstractFunctionSpaceElement const& x) const { assert(!"not implemented"); return 0; }
    virtual std::unique_ptr<AbstractLinearization> getLinearization(AbstractFunctionSpaceElement const& x) const = 0;
    virtual std::unique_ptr<AbstractFunctionSpaceElement> getImageVector(AbstractFunctionSpaceElement const& x) const = 0;
    virtual bool inDomain(AbstractFunctionSpaceElement const& x) const { return true; }
    virtual ~AbstractFunctional() {}
  };

  /// Representation of parameters
  class AbstractParameters
  {
  public:
    virtual ~AbstractParameters() {}
  };

  /// ...for parameter dependent functionals, implements AbstractParameters
  template<typename ParameterType>
  class Parameters : public AbstractParameters
  {
  public:
    explicit Parameters(ParameterType const& p) : pref(p) {}
    ParameterType const& getPars() const {return pref;}
  private:
    ParameterType const& pref;
  };

  ///
  template<class ParameterType>
  Parameters<ParameterType> makePars(ParameterType const& p) { return Parameters<ParameterType>(p); }

  /// Creates a functional from a homotopy of functionals by inserting a parameter
  class AbstractParameterFunctional
  {
  public:
    virtual std::unique_ptr<AbstractFunctional> getFunctional(AbstractParameters const&) const = 0;
    virtual std::unique_ptr<AbstractFunctional> getParameterLinFunctional(AbstractParameters const& p) const
          { assert(!"ParameterFunctional: Linearization not Implemented"); return getFunctional(p);}
    virtual std::unique_ptr<AbstractFunctional> getLinFunctionValue(AbstractParameters const& p) const
          { assert(!"ParameterFunctional: Linearization not Implemented"); return getFunctional(p);}
    virtual ~AbstractParameterFunctional() {}
  };

  /// Class that models the functionality of a (possibly inexact) linear solver
  class AbstractNewtonDirection
  {
  public:
    /** This method is not const, since the internal state of the solver may be modified */
    /** Computes an undamped ordinary Newton step, i.e., \f$correction=-F'(x)^{-1}F(x)\f$*/
    void ordinary(AbstractFunctionSpaceElement& correction, AbstractLinearization& linearization)
    {  doSolve(correction, linearization);
    correction *= -1.0;
    }
    /** Computes an undamped simplified Newton step, i.e., correction=-F'(xold)^{-1}F(x)*/
    void simplified(AbstractFunctionSpaceElement& correction, AbstractLinearization const& linearization, AbstractLinearization const& oldlinearization) const
    {  doResolve(correction, linearization, oldlinearization);
    correction *= -1.0;
    }

    /** Computes an undamped simplified Newton step, i.e., correction=-F'(xold)^{-1}F(x)*/
    /** where F'(xold)^{-1} has been kept from an earlier ordinary() call */
    void simplified(AbstractFunctionSpaceElement& correction, AbstractLinearization const& linearization) const
    {  doResolve(correction, linearization);
    correction *= -1.0;
    }

    /// Specify accuracy that should be achieved
    virtual void setRelativeAccuracy(double accuracy) = 0;
    /// Specify accuracy that should be achieved
    virtual void setAbsoluteAccuracy(double) {}
    /// Get accuracy that was actually achieved
    virtual double getRelativeAccuracy() = 0;
    /// Get accuracy that was actually achieved
    virtual double getAbsoluteAccuracy() = 0;

    virtual bool improvementPossible() = 0;

    virtual bool changedGrid() { return false; }

    virtual ~AbstractNewtonDirection() {}

    /// Solve Newton System: correction = +F'(iterate)^{-1}F(iterate)
    virtual void doSolve(AbstractFunctionSpaceElement& correction,
        AbstractLinearization& lin) = 0;
    /// Solve simplified Newton system: scorrection = +F'(iterate)^{-1}F(trialIterate)
    virtual void doResolve(AbstractFunctionSpaceElement& correction,
        AbstractLinearization const& lin,
        AbstractLinearization const& olin) const = 0;

    /// Solve simplified Newton system: scorrection = +F'(iterate)^{-1}F(trialIterate)
    virtual void doResolve(AbstractFunctionSpaceElement& correction,
        AbstractLinearization const& lin) const = 0;

    mutable boost::signals2::signal<void()> changed;
  };

  class AbstractChart
  {
  public:
    virtual void addPerturbation
    (AbstractFunctionSpaceElement& newIterate,
        AbstractFunctionSpaceElement const& perturbation,
        AbstractLinearization const& lin,
        std::vector<std::shared_ptr<AbstractFunctionSpaceElement> > basis = std::vector<std::shared_ptr<AbstractFunctionSpaceElement> >()) const = 0;

    virtual std::unique_ptr<AbstractChart> clone() const = 0;
  };

  class AbstractNorm
  {
  public:
    virtual ~AbstractNorm(){}
    virtual double operator()(AbstractFunctionSpaceElement const&) const = 0;
    virtual void setOrigin(AbstractLinearization const&) {}
  };

  class AbstractScalarProduct : public AbstractNorm
  {
  public:
    virtual double operator()(AbstractFunctionSpaceElement const&, AbstractFunctionSpaceElement const&) const = 0;
    double operator()(AbstractFunctionSpaceElement const& v) const
    {
      double sc = this->operator()(v,v);
      if(sc < 0) std::cout << "Warning: scalar product not positive definite! Taking absolute value" << std::endl;
      return sqrt(std::fabs(sc));
    }
  };

  ///Representation of an error estimate, i.e. the output of an error estimator
  class AbstractErrorEstimate
  {
  public:
    virtual double absoluteError() const = 0;
    virtual ~AbstractErrorEstimate() {}
  };

  /// Representation of an error estimator
  class AbstractErrorEstimator
  {
  public:
    virtual std::unique_ptr<AbstractErrorEstimate> createEstimate(AbstractFunctionSpaceElement const& correction,
        AbstractLinearization const& lin) const = 0;
    virtual ~AbstractErrorEstimator() {}
  };

  ///Representation of an adaptive grid and a simple set of operations thereon
  class AbstractAdaptiveGrid
  {
  public:
    /// Change grid according to marked elements
    virtual void adapt() = 0;
    /// Mark elements, using an error estimate that hold error indicators
    virtual void mark(AbstractErrorEstimate&, double portion) = 0;
    /// Remove all marks in the grid
    virtual void flushMarks() = 0;
    /// Number of patches
    virtual int size() = 0;
    virtual ~AbstractAdaptiveGrid() {}

    virtual int getNMarked() = 0;

    /// Inform others that the grid will change
    mutable boost::signals2::signal<void()> gridWillChange;
  };

  class AbstractHierarchicalErrorEstimator
  {
  public:
    virtual ~AbstractHierarchicalErrorEstimator(){}

    virtual void operator()(AbstractLinearization const& lin, AbstractFunctionSpaceElement const& x, AbstractFunctionSpaceElement const& dx, int, AbstractFunctionSpaceElement const& rhs) = 0;

    virtual void refineGrid() = 0;

    virtual double estimatedAbsoluteError() const = 0;

    virtual size_t gridSize() const = 0;

//    virtual void setNorm(AbstractNorm const&) = 0;
  };

  class ContinuousScalarFunction
  {
  public:
    virtual ~ContinuousScalarFunction() {}
    virtual double d0(std::vector<double> const&) const = 0;
  };

  class DifferentiableScalarFunction : public ContinuousScalarFunction
  {
  public:
    virtual ~DifferentiableScalarFunction() {}

    virtual std::vector<double> d1(std::vector<double> const&) const = 0;
  };

/** @}*/

}  // namespace Kaskade
#endif


// Copyright András Vukics 2006–2020. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt)
#include "Mode.tcc"

#include "TridiagonalHamiltonian.h"

#include <boost/assign/list_inserter.hpp>

using std::cout; using std::endl; using std::string;
using namespace boost;
using namespace cppqedutils;

namespace mode {

#define DEFINE_make_by_redirect(AUX) const Ptr make(const BOOST_PP_CAT(Pars,AUX) & p, QM_Picture qmp) {return make<Averaged>(p,qmp);}

DEFINE_make_by_redirect()
DEFINE_make_by_redirect(Lossy)
DEFINE_make_by_redirect(Pumped)
DEFINE_make_by_redirect(PumpedLossy)

#undef DEFINE_make_by_redirect

const Tridiagonal aop(size_t);

////////
//
// Exact
//
////////

Exact::Exact(dcomp zI, double omegaKerr, size_t dim)
  : FreeExact(dim), zI_(zI), omegaKerr_(omegaKerr)
{
}

void Exact::updateU(Time t) const
{
  getDiagonal()=exp(-zI_*(double(t)*blitz::tensor::i));
}

//////////////
//
// Hamiltonian
//
//////////////

#define KERRDIAGONAL(d,o) d=(i-1.)*i; d*=o/DCOMP_I;

const Tridiagonal::Diagonal mainDiagonal(dcomp z, double omegaKerr, size_t dim)
{
  using blitz::tensor::i;
  Tridiagonal::Diagonal res1(dim), res2(dim);
  res1=i; res1*=z;
  KERRDIAGONAL(res2,omegaKerr)
  return Tridiagonal::Diagonal(res1+res2);
}

const Tridiagonal pumping(dcomp eta, size_t dim)
{
  return tridiagMinusHC(eta*aop(dim).dagger());
}

namespace {

Tridiagonal hOverI(dcomp z, dcomp eta, double omegaKerr, size_t dim)
// Here we use runtime dispatching because runtime dispatching will anyway happen at the latest in some maker function.
{
  bool isPumped=isNonZero(eta);
  if (isNonZero(z)) {
    Tridiagonal res(mainDiagonal(-z,omegaKerr,dim));
    if (isPumped) return res+pumping(eta,dim);
    else return res;
  }
  else if(isPumped) return pumping(eta,dim);
  else return Tridiagonal();
}

}

#define FILLKERR using blitz::tensor::i; Tridiagonal::Diagonal temp(dim); KERRDIAGONAL(temp,omegaKerrAlter) getH_OverIs().push_back(Tridiagonal(temp));

template<> template<>
Hamiltonian<true >::Hamiltonian(dcomp zSch, dcomp zI, dcomp eta, double omegaKerr, double omegaKerrAlter, size_t dim)
  : Base(furnishWithFreqs(hOverI(zSch,eta,omegaKerr,dim),mainDiagonal(zI,omegaKerr,dim))), Exact(zI,omegaKerr,dim), zSch_(zSch), eta_(eta), dim_(dim)
{
  FILLKERR
}

template<> template<>
Hamiltonian<false>::Hamiltonian(dcomp zSch, dcomp eta, double omegaKerr, double omegaKerrAlter, size_t dim)
  : Base(hOverI(zSch,eta,omegaKerr,dim)), zSch_(zSch), eta_(eta), dim_(dim)
{
  FILLKERR
}

#undef KERRDIAGONAL
#undef FILLKERR

//////////////
//
// Liouvillean
//
//////////////

void details::aJump   (StateVectorLow& psi, double kappa) // kappa is kappa*(nTh+1) when the temperature is finite
{
  double fact=sqrt(2.*kappa);
  int ubound=psi.ubound(0);
  for (int n=0; n<ubound; ++n)
    psi(n)=fact*sqrt(n+1)*psi(n+1);
  psi(ubound)=0;
}

void details::aDagJump(StateVectorLow& psi, double kappa) // kappa is kappa* nTh    when the temperature is finite
{
  double fact=sqrt(2.*kappa);
  for (int n=psi.ubound(0); n>0; --n)
    psi(n)=fact*sqrt(n)*psi(n-1);
  psi(0)=0;
}

void details::aSuperoperator(const DensityOperatorLow& rho, DensityOperatorLow& drhodt, double kappa)
{
  for (int m=0; m<rho.ubound(0); ++m)
    for (int n=0; n<rho.ubound(1); ++n)
      drhodt(m,n)+=2*kappa*sqrt((m+1)*(n+1))*rho(m+1,n+1);
}

void details::aDagSuperoperator(const DensityOperatorLow& rho, DensityOperatorLow& drhodt, double kappa)
{
  for (int m=1; m<=rho.ubound(0); ++m)
    for (int n=1; n<=rho.ubound(1); ++n)
      drhodt(m,n)+=2*kappa*sqrt(m*n)*rho(m-1,n-1);
}

///////////
//
// Averaged
//
///////////

namespace {

typedef cppqedutils::KeyPrinter::KeyLabels KeyLabels;

const KeyLabels Assemble(const KeyLabels& first, const KeyLabels& middle, const KeyLabels& last=KeyLabels())
{
  KeyLabels res(first); boost::assign::push_back(res).range(middle).range(last);
  return res;
}

}

Averaged::Averaged(const KeyLabels& follow, const KeyLabels& precede)
  : Base(keyTitle,
         Assemble(precede,KeyLabels{"<number operator>","VAR(number operator)","real(<ladder operator>)","imag(\")"},follow))
{
}

const Averages Averaged::average_v(NoTime, const LazyDensityOperator& matrix) const
{
  auto averages(initializedAverages());

  for (int n=1; n<int(matrix.getDimension()); n++) {

    double diag=matrix(n);
    averages(0)+=  n*diag;
    averages(1)+=n*n*diag;

    dcomp offdiag(sqrt(n)*matrix(n)(n-1));
    averages(2)+=real(offdiag);
    averages(3)+=imag(offdiag);

  }

  return averages;

}

void Averaged::process_v(Averages& averages) const
{
  averages(1)-=sqr(averages(0));
}

AveragedQuadratures::AveragedQuadratures(const KeyLabels& follow, const KeyLabels& precede)
  : Averaged(Assemble(KeyLabels{"VAR(X)","VAR(Y)","COV(X,Y)"},follow),precede)
{
}

const Averages AveragedQuadratures::average_v(NoTime t, const LazyDensityOperator& matrix) const
{
  auto averages(initializedAverages());

  averages(blitz::Range(0,3))=Averaged::average_v(t,matrix)(blitz::Range(0,3));

  for (int n=2; n<int(matrix.getDimension()); n++) {

    dcomp  offdiag(sqrt(n*(n-1.))*matrix(n)(n-2));
    averages(4)+=real(offdiag);
    averages(5)+=imag(offdiag);

  }

  return averages;

}

void AveragedQuadratures::process_v(Averages& averages) const
{
  {
    Averages ranged(averages(blitz::Range(0,3)));
    Averaged::process_v(ranged);
  }

  double
    Re_aSqrExpVal=averages(4),
    Re_aExpVal=averages(2),
    Im_aExpVal=averages(3);

  double
    a=averages(0)+.5+Re_aSqrExpVal-2*sqr(Re_aExpVal), // <X^2>-<X>^2
    b=averages(0)+.5-Re_aSqrExpVal-2*sqr(Im_aExpVal), // <Y^2>-<Y>^2
    c=averages(5)-2*Re_aExpVal*Im_aExpVal; // <(XY+YX)/2>-<X><Y>

  averages(4)=a;
  averages(5)=b;
  averages(6)=c;

  /*
  Eigenvalues of the real matrix
    ( a c )
    ( c b )
  */

  /*
    double
    temp1=(a+b)/2,
    temp2=sqrt(sqr(a-b)+4*sqr(c))/2;

    averages(4)=temp1+temp2;
    averages(5)=temp1-temp2;

    averages(6)=atan((-a+b)/(2*c)+temp2/c);
  */
}

//////////
//
// Helpers
//
//////////

const Tridiagonal aop(size_t dim)
{
  typedef Tridiagonal::Diagonal Diagonal;
  Diagonal diagonal(dim-1);
  return Tridiagonal(Diagonal(),1,Diagonal(),diagonal=sqrt(blitz::tensor::i+1.));
}

// This returns a Tridiagonal furnished with frequencies, when mode is derived from mode::Exact

const Tridiagonal aop(Ptr mode)
{
  size_t dim=mode->getDimension();
  Tridiagonal res(aop(dim));
  if (const auto exact=dynamic_cast<const mode::Exact*>(mode.get())) res.furnishWithFreqs(mainDiagonal(exact->get_zI(),exact->get_omegaKerr(),dim));
  return res;
}

const Tridiagonal nop(Ptr mode)
{
  return Tridiagonal(mainDiagonal(1.,0.,mode->getDimension()));
}

double photonNumber(const StateVectorLow& psi)
{
  using blitz::tensor::i;
  return sum(i*blitzplusplus::sqrAbs(psi(i)));
}

double photonNumber(const LazyDensityOperator& matrix)
{
  double res=0;
  for (size_t n=1; n<matrix.getDimension(); ++n)
    res+=n*matrix(n);
  return res;
}

StateVector coherent(dcomp alpha, size_t dim)
{
  StateVector res(dim,false);
  double norm(exp(-sqr(abs(alpha))/2.));

  for (size_t n=0; n<dim; ++n) res(n)=norm*coherentElement(n,alpha);

  return res;

}

StateVector fock(size_t n, size_t dim, double phase)
{
  if (n>=dim) throw std::overflow_error("Fock state "+std::to_string(n)+" higher than dim "+std::to_string(dim));
  StateVector res(dim);
  res(n)=exp(DCOMP_I*phase);
  return res;
}

StateVector init(const Pars& p)
{
  return p.minitFock ? fock(p.minitFock,p.cutoff) : coherent(p.minit,p.cutoff);
}

} // mode

ModeBase::ModeBase(size_t dim, const RealFreqs& realFreqs, const ComplexFreqs& complexFreqs, const string& keyTitle)
    : Free(dim,realFreqs,complexFreqs)
{
  getParsStream()<<keyTitle<<endl;
}

PumpedLossyModeIP_NoExact::PumpedLossyModeIP_NoExact(const mode::ParsPumpedLossy& p)
  : ModeBase(p.cutoff),
    quantumoperator::TridiagonalHamiltonian<1,true>(furnishWithFreqs(mode::pumping(p.eta,p.cutoff),mode::mainDiagonal(dcomp(p.kappa,-p.delta),p.omegaKerr,p.cutoff))),
    structure::ElementLiouvillean<1,1,true>(mode::keyTitle,"excitation loss"),
    structure::ElementAveraged<1,true>(mode::keyTitle,{"<number operator>","real(<ladder operator>)","imag(\")"}),
    z_(p.kappa,-p.delta)
{
  getParsStream()<<"Interaction picture, not derived from Exact\n";
}

double PumpedLossyModeIP_NoExact::rate(OneTime, const mode::LazyDensityOperator& m) const
{
  return mode::photonNumber(m);
}

void PumpedLossyModeIP_NoExact::doActWithJ(OneTime t, mode::StateVectorLow& psi) const
{
  dcomp fact=sqrt(2.*real(z_))*exp(-z_*double(t));
  int ubound=psi.ubound(0);
  for (int n=0; n<ubound; ++n)
    psi(n)=fact*sqrt(n+1)*psi(n+1);
  psi(ubound)=0;
}

const mode::Averages PumpedLossyModeIP_NoExact::average_v(OneTime t, const mode::LazyDensityOperator& matrix) const
{
  auto averages(initializedAverages());

  for (int n=1; n<int(matrix.getDimension()); n++) {

    averages(0)+=n*exp(-2*real(z_)*n*t)*matrix(n);

    dcomp offdiag(sqrt(n)*matrix(n)(n-1)*exp(-(z_+2*(n-1)*real(z_))*double(t)));
    averages(1)+=real(offdiag);
    averages(2)+=imag(offdiag);

  }

  return averages;

}


// ====================================================================
// This file is part of FlexibleSUSY.
//
// FlexibleSUSY 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.
//
// FlexibleSUSY 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 FlexibleSUSY.  If not, see
// <http://www.gnu.org/licenses/>.
// ====================================================================

#ifndef EIGEN_UTILS_H
#define EIGEN_UTILS_H

#include <Eigen/Core>
#include <cassert>
#include <complex>
#include <iomanip>
#include <sstream>
#include <string>
#include <limits>

namespace flexiblesusy {

template <typename Derived>
int closest_index(double mass, const Eigen::ArrayBase<Derived>& v)
{
   int pos;
   typename Derived::PlainObject tmp;
   tmp.setConstant(mass);

   (v - tmp).abs().minCoeff(&pos);

   return pos;
}

template <class BinaryOp, class Derived>
Derived binary_map(
   const Eigen::DenseBase<Derived>& a, const Eigen::DenseBase<Derived>& b, BinaryOp op)
{
   typename Derived::PlainObject result(a.rows(), b.cols());

   assert(a.rows() == b.rows());
   assert(a.cols() == b.cols());

   for (int k = 0; k < a.cols(); k++)
      for (int i = 0; i < a.rows(); i++)
         result(i,k) = op(a(i,k), b(i,k));

   return result;
}

/**
 * Divides a by b element wise.  If the quotient is not finite, it is
 * set to zero.
 *
 * @param a numerator
 * @param b denominator
 */
template <class Derived>
Derived div_safe(
   const Eigen::DenseBase<Derived>& a, const Eigen::DenseBase<Derived>& b)
{
   using Scalar = typename Derived::Scalar;

   return binary_map(a, b, [](Scalar x, Scalar y){
         const Scalar q = x / y;
         return std::isfinite(q) ? q : Scalar{};
      });
}

/**
 * Calls eval() on any Eigen expression.  If the argument is not an
 * Eigen expression, the argument is returned.
 *
 * @param expr expression
 *
 * @return evaluated expression or argument
 */
template <class Derived>
auto Eval(const Eigen::DenseBase<Derived>& expr) -> decltype(expr.eval())
{
   return expr.eval();
}

inline char                 Eval(char                        expr) { return expr; }
inline short                Eval(short                       expr) { return expr; }
inline int                  Eval(int                         expr) { return expr; }
inline long                 Eval(long                        expr) { return expr; }
inline unsigned short       Eval(unsigned short              expr) { return expr; }
inline unsigned int         Eval(unsigned int                expr) { return expr; }
inline unsigned long        Eval(unsigned long               expr) { return expr; }
inline double               Eval(double                      expr) { return expr; }
inline std::complex<double> Eval(const std::complex<double>& expr) { return expr; }

/**
 * The element of v, which is closest to mass, is moved to the
 * position idx.
 *
 * @param idx new index of the mass eigenvalue
 * @param mass mass to compare against
 * @param v vector of masses
 * @param z corresponding mixing matrix
 */
template <typename DerivedArray, typename DerivedMatrix>
void move_goldstone_to(int idx, double mass, Eigen::ArrayBase<DerivedArray>& v,
                       Eigen::MatrixBase<DerivedMatrix>& z)
{
   int pos = closest_index(mass, v);
   if (pos == idx)
      return;

   const int sign = (idx - pos) < 0 ? -1 : 1;
   int steps = std::abs(idx - pos);

   // now we shuffle the states
   while (steps--) {
      const int new_pos = pos + sign;
      v.row(new_pos).swap(v.row(pos));
      z.row(new_pos).swap(z.row(pos));
      pos = new_pos;
   }
}

/**
 * Normalize each element of the given real matrix to be within the
 * interval [min, max].  Values < min are set to min.  Values > max
 * are set to max.
 *
 * @param m matrix
 * @param min minimum
 * @param max maximum
 */
template <int M, int N>
void normalize_to_interval(Eigen::Matrix<double,M,N>& m, double min = -1., double max = 1.)
{
   auto data = m.data();
   const auto size = m.size();

   for (int i = 0; i < size; i++) {
      if (data[i] < min)
         data[i] = min;
      else if (data[i] > max)
         data[i] = max;
   }
}

/**
 * Normalize each element of the given complex matrix to have a
 * magnitude within the interval [0, max].  If the magnitude of a
 * matrix element is > max, then the magnitude is set to max.  The
 * phase angles are not modified.
 *
 * @param m matrix
 * @param max_mag maximum magnitude
 */
template <int M, int N>
void normalize_to_interval(Eigen::Matrix<std::complex<double>,M,N>& m, double max_mag = 1.)
{
   auto data = m.data();
   const auto size = m.size();

   for (int i = 0; i < size; i++) {
      if (std::abs(data[i]) > max_mag)
         data[i] = std::polar(max_mag, std::arg(data[i]));
   }
}

namespace {
template <class T>
struct Is_not_finite {
   bool operator()(T x) const noexcept { return !std::isfinite(x); }
};
} // anonymous namespace

/**
 * Returns all elements from src, which are not close to the elements
 * in cmp.  The returned vector will have the length (src.size() -
 * cmp.size()).
 *
 * @param src source vector
 * @param cmp vector with elements to compare against
 * @return vector with elements of src not close to cmp
 */
template<class Real, int Nsrc, int Ncmp>
Eigen::Array<Real,Nsrc - Ncmp,1> remove_if_equal(
   const Eigen::Array<Real,Nsrc,1>& src,
   const Eigen::Array<Real,Ncmp,1>& cmp)
{
   Eigen::Array<Real,Nsrc,1> non_equal(src);
   Eigen::Array<Real,Nsrc - Ncmp,1> dst;

   for (int i = 0; i < Ncmp; i++) {
      const int idx = closest_index(cmp(i), non_equal);
      non_equal(idx) = std::numeric_limits<double>::infinity();
   }

   std::remove_copy_if(non_equal.data(), non_equal.data() + Nsrc,
                       dst.data(), Is_not_finite<Real>());

   return dst;
}

/**
 * @brief reorders vector v according to ordering in vector v2
 * @param v vector with elementes to be reordered
 * @param v2 vector with reference ordering
 */
template<class Real, int N>
void reorder_vector(
   Eigen::Array<Real,N,1>& v,
   const Eigen::Array<Real,N,1>& v2)
{
   Eigen::PermutationMatrix<N> p;
   p.setIdentity();
   std::sort(p.indices().data(), p.indices().data() + p.indices().size(),
             [&v2] (int i, int j) { return v2[i] < v2[j]; });

#if EIGEN_VERSION_AT_LEAST(3,1,4)
   v.matrix().transpose() *= p.inverse();
#else
   Eigen::Map<Eigen::Matrix<Real,N,1> >(v.data()).transpose() *= p.inverse();
#endif
}

/**
 * @brief reorders vector v according to ordering of diagonal elements in mass_matrix
 * @param v vector with elementes to be reordered
 * @param matrix matrix with diagonal elements with reference ordering
 */
template<class Derived>
void reorder_vector(
   Eigen::Array<double,Eigen::MatrixBase<Derived>::RowsAtCompileTime,1>& v,
   const Eigen::MatrixBase<Derived>& matrix)
{
   reorder_vector(v, matrix.diagonal().array().eval());
}

template<class Derived>
std::string print_scientific(const Eigen::DenseBase<Derived>& v,
                             int number_of_digits = std::numeric_limits<typename Derived::Scalar>::digits10 + 1)
{
   std::ostringstream sstr;

   for (int k = 0; k < v.cols(); k++) {
      for (int i = 0; i < v.rows(); i++) {
         sstr << std::setprecision(number_of_digits)
              << std::scientific << v(i,k) << ' ';
      }
      sstr << '\n';
   }

   return sstr.str();
}

} // namespace flexiblesusy

#endif


#include <boost/python.hpp>
#include <string>
#include "inf_def_visitor.hxx"

#include <opengm/inference/graphcut.hxx>
#include <opengm/inference/alphabetaswap.hxx>
#ifdef WITH_BOOST
#  include <opengm/inference/auxiliary/minstcutboost.hxx>
#endif
#ifdef WITH_MAXFLOW
#  include <opengm/inference/auxiliary/minstcutkolmogorov.hxx>
#endif

#include <param/alpha_beta_swap_param.hxx>

#if PY_MAJOR_VERSION == 2
static void wrap_import_array() {
    import_array();
}
#else
static void * wrap_import_array() {
    import_array();
}
#endif

template<class GM,class ACC>
void export_abswap(){

   wrap_import_array();
   typedef GM PyGm;
   typedef typename PyGm::ValueType ValueType;
   typedef typename PyGm::IndexType IndexType;

   append_subnamespace("solver");

   #ifdef WITH_MAXFLOW
      const bool withMaxFlow=true;
   #else
      const bool withMaxFlow=false;
   #endif

   // documentation
   InfSetup setup;
   setup.cite       = "";
   setup.algType    = "graphCut / movemaking";
   setup.limitations= "max 2.order, must be submodular";
   setup.hyperParameterKeyWords = StringVector(1,std::string("minStCut"));
   setup.hyperParametersDoc     = StringVector(1,std::string("minStCut implementation of graphcut"));
   setup.dependencies = "to use ``'kolmogorov'`` as minStCut the kolmogorov max flow library, "
                        "compile OpenGM with CMake-Flag ``WITH_MAXFLOW`` set to ``ON`` ";

   #ifdef WITH_MAXFLOW
   {
      // set up hyper parameter name for this template
      setup.isDefault=withMaxFlow;
      setup.hyperParameters= StringVector(1,std::string("kolmogorov"));
      typedef opengm::external::MinSTCutKolmogorov<size_t,ValueType> MinStCutKolmogorov;
      typedef opengm::GraphCut<PyGm, ACC, MinStCutKolmogorov>        PyGraphCutKolmogorov;
      typedef opengm::AlphaBetaSwap<PyGm, PyGraphCutKolmogorov> PyAlphaBetaSwapKolmogorov;
      // export parameter
      exportInfParam<PyAlphaBetaSwapKolmogorov>("_AlphaBetaSwap_Kolmogorov");
      // export inference
      boost::python::class_< PyAlphaBetaSwapKolmogorov>("_AlphaBetaSwap_Kolmogorov",init<const GM & >())
      .def(InfSuite<PyAlphaBetaSwapKolmogorov,false>(std::string("AlphaBetaSwap"),setup))
      ;
   }
   #endif
   {
      // set up hyper parameter name for this template
      setup.isDefault=!withMaxFlow;
      setup.hyperParameters= StringVector(1,std::string("boost-kolmogorov"));
      typedef opengm::MinSTCutBoost<size_t, ValueType, opengm::KOLMOGOROV> MinStCutBoostKolmogorov;
      typedef opengm::GraphCut<PyGm, ACC, MinStCutBoostKolmogorov> PyGraphCutBoostKolmogorov;
      typedef opengm::AlphaBetaSwap<PyGm, PyGraphCutBoostKolmogorov> PyAlphaBetaSwapBoostKolmogorov;
      // export parameter
      exportInfParam<PyAlphaBetaSwapBoostKolmogorov>("_AlphaBetaSwap_Boost_Kolmogorov");
      // export inference
      boost::python::class_< PyAlphaBetaSwapBoostKolmogorov>("_AlphaBetaSwap_Boost_Kolmogorov",init<const GM & >())
      .def(InfSuite<PyAlphaBetaSwapBoostKolmogorov,false>(std::string("AlphaBetaSwap"),setup))
      ;
   }

   {
      // set up hyper parameter name for this template
      setup.isDefault=false;
      setup.hyperParameters= StringVector(1,std::string("push-relabel"));
      typedef opengm::MinSTCutBoost<size_t, ValueType, opengm::PUSH_RELABEL> MinStCutBoostPushRelabel;
      typedef opengm::GraphCut<PyGm, ACC, MinStCutBoostPushRelabel> PyGraphCutBoostPushRelabel;
      typedef opengm::AlphaBetaSwap<PyGm, PyGraphCutBoostPushRelabel> PyAlphaBetaSwapPushRelabel;
      // export parameter
      exportInfParam<PyAlphaBetaSwapPushRelabel>("_AlphaBetaSwap_Boost_Push_Relabel");
      // export inference
      boost::python::class_< PyAlphaBetaSwapPushRelabel>("_AlphaBetaSwap_Boost_Push_Relabel",init<const GM & >())
      .def(InfSuite<PyAlphaBetaSwapPushRelabel,false>(std::string("AlphaBetaSwap"),setup))
   ;
   }

}

template void export_abswap<opengm::python::GmAdder,opengm::Minimizer>();


/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center.

All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include <mitkImageCast.h>
#include <mitkOdfImage.h>
#include <mitkTensorImage.h>
#include <mitkFiberBundle.h>
#include <itkGibbsTrackingFilter.h>
#include <itkDiffusionTensor3D.h>
#include <itkShCoefficientImageImporter.h>
#include <itkShToOdfImageFilter.h>
#include <mitkImageToItk.h>
#include <mitkIOUtil.h>
#include "mitkDiffusionCommandLineParser.h"
#include <boost/algorithm/string.hpp>
#include <itkFlipImageFilter.h>
#include <mitkCoreObjectFactory.h>
#include <mitkPreferenceListReaderOptionsFunctor.h>
#include <mitkShImage.h>
#include <mitkDiffusionFunctionCollection.h>

/*!
\brief Perform global fiber tractography (Gibbs tractography)
*/
int main(int argc, char* argv[])
{
  mitkDiffusionCommandLineParser parser;

  parser.setTitle("Gibbs Tracking");
  parser.setCategory("Fiber Tracking and Processing Methods");
  parser.setDescription("Perform global fiber tractography (Gibbs tractography)");
  parser.setContributor("MIC");

  parser.setArgumentPrefix("--", "-");
  parser.addArgument("", "i", mitkDiffusionCommandLineParser::String, "Input:", "input image (tensor, ODF or SH-coefficient image)", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Input);
  parser.addArgument("", "o", mitkDiffusionCommandLineParser::String, "Output:", "output tractogram", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Output);
  parser.addArgument("parameters", "", mitkDiffusionCommandLineParser::String, "Parameters:", "parameter file (.gtp)", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Input);
  parser.addArgument("mask", "", mitkDiffusionCommandLineParser::String, "Mask:", "binary mask image", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Input);

  std::map<std::string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
  if (parsedArgs.size()==0)
    return EXIT_FAILURE;

  std::string inFileName = us::any_cast<std::string>(parsedArgs["i"]);
  std::string paramFileName = us::any_cast<std::string>(parsedArgs["parameters"]);
  std::string outFileName = us::any_cast<std::string>(parsedArgs["o"]);

  try
  {
    // instantiate gibbs tracker
    typedef itk::Vector<float, ODF_SAMPLING_SIZE>   OdfVectorType;
    typedef itk::Image<OdfVectorType,3>         ItkOdfImageType;
    typedef itk::GibbsTrackingFilter<ItkOdfImageType> GibbsTrackingFilterType;
    GibbsTrackingFilterType::Pointer gibbsTracker = GibbsTrackingFilterType::New();

    // load input image
    mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"SH Image"}, std::vector<std::string>());
    mitk::Image::Pointer mitkImage = mitk::IOUtil::Load<mitk::Image>(inFileName, &functor);

    // try to cast to Odf image
    if( dynamic_cast<mitk::OdfImage*>(mitkImage.GetPointer()) )
    {
      mitk::OdfImage::Pointer mitkOdfImage = dynamic_cast<mitk::OdfImage*>(mitkImage.GetPointer());
      ItkOdfImageType::Pointer itk_odf = ItkOdfImageType::New();
      mitk::CastToItkImage(mitkOdfImage, itk_odf);
      gibbsTracker->SetOdfImage(itk_odf.GetPointer());
    }
    else if( dynamic_cast<mitk::TensorImage*>(mitkImage.GetPointer()) )
    {
      typedef itk::Image< itk::DiffusionTensor3D<float>, 3 >    ItkTensorImage;
      mitk::TensorImage::Pointer mitkTensorImage = dynamic_cast<mitk::TensorImage*>(mitkImage.GetPointer());
      ItkTensorImage::Pointer itk_dti = ItkTensorImage::New();
      mitk::CastToItkImage(mitkTensorImage, itk_dti);
      gibbsTracker->SetTensorImage(itk_dti);
    }
    else if ( dynamic_cast<mitk::ShImage*>(mitkImage.GetPointer()) )
    {
      MITK_INFO << "Assuming MITK/MRtrix style SH convention!";
      mitk::Image::Pointer shImage = dynamic_cast<mitk::Image*>(mitkImage.GetPointer());
      gibbsTracker->SetOdfImage(mitk::convert::GetItkOdfFromShImage(shImage));
    }
    else
      return EXIT_FAILURE;

    // global tracking
    if (parsedArgs.count("mask"))
    {
      typedef itk::Image<float,3> MaskImgType;
      mitk::Image::Pointer mitkMaskImage = mitk::IOUtil::Load<mitk::Image>(us::any_cast<std::string>(parsedArgs["mask"]));
      MaskImgType::Pointer itk_mask = MaskImgType::New();
      mitk::CastToItkImage(mitkMaskImage, itk_mask);
      gibbsTracker->SetMaskImage(itk_mask);
    }

    gibbsTracker->SetDuplicateImage(false);
    gibbsTracker->SetLoadParameterFile( paramFileName );
    //        gibbsTracker->SetLutPath( "" );
    gibbsTracker->Update();

    mitk::FiberBundle::Pointer mitkFiberBundle = mitk::FiberBundle::New(gibbsTracker->GetFiberBundle());
    mitkFiberBundle->SetTrackVisHeader(mitkImage->GetGeometry());

    mitk::IOUtil::Save(mitkFiberBundle, outFileName );
  }
  catch (const itk::ExceptionObject& e)
  {
    std::cout << e.what();
    return EXIT_FAILURE;
  }
  catch (std::exception& e)
  {
    std::cout << e.what();
    return EXIT_FAILURE;
  }
  catch (...)
  {
    std::cout << "ERROR!?!";
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}