#include <vector>
#include <deque>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>

#include <unistd.h>
#include <sys/wait.h>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include "opencv2/core/core.hpp"
#include "opencv2/core/operations.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/video/tracking.hpp>

#include "../../../core/image.h"
#include "../../../tracker/stereo/experiment_factory.h"
#include "../../../tracker/stereo/stereo_tracker_base.h"
#include "../../../tracker/refiner/feature_refiner_base.cc"
#include "../../../tracker/refiner/feature_refiner_klt.h"
#include "../../../tracker/detector/feature_detector_base.h"
//#include "../../../tracker/descriptor/freak.h"
#include "../../../tracker/stereo/tracker_helper.h"
#include "../../../optimization/sba/sba_base.h"
//#include "../../../optimization/sba/sba_ros.h"
#include "../../../optimization/sba/feature_helper_sba.h"
#include "../../extern/libviso2/src/viso_stereo.h"
#include "../../extern/libviso2/src/matrix.h"
#include "../../math_helper.h"
#include "../../../tracker/base/eval_helper.h"
#include "../../../core/format_helper.h"
#include "../../helper_libviso.h"
#include "../../cv_plotter.h"

using namespace core;
using namespace vo;
using namespace track;

void run_visual_odometry(const std::string& source_folder,
                         const std::string& imagelistfn,
                         const std::string& experiment_config,
                         const std::string& cparams_file,
                         const std::string& gt_filepath)
{
  std::deque<cv::Mat> extr_params; // pose mat
  std::deque<cv::Mat> Rt_params;

  double cam_params[5];
  FormatHelper::readCameraParams(cparams_file, cam_params);

  std::string output_folder;
  FeatureDetectorBase* detector = nullptr;
  TrackerBase* mono_tracker = nullptr;
  StereoTrackerBase* stereo_tracker = nullptr;
  libviso::VisualOdometryStereo* viso = nullptr;
  bool use_ba; // use bundle adjustment
  int ba_frames;
  track::ExperimentFactory::create_experiment(experiment_config, cam_params, output_folder, &detector,
                                              &mono_tracker, &stereo_tracker, &viso, use_ba, ba_frames);

  std::vector<std::string> imagelist;
  bool ok = FormatHelper::readStringList(imagelistfn, imagelist);
  if(!ok || imagelist.empty())
    throw "can not open " + imagelistfn + " or the string list is empty\n";

  // TODO
  //param.match.refinement = 2;

  // optional
  //param.inlier_threshold = 0.01;       // 1.5
  //param.ransac_iters = RANSAC_ITERS;           // def: 100
  //param.bucket.bucket_height = 50;    // 50
  //param.bucket.bucket_width = 50;     // 50
  //param.bucket.max_features = 3;      // 2

  int start_frame = 0 * 2;
  //int start_frame = 1110 * 2;
  int end_frame = imagelist.size();
  //int end_frame = 10 * 2;

  bool smooth_images = false;
  cv::Mat img_left_prev, img_right_prev;
  cv::Mat img_left = cv::imread(source_folder + imagelist[start_frame], CV_LOAD_IMAGE_GRAYSCALE);
  cv::Mat img_right = cv::imread(source_folder + imagelist[start_frame+1], CV_LOAD_IMAGE_GRAYSCALE);
  if(smooth_images) {
    cv::GaussianBlur(img_left, img_left, cv::Size(3,3), 0.7);
    cv::GaussianBlur(img_right, img_right, cv::Size(3,3), 0.7);
  }

  optim::FeatureHelperSBA* sba;
  if(use_ba)
    sba = new optim::FeatureHelperSBA(img_left, img_right, ba_frames, stereo_tracker->countFeatures());

  libviso::Matrix pose = libviso::Matrix::eye(4);
  libviso::Matrix viso_cvtrack = libviso::Matrix::eye(4);
  //Matrix point_rt = Matrix::eye(4);
  cv::Mat pose_mat = cv::Mat::eye(4, 4, CV_64F);
  Mat Rt_inv;
  Mat mat_I = Mat::eye(4, 4, CV_64F);
  mat_I.copyTo(Rt_inv);
  Vec<double,7> trans_vec;
  extr_params.push_back(mat_I.clone());
  Mat Rt(4, 4, CV_64F);
  Mat Rt_gt(4, 4, CV_64F);
  Mat Rt_gt_prev = Mat::eye(4, 4, CV_64F);
  Mat Rt_gt_curr = Mat::eye(4, 4, CV_64F);
  MathHelper::invTrans(Rt_inv, Rt);
  Rt_params.push_back(Rt.clone());

  Mat prev_location_viso = Mat::zeros(4, 1, CV_64F);

  // init the tracker
  stereo_tracker->init(img_left, img_right);

  Mat disp_camera_left = Mat::zeros(img_left.rows, img_left.cols, CV_8UC3);
  Mat disp_camera_right = Mat::zeros(img_left.rows, img_left.cols, CV_8UC3);

  // matrix transforms points in current camera coordinate system to world coord system
  std::vector<cv::Mat> libviso_Rt_all;
  cv::Mat pose_libviso = Mat::eye(4, 4, CV_64F);
  libviso_Rt_all.push_back(pose_libviso.clone());

  bool using_kitti = true;
  std::string track_name;
  //std::ifstream gt_file(gt_filepath);
  if(experiment_config.find("tsukuba") != std::string::npos) {
    printf("---------- Using Tsukuba dataset! ------------\n");
    track_name = "00";
    using_kitti = false;
    //gt_file.open("/home/kivan/Projects/datasets/Tsukuba/NewTsukubaStereoDataset/groundtruth/tsukuba_gt_crop.txt");
  }
  else {
    track_name = imagelistfn.substr(imagelistfn.size()-10,2);
    //gt_file.open("/home/kivan/Projects/datasets/KITTI/poses/07.txt");
  }

  //int gt_better_cnt = 0;
  int frame_num = start_frame / 2 + 1;
  for(unsigned i = start_frame + 2; i < end_frame; i+=(2)) {
    frame_num = i / 2 + 1;
    std::cout << "Frame: " << frame_num << " / " << imagelist.size()/2 << "\n";
    cout << source_folder + imagelist[i] << endl;
    cv::swap(img_left_prev, img_left);
    cv::swap(img_right_prev, img_right);
    img_left = cv::imread(source_folder + imagelist[i], CV_LOAD_IMAGE_GRAYSCALE);
    img_right = cv::imread(source_folder + imagelist[i+1], CV_LOAD_IMAGE_GRAYSCALE);
    if(smooth_images) {
      cv::GaussianBlur(img_left, img_left, cv::Size(3,3), 0.7);
      cv::GaussianBlur(img_right, img_right, cv::Size(3,3), 0.7);
    }

    stereo_tracker->track(img_left, img_right);

    // default prior
    double max_z_dist = 300.0; // for tsukuba in cm
    double min_disp = 0.1;
    double max_disp_diff = 50.0;
    // for KITTI
    if(using_kitti) {
      max_disp_diff = 30.0;
      max_z_dist = 3.0;         // 3m
    }
    // filter tracks with prior knowledge
    FeatureHelper::FilterTracksWithPriorOld(*stereo_tracker, max_disp_diff, min_disp);

    // convert from my tracker to Libviso data structure
    std::vector<int> active_tracks;
    std::vector<libviso::Matcher::p_match> libviso_tracks;
    FeatureHelper::TrackerBaseToLibviso(stereo_tracker, libviso_tracks, active_tracks);

    // run odometry optimization
    if(viso->process(libviso_tracks)) {
      // is it better to kill or not to kill outliers in tracker?
      std::vector<int32_t>& inliers = viso->getInliers();
      std::cout << "Tracks before RANSAC: " << stereo_tracker->countActiveTracks() << "\n";
      //FeatureHelper::FilterOutlierTracks(*stereo_tracker, active_tracks, inliers, 30.0, 0.1);
      FeatureHelper::FilterRansacOutliers(*stereo_tracker, active_tracks, inliers);
      std::cout << "Tracks after RANSAC: " << stereo_tracker->countActiveTracks() << "\n";

      //libviso::Matrix Rt_inv_libviso = libviso::Matrix::inv(viso.getMotion());
      //MathHelper::matrixToMat(Rt_inv_libviso, Rt_inv);
      libviso::Matrix Rt_libviso = viso->getMotion();
      MathHelper::matrixToMat(Rt_libviso, Rt);

      // if the motion is to small skip it
      // tracker.undo_state();
      MathHelper::invTrans(Rt, Rt_inv);    // better
      extr_params.push_back(Rt_inv.clone());

      // on success, update current pose
      pose_mat = pose_mat * Rt_inv;
      libviso_Rt_all.push_back(pose_mat.clone());

      if(use_ba) {
        // ----- SBA -----
        sba->updateTracks(img_left, img_right, *stereo_tracker, Rt_inv, cam_params);
        //sba->updateTracks(img_left, img_right, *stereo_tracker, mat_I, cam_params);
        if(frame_num >= ba_frames) {
          sba->runSBA();
          cout << "-------------------------------\n";
          //cout << "reprojection error (SBA): " << reproj_error_sba << "\n";
        }
      }

      double num_matches = viso->getNumberOfMatches();
      double num_inliers = viso->getNumberOfInliers();
      cout << "[Libviso] Matches: " << num_matches << ", Inliers: " << num_inliers << " -> "
           << 100.0*num_inliers/num_matches << " %" << endl;
      cout << "-----------------------------------------------------------------------\n\n";
      Mat location_viso(pose_libviso, Range(0,4), Range(3,4)); // extract 4-th column

      location_viso.copyTo(prev_location_viso);
    } else {
      cout << "libviso ... failed!" << endl;
      throw "Error\n";
      waitKey(0);
      //extr_params.push_back(Rt_inv.clone());
      //exit(1);
    }
  }

  //waitKey(0);
  //destroyAllWindows();

  //std::cout << "Groundtruth data cost is better then odometry in " << gt_better_cnt << " / "
  //          << imagelist.size() << " frames.\n";

  std::cout << "Writing track " << track_name << " to files\n";
  std::ofstream libviso_ofile(output_folder + '/' + track_name + ".txt");

  std::ofstream sba_ofile;
  cv::Mat sba_pose;
  if(use_ba) {
    std::string ba_folder = output_folder.substr(0, output_folder.size()-1) + "_ba/";
    sba_ofile.open(ba_folder + track_name + ".txt");
    sba_pose = cv::Mat::eye(4, 4, CV_64F);
  }
  for(size_t i = 0; i < libviso_Rt_all.size(); i++) {
    FormatHelper::writeMatRt(libviso_Rt_all[i], libviso_ofile);
    if(use_ba) {
      sba_pose = sba_pose * sba->getCameraRt(i);
      FormatHelper::writeMatRt(sba_pose, sba_ofile);
    }
  }

  if(use_ba)
    delete sba;
  delete stereo_tracker;
  delete viso;
}

int main(int argc, char** argv)
{
  std::string config_file;
  std::string experiment_config;
  std::string imagelistfn;
  std::string cam_params_file;
  std::string source_folder;
  std::string gt_filepath;

  try {
    po::options_description generic("Generic options");
    generic.add_options()
      ("help, h", "produce help message")
      ("config,c", po::value<string>(&config_file), "config filename")
      ("experiment_config,e", po::value<string>(&experiment_config), "experiment config filename");
    po::options_description cmdline_options;
    cmdline_options.add(generic);

    po::variables_map vm;
    //po::store(po::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
    po::store(po::parse_command_line(argc, argv, cmdline_options), vm);
    notify(vm);
    if(vm.count("help")) {
      cout << generic;
      return 0;
    }

    po::options_description config("Config file options");
    config.add_options()
      ("camera_params,p", po::value<std::string>(&cam_params_file)->default_value("camera_params.txt"), "camera params file")
      ("source_folder,s", po::value<std::string>(&source_folder), "folder with source")
      ("imglist,l", po::value<std::string>(&imagelistfn), "file with image list")
      ("groundtruth,g", po::value<std::string>(&gt_filepath), "file with motion GT");

    std::ifstream ifs(config_file);
    if(!ifs)
      throw "can not open config file: " + config_file + "\n";
    else {
      po::store(parse_config_file(ifs, config, true), vm);
      notify(vm);
    }
  }
  catch(std::exception& e) {
    cout << e.what() << "\n";
    return -1;
  }

  run_visual_odometry(source_folder, imagelistfn, experiment_config, cam_params_file, gt_filepath);

  return 0;
}


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2014, Oracle and/or its affiliates.

// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_RANGE_HPP

#include <boost/range.hpp>

#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>

#include <boost/geometry/algorithms/dispatch/distance.hpp>

#include <boost/geometry/algorithms/detail/distance/single_to_multi.hpp>
#include <boost/geometry/algorithms/detail/distance/multi_to_multi.hpp>
#include <boost/geometry/algorithms/detail/distance/geometry_to_geometry_rtree.hpp>

#include <boost/geometry/geometries/concepts/check.hpp>

#include <boost/geometry/iterators/point_iterator.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{

template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
struct multipoint_to_multipoint
{
    typedef typename strategy::distance::services::return_type
        <
            Strategy,
            typename point_type<MultiPoint1>::type,
            typename point_type<MultiPoint2>::type
        >::type return_type;

    static inline return_type apply(MultiPoint1 const& multipoint1,
                                    MultiPoint2 const& multipoint2,
                                    Strategy const& strategy)
    {
        if ( boost::size(multipoint1) > boost::size(multipoint2) )

        {
            return multipoint_to_multipoint
                <
                    MultiPoint2, MultiPoint1, Strategy
                >::apply(multipoint2, multipoint1, strategy);
        }

        return point_range_to_geometry_rtree
            <
                typename point_type<MultiPoint1>::type,
                MultiPoint2,
                Strategy
            >::apply(points_begin(multipoint1), points_end(multipoint1),
                     multipoint2, strategy);
    }
};

}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

namespace splitted_dispatch
{

// specializations of distance_single_to_multi for various geometry combinations

template<typename Linestring, typename MultiPoint, typename Strategy>
struct distance_single_to_multi
    <
        Linestring, MultiPoint, Strategy,
        linestring_tag, multi_point_tag,
        strategy_tag_distance_point_segment
    >
{
    typedef typename strategy::distance::services::return_type
        <
            Strategy,
            typename point_type<Linestring>::type,
            typename point_type<MultiPoint>::type
        >::type return_type;

    static inline return_type apply(Linestring const& linestring,
                                    MultiPoint const& multipoint,
                                    Strategy const& strategy)
    {
        return detail::distance::point_range_to_geometry_rtree
            <
                typename point_type<MultiPoint>::type,
                Linestring,
                Strategy
            >::apply(geometry::points_begin(multipoint),
                     geometry::points_end(multipoint),
                     linestring, strategy);

    }
};

// specializations of distance_multi_to_multi for various geometry combinations

template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
struct distance_multi_to_multi
    <
        MultiPoint1, MultiPoint2, Strategy,
        multi_point_tag, multi_point_tag,
        strategy_tag_distance_point_point
    > : detail::distance::multipoint_to_multipoint
        <
            MultiPoint1, MultiPoint2, Strategy
        >
{};

template
<
    typename MultiPoint,
    typename MultiLinestring,
    typename Strategy
>
struct distance_multi_to_multi
    <
        MultiPoint, MultiLinestring, Strategy,
        multi_point_tag, multi_linestring_tag,
        strategy_tag_distance_point_segment
    >
{
    typedef typename strategy::distance::services::return_type
        <
            Strategy,
            typename point_type<MultiPoint>::type,
            typename point_type<MultiLinestring>::type
        >::type return_type;

    static inline return_type apply(MultiPoint const& multipoint,
                                    MultiLinestring const& multilinestring,
                                    Strategy const& strategy)
    {
        return detail::distance::point_range_to_geometry_rtree
            <
                typename point_type<MultiPoint>::type,
                MultiLinestring,
                Strategy
            >::apply(geometry::points_begin(multipoint),
                     geometry::points_end(multipoint),
                     multilinestring, strategy);

    }
};

} // namespace splitted_dispatch

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DISTANCE_ALTERNATE_HPP


#ifndef ALGOIM_BLITZINC_HPP
#define ALGOIM_BLITZINC_HPP

// Management of Algoim's use of blitz++, mainly to inject blitz::TinyVector into the Algoim namespace
// and to enable vector expressions when using QD for double-double or quadruple-double precision.

#include <blitz/array.h>
#if __has_include(<blitz/tinyvec-et.h>)
#include <blitz/tinyvec-et.h> // to support backwards compatibility with blitz-0.9
#endif
#include "algoim_real.hpp"

namespace Algoim
{
    // Algoim makes heavy use of blitz::TinyVector, but try not to pollute global namespace by using all of blitz
    using ::blitz::TinyVector;
}

// std::equal_to for blitz::TinyVector
namespace std
{
    template<typename T, int N>
    struct equal_to<blitz::TinyVector<T,N>>
    {
        bool operator()(const blitz::TinyVector<T,N>& x, const blitz::TinyVector<T,N>& y) const
        {
            return blitz::all(x == y);
        }
    };
}

#ifdef ALGOIM_HPREAL

// Enable blitz vector expressions for Real

BZ_NAMESPACE(blitz)

// Should be fine to leave this out, but specifying it could inform blitz that a trivial
// constructor is available.
//BZDECLNUMTRAIT(Real, Real, Real, Real, Real);

// Use this to inform blitz that all types can be promoted to Real as it has more precision
//BZ_DECLARE_PRECISION(Real,710)

// The following has been copied from vecbops.cc, isolating those routines containing
// 'long double' and replaced with Real.

// Vector<P_numtype1> + Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<P_numtype1, Real > > >
operator+(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> + Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<typename P_expr1::T_numtype, Real > > >
operator+(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> + Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<P_numtype1, Real > > >
operator+(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range + Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Add<int, Real > > >
operator+(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Add<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> + Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<P_numtype1, Real > > >
operator+(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Add<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real + Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Add<Real, P_numtype2 > > >
operator+(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Add<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real + _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Add<Real, typename P_expr2::T_numtype > > >
operator+(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Add<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real + VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Add<Real, P_numtype2 > > >
operator+(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Add<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real + Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Add<Real, int > > >
operator+(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Add<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real + TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Add<Real, P_numtype2 > > >
operator+(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Add<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> - Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<P_numtype1, Real > > >
operator-(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> - Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<typename P_expr1::T_numtype, Real > > >
operator-(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> - Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<P_numtype1, Real > > >
operator-(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range - Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<int, Real > > >
operator-(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> - Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<P_numtype1, Real > > >
operator-(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Subtract<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real - Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Subtract<Real, P_numtype2 > > >
operator-(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Subtract<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real - _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Subtract<Real, typename P_expr2::T_numtype > > >
operator-(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Subtract<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real - VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Subtract<Real, P_numtype2 > > >
operator-(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Subtract<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real - Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Subtract<Real, int > > >
operator-(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Subtract<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real - TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Subtract<Real, P_numtype2 > > >
operator-(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Subtract<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> * Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<P_numtype1, Real > > >
operator*(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> * Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<typename P_expr1::T_numtype, Real > > >
operator*(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> * Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<P_numtype1, Real > > >
operator*(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range * Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<int, Real > > >
operator*(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> * Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<P_numtype1, Real > > >
operator*(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Multiply<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real * Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Multiply<Real, P_numtype2 > > >
operator*(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Multiply<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real * _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Multiply<Real, typename P_expr2::T_numtype > > >
operator*(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Multiply<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real * VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Multiply<Real, P_numtype2 > > >
operator*(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Multiply<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real * Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Multiply<Real, int > > >
operator*(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Multiply<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real * TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Multiply<Real, P_numtype2 > > >
operator*(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Multiply<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> / Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<P_numtype1, Real > > >
operator/(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> / Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<typename P_expr1::T_numtype, Real > > >
operator/(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> / Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<P_numtype1, Real > > >
operator/(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range / Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Divide<int, Real > > >
operator/(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Divide<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> / Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<P_numtype1, Real > > >
operator/(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Divide<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real / Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Divide<Real, P_numtype2 > > >
operator/(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Divide<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real / _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Divide<Real, typename P_expr2::T_numtype > > >
operator/(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Divide<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real / VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Divide<Real, P_numtype2 > > >
operator/(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Divide<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real / Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Divide<Real, int > > >
operator/(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Divide<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real / TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Divide<Real, P_numtype2 > > >
operator/(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Divide<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> > Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<P_numtype1, Real > > >
operator>(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> > Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<typename P_expr1::T_numtype, Real > > >
operator>(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> > Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<P_numtype1, Real > > >
operator>(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range > Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Greater<int, Real > > >
operator>(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Greater<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> > Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<P_numtype1, Real > > >
operator>(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Greater<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real > Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Greater<Real, P_numtype2 > > >
operator>(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Greater<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real > _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Greater<Real, typename P_expr2::T_numtype > > >
operator>(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Greater<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real > VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Greater<Real, P_numtype2 > > >
operator>(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Greater<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real > Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Greater<Real, int > > >
operator>(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Greater<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real > TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Greater<Real, P_numtype2 > > >
operator>(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Greater<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> < Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<P_numtype1, Real > > >
operator<(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> < Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<typename P_expr1::T_numtype, Real > > >
operator<(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> < Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<P_numtype1, Real > > >
operator<(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range < Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Less<int, Real > > >
operator<(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Less<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> < Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<P_numtype1, Real > > >
operator<(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Less<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real < Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Less<Real, P_numtype2 > > >
operator<(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Less<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real < _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Less<Real, typename P_expr2::T_numtype > > >
operator<(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Less<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real < VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Less<Real, P_numtype2 > > >
operator<(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Less<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real < Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Less<Real, int > > >
operator<(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Less<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real < TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Less<Real, P_numtype2 > > >
operator<(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Less<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> >= Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<P_numtype1, Real > > >
operator>=(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> >= Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<typename P_expr1::T_numtype, Real > > >
operator>=(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> >= Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<P_numtype1, Real > > >
operator>=(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range >= Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<int, Real > > >
operator>=(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> >= Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<P_numtype1, Real > > >
operator>=(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_GreaterOrEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real >= Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_GreaterOrEqual<Real, P_numtype2 > > >
operator>=(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_GreaterOrEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real >= _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_GreaterOrEqual<Real, typename P_expr2::T_numtype > > >
operator>=(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_GreaterOrEqual<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real >= VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_GreaterOrEqual<Real, P_numtype2 > > >
operator>=(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_GreaterOrEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real >= Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_GreaterOrEqual<Real, int > > >
operator>=(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_GreaterOrEqual<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real >= TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_GreaterOrEqual<Real, P_numtype2 > > >
operator>=(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_GreaterOrEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> <= Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<P_numtype1, Real > > >
operator<=(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> <= Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<typename P_expr1::T_numtype, Real > > >
operator<=(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> <= Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<P_numtype1, Real > > >
operator<=(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range <= Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<int, Real > > >
operator<=(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> <= Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<P_numtype1, Real > > >
operator<=(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_LessOrEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real <= Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_LessOrEqual<Real, P_numtype2 > > >
operator<=(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_LessOrEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real <= _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_LessOrEqual<Real, typename P_expr2::T_numtype > > >
operator<=(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_LessOrEqual<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real <= VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_LessOrEqual<Real, P_numtype2 > > >
operator<=(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_LessOrEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real <= Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_LessOrEqual<Real, int > > >
operator<=(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_LessOrEqual<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real <= TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_LessOrEqual<Real, P_numtype2 > > >
operator<=(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_LessOrEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> == Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<P_numtype1, Real > > >
operator==(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> == Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<typename P_expr1::T_numtype, Real > > >
operator==(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> == Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<P_numtype1, Real > > >
operator==(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range == Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Equal<int, Real > > >
operator==(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_Equal<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> == Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<P_numtype1, Real > > >
operator==(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_Equal<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real == Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Equal<Real, P_numtype2 > > >
operator==(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_Equal<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real == _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Equal<Real, typename P_expr2::T_numtype > > >
operator==(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_Equal<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real == VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Equal<Real, P_numtype2 > > >
operator==(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_Equal<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real == Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Equal<Real, int > > >
operator==(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_Equal<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real == TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Equal<Real, P_numtype2 > > >
operator==(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_Equal<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Vector<P_numtype1> != Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<P_numtype1, Real > > >
operator!=(const Vector<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// _bz_VecExpr<P_expr1> != Real
template<class P_expr1>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<typename P_expr1::T_numtype, Real > > >
operator!=(_bz_VecExpr<P_expr1> d1,
      Real d2)
{
    typedef _bz_VecExprOp<_bz_VecExpr<P_expr1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<typename P_expr1::T_numtype, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// VectorPick<P_numtype1> != Real
template<class P_numtype1>
inline
_bz_VecExpr<_bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<P_numtype1, Real > > >
operator!=(const VectorPick<P_numtype1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<VectorPickIterConst<P_numtype1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Range != Real

inline
_bz_VecExpr<_bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<int, Real > > >
operator!=(Range d1,
      Real d2)
{
    typedef _bz_VecExprOp<Range,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<int, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1,
      _bz_VecExprConstant<Real>(d2)));
}

// TinyVector<P_numtype1, N_length1> != Real
template<class P_numtype1, int N_length1>
inline
_bz_VecExpr<_bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<P_numtype1, Real > > >
operator!=(const TinyVector<P_numtype1, N_length1>& d1,
      Real d2)
{
    typedef _bz_VecExprOp<TinyVectorIterConst<P_numtype1, N_length1>,
      _bz_VecExprConstant<Real>,
      _bz_NotEqual<P_numtype1, Real> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(d1.beginFast(),
      _bz_VecExprConstant<Real>(d2)));
}

// Real != Vector<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_NotEqual<Real, P_numtype2 > > >
operator!=(Real d1,
      const Vector<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorIterConst<P_numtype2>,
      _bz_NotEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real != _bz_VecExpr<P_expr2>
template<class P_expr2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_NotEqual<Real, typename P_expr2::T_numtype > > >
operator!=(Real d1,
      _bz_VecExpr<P_expr2> d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      _bz_VecExpr<P_expr2>,
      _bz_NotEqual<Real, typename P_expr2::T_numtype> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real != VectorPick<P_numtype2>
template<class P_numtype2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_NotEqual<Real, P_numtype2 > > >
operator!=(Real d1,
      const VectorPick<P_numtype2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      VectorPickIterConst<P_numtype2>,
      _bz_NotEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Real != Range

inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_NotEqual<Real, int > > >
operator!=(Real d1,
      Range d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      Range,
      _bz_NotEqual<Real, int> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2));
}

// Real != TinyVector<P_numtype2, N_length2>
template<class P_numtype2, int N_length2>
inline
_bz_VecExpr<_bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_NotEqual<Real, P_numtype2 > > >
operator!=(Real d1,
      const TinyVector<P_numtype2, N_length2>& d2)
{
    typedef _bz_VecExprOp<_bz_VecExprConstant<Real>,
      TinyVectorIterConst<P_numtype2, N_length2>,
      _bz_NotEqual<Real, P_numtype2> > T_expr;

    return _bz_VecExpr<T_expr>(T_expr(_bz_VecExprConstant<Real>(d1),
      d2.beginFast()));
}

// Expression templates for blitz::Array
BZ_DECLARE_ARRAY_ET_SCALAR_OPS(Real)

BZ_NAMESPACE_END
#endif

#endif


/*
Copyright 2009-2021 Nicolas Colombe

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#pragma once

#include <gen/pattern.hpp>
#include <core/randomsetwalk.hpp>
#include <boost/optional.hpp>

namespace eXl
{
  class Random;

  template <unsigned int N>
  struct NearestPow2;

  template <>
  struct NearestPow2<1>
  {
    static const unsigned int Pow = 1;
  };

  template <unsigned int N>
  struct NearestPow2
  {
    static const unsigned int Pow = NearestPow2<N / 2>::Pow + 1;
  };

  template <unsigned int N, unsigned int Size>
  struct CompactStorage
  {
    static const unsigned int ArraySize = (NearestPow2<N>::Pow * Size) / 32 + ((NearestPow2<N>::Pow * Size) % 32 == 0 ? 0 : 1);
    unsigned int Data[ArraySize];

    void Build(Pattern<unsigned int> const& iSample);
    void Extract(Pattern<unsigned int>& oSample) const;
  };

  template <unsigned int N, unsigned int FieldSize, bool UseDictionnary = false>
  class ConvChains
  {
  public:

    static const unsigned int GridSize = FieldSize * FieldSize;
    typedef CompactStorage<N - 1, GridSize> Storage;

    struct iequal_to : std::binary_function<Storage,Storage, bool>
    {
      bool operator()(Storage const& x, Storage const& y) const;
    };

    struct ihash : std::unary_function<Storage, std::size_t>
    {
      std::size_t operator()(Storage const& x) const;
    };

    ConvChains(bool iToroidal = false) : m_Toroidal(iToroidal)
    {
      if(UseDictionnary)
      {
        m_Dict.push_back(0xFFFFFFFF);
        m_RevDict[0xFFFFFFFF] = 0;
      }
    }

    ConvChains(Pattern<unsigned int> const& iSample, bool iToroidal = false) : m_Toroidal(iToroidal)
    {
      if(UseDictionnary)
      {
        m_Dict.push_back(0xFFFFFFFF);
        m_RevDict[0xFFFFFFFF] = 0;
      }
      AddPattern(iSample);
    }

    void AddPattern(Pattern<unsigned int> const& iSample, bool iRotateSym = true);

    void Generate(Pattern<unsigned int>& ioResult, Random& iRand, float iTemperature, int iIterations, bool iInitRand = false, Pattern<float> const* iTemp = nullptr);

    void Evaluate(Pattern<unsigned int> const& iPattern, Vector<double>& oRef, Vector<double>& oScore, bool iRotateSym = true) const;

    struct PatternInfo
    {
      uint32_t weight = 0;
      bool isBorder = false;
    };

    typedef UnorderedMap<Storage, PatternInfo, ihash, iequal_to> WeightsMap;

    struct WaveState
    {
      struct CellState
      {
        Vector<uint32_t> comp[4];
        Vector<bool> possible;

        int sumOfOnes;
        float sumOfWeights;
        float sumOfWeightsLogWeight;
        float entropy;
      };

      bool Outside(Vector2i& ioPos)
      {
        auto const& wkAreaSize = m_State.GetSize();

        if(m_Toroidal)
        {
          Vector2i coord((ioPos.X() + wkAreaSize.X()) % wkAreaSize.X(),
            (ioPos.Y() + wkAreaSize.Y()) % wkAreaSize.Y());
          ioPos = coord;
          return false;
        }
        else
        {
          if(ioPos.X() < 0 || ioPos.X() >= (wkAreaSize.X() /*- FieldSize*/)
          || ioPos.Y() < 0 || ioPos.Y() >= (wkAreaSize.Y() /*- FieldSize*/))
          {
            return true;
          }
          return false;
        }
      }

      void InitPropagator()
      {
        auto agrees = [](Pattern<uint32_t> const& iP1, Pattern<uint32_t> const& iP2, int dx, int dy)
        {
          int xmin = dx < 0 ? 0 : dx;
          int xmax = dx < 0 ? dx + FieldSize : FieldSize;
          int ymin = dy < 0 ? 0 : dy;
          int ymax = dy < 0 ? dy + FieldSize : FieldSize;
          for (int y = ymin; y < ymax; y++)
          {
            for (int x = xmin; x < xmax; x++)
            {
              if (iP1[Vector2i(x, y)] != iP2[Vector2i(x - dx, (y - dy))])
              {
                return false;
              }
            }
          }
          return true;
        };

        int DX[4] = {1, -1, 0, 0};
        int DY[4] = {0, 0, 1, -1};

        Vector<Pattern<uint32_t>> extracted(numSymbols, Pattern<uint32_t> (Vector2i(FieldSize, FieldSize)));

        for (int sym = 0; sym < numSymbols; ++sym)
        {
          m_PatternDict[sym]->first.Extract(extracted[sym]);
        }

        for (int d = 0; d < 4; d++)
        {
          for (int sym = 0; sym < numSymbols; ++sym)
          {
            Pattern<uint32_t> const& p1 = extracted[sym];
            //List<int> list = new List<int>();
            Vector<uint32_t> list;
            uint32_t count = 0;
            for (int sym2 = 0; sym2 < numSymbols; ++sym2)
            {
              Pattern<uint32_t> const& p2 = extracted[sym2];

              if (agrees(p1, p2, DX[d], DY[d]))
              {
                ++count;
                list.push_back(sym2);
              }
            }
            //propagator[d][t] = new int[list.Count];
            //for (int c = 0; c < list.Count; c++)
            //{
            //  propagator[d][t][c] = list[c];
            //}
            m_Propagator[d][sym] = std::move(list);
          }
        }
      }

      void Init(ConvChains const& iMem, Vector2i const& iSize)
      {
        m_Toroidal = iMem.m_Toroidal;

        numSymbols = iMem.m_WeightsMap.size();

        CellState defaultCell;
        defaultCell.possible.resize(numSymbols, true);
        for(uint32_t i = 0; i<4; ++i)
        {
          defaultCell.comp[i].resize(numSymbols, 0);
          m_Propagator[i].resize(numSymbols);
        }

        m_State.SetSize(iSize, defaultCell);
        m_CollapsedState.SetSize(iSize, numSymbols);

        for(auto iter = iMem.m_WeightsMap.begin(); iter != iMem.m_WeightsMap.end(); ++iter)
        {
          m_PatternDict.push_back(iter);

          m_SumOfWeights += iter->second.weight;
          m_WeightLogWeights.push_back(iter->second.weight * log(iter->second.weight));
          m_SumOfWeightLogWeights += m_WeightLogWeights.back();
        }

        InitPropagator();

        m_StartingEntropy = log(m_SumOfWeights) - m_SumOfWeightLogWeights / m_SumOfWeights;

      }

      boost::optional<bool> Observe(Random& iRand)
      {
        uint32_t const stateSize = m_State.GetSize().X() * m_State.GetSize().Y();

        float min = 1.0e3;
        int argmin = -1;
        Vector2i selectedPos;
        uint32_t offset = 0;
        for (int y = 0; y < m_State.GetSize().Y(); ++y)
        {
          for (int x = 0; x < m_State.GetSize().X(); ++x)
          {
            if (Outside(Vector2i(x, y)))
            {
              ++offset;
              continue;
            }

            auto const& cellState = m_State[offset];

            int amount = cellState.sumOfOnes;

            if (amount == 0)
            {
              return false;
            }

            float entropy = cellState.entropy;
            if (amount > 1 && entropy <= min)
            {
              double noise = 1.0e-11 * (iRand() % 10000);
              if (entropy + noise < min)
              {
                min = entropy + noise;
                selectedPos = Vector2i(x, y);
                argmin = offset;
              }
            }
            ++offset;
          }
        }

        //if (argmin == -1)
        {
          for (int i = 0; i < stateSize; ++i)
          {
            for (int sym = 0; sym < numSymbols; ++sym)
            {
              if (m_State.GetBitmap()[i].possible[sym])
              {
                m_CollapsedState.GetBitmap()[i] = sym;
                break;
              }
            }
          }
          if (argmin == -1)
          {
            return true;
          }
        }

        float distTotSum = 0;
        Multimap<float, uint32_t> distribution;
        for (int sym = 0; sym < numSymbols; sym++)
        {
          if(m_State.GetBitmap()[argmin].possible[sym])
          {
            distribution.insert(std::make_pair(m_PatternDict[sym]->second.weight, sym));
            distTotSum += m_PatternDict[sym]->second.weight;
          }
        }

        eXl_ASSERT(!distribution.empty());

        uint32_t selectedSym = distribution.begin()->second;
        //int r = distribution.Random(random.NextDouble());
        float val = (float(iRand() % 1000) / 1000.0) * distTotSum;
        for(auto revIter = distribution.rbegin(); revIter != distribution.rend(); ++revIter)
        {
          if(revIter->first > val)
          {
            selectedSym = revIter->second;
            break;
          }
          else
          {
            val -= revIter->first;
          }
        }

        auto const& possibilities = m_State.GetBitmap()[argmin].possible;
        for (int sym = 0; sym < numSymbols; sym++)
        {
          if (possibilities[sym] != (sym == selectedSym))
          {
            Ban(selectedPos, sym);
          }
        }

        return boost::none;
      }

      void Ban(Vector2i pos, uint32_t sym)
      {
        auto& cellState = m_State[pos];
        cellState.possible[sym] = false;

        for (int dir = 0; dir < 4; dir++)
        {
          cellState.comp[dir][sym] = 0;
        }

        m_Stack.push_back(std::make_pair(pos, sym));

        cellState.sumOfOnes -= 1;
        if(cellState.sumOfOnes == 0)
        {
          printf("Termination reached at (%i,%i)", pos.X(), pos.Y());
        }
        cellState.sumOfWeights -= m_PatternDict[sym]->second.weight;
        cellState.sumOfWeightsLogWeight -= m_WeightLogWeights[sym];

        float sum = cellState.sumOfWeights;
        cellState.entropy = log(sum) - cellState.sumOfWeightsLogWeight / sum;
      }

      void Propagate()
      {
        while (!m_Stack.empty())
        {
          auto cell = m_Stack.back();
          m_Stack.pop_back();

          Vector2i const& pos = cell.first;

          uint32_t const& sym = cell.second;

          for (int dim = 0; dim < 2; ++dim)
          {
            for (int signIdx = 0; signIdx < 2; ++signIdx)
            {
              Vector2i otherPos = pos;
              otherPos.m_Data[dim] += 1 - 2*signIdx;

              if(Outside(otherPos))
              {
                continue;
              }
              else
              {
                //int i2 = x2 + y2 * FMX;

                uint32_t dirIdx = dim * 2 + signIdx;

                auto& p = m_Propagator[dirIdx][sym];

                CellState& otherCell = m_State[otherPos];

                for (uint32_t otherSym : p)
                {
                  uint32_t& comp = otherCell.comp[dirIdx][otherSym];

                  comp--;

                  if (comp == 0)
                  {
                    Ban(otherPos, otherSym);
                  }
                }
              }
            }
          }
        }
      }

      void Clear()
      {
        uint32_t localOffset = 0;
        for (int y = 0; y < m_State.GetSize().Y(); ++y)
        {
          for (int x = 0; x < m_State.GetSize().X(); ++x)
          {
            CellState& state = m_State.GetBitmap()[localOffset];

            for (int sym = 0; sym < numSymbols; ++sym)
            {
              state.possible[sym] = true;

              for (int d = 0; d < 4; d++)
              {
                state.comp[d][sym] = state.possible[sym] ? m_Propagator[s_Opposite[d]][sym].size() : 0;
              }

            }

            state.sumOfOnes = numSymbols;
            state.sumOfWeights = m_SumOfWeights;
            state.sumOfWeightsLogWeight = m_SumOfWeightLogWeights;
            state.entropy = m_StartingEntropy;

            ++localOffset;
          }
        }
        if(!m_Toroidal)
        {
          for (int y = 0; y < (int)m_State.GetSize().Y() - FieldSize; ++y)
          {
            for (int x = 0; x < (int)m_State.GetSize().X() - FieldSize; ++x)
            {
              for (int sym = 0; sym < numSymbols; ++sym)
              {
                if(m_PatternDict[sym]->second.isBorder)
                {
                  Ban(Vector2i(x,y), sym);
                }
              }
            }
          }
          Propagate();
        }
      }

      uint32_t s_Opposite[4] = {1, 0, 3, 2};

      Vector<Vector<uint32_t>> m_Propagator[4];

      Pattern<CellState> m_State;
      Pattern<uint32_t> m_CollapsedState;

      Vector<double> m_WeightLogWeights;

      uint32_t numSymbols;
      bool m_Toroidal;

      float m_SumOfWeights = 0;
      float m_SumOfWeightLogWeights = 0;
      float m_StartingEntropy = 0;

      uint32_t m_RestartCounter = 0;

      Vector<typename WeightsMap::const_iterator> m_PatternDict;
      Vector<std::pair<Vector2i, uint32_t>> m_Stack;
    };

    void Wave(Pattern<unsigned int>& ioResult, Random& iRand, uint32_t numIter, WaveState& ioState, bool iInit = false)
    {
      if(iInit)
      {
        ioState.Clear();
      }

      eXl_ASSERT(ioResult.GetSize() == ioState.m_State.GetSize());

      for (uint32_t l = 0; l < numIter; l++)
      {
        auto result = ioState.Observe(iRand);
        if (!result)
        {
          ioState.Propagate();
        }
        else if(!result.get())
        {
          ioState.Clear();
          ioState.m_RestartCounter++;
          printf("Restarted %i \n", ioState.m_RestartCounter);
        }
      }

      uint32_t globOffset = 0;
      for (int y = 0; y < ioState.m_State.GetSize().Y(); ++y)
      {
        for (int x = 0; x < ioState.m_State.GetSize().X(); ++x)
        {
          Vector2i curPos(x,y);

          uint32_t sym = ioState.m_CollapsedState.GetBitmap()[globOffset];
          if(sym != ioState.numSymbols)
          {
            Pattern<uint32_t> pattern(Vector2i(FieldSize, FieldSize));
            ioState.m_PatternDict[sym]->first.Extract(pattern);
            //ioResult[curPos] = m_Dict[pattern[Vector2i::ZERO]];
            for (int ly = 0; ly < FieldSize; ++ly)
            {
              for (int lx = 0; lx < FieldSize; ++lx)
              {
                Vector2i localPos(lx, ly);
                Vector2i otherPos = curPos;
                otherPos += Vector2i (lx, ly);
                if(otherPos.X() >=0 && otherPos.X() < ioState.m_State.GetSize().X()
                && otherPos.Y() >=0 && otherPos.Y() < ioState.m_State.GetSize().Y())
                {
                  ioResult[otherPos] = m_Dict[pattern[localPos]];
                }
              }
            }
          }

          ++globOffset;
        }
      }

      //return true;
    }

    Image GetPatternImage()
    {
      uint32_t dimX = Mathf::Round(sqrt(m_WeightsMap.size()));
      uint32_t dimY = m_WeightsMap.size() / dimX;
      if(m_WeightsMap.size() % dimX != 0)
      {
        ++dimX;
      }

      Image::Size imageSize(dimX * (FieldSize + 1) - 1, dimY * (FieldSize + 1) - 1);

      Vector<WeightsMap::iterator> patternDict;
      Multimap<uint32_t, uint32_t> patternSort;

      for(auto iter = m_WeightsMap.begin(); iter != m_WeightsMap.end(); ++iter)
      {
        patternDict.push_back(iter);
        patternSort.insert(std::make_pair(iter->second.weight, patternDict.size() - 1));
      }

      Image outImg(nullptr, imageSize, Image::RGBA, Image::Char, 1);
      memset(outImg.GetImageData(), 0, outImg.GetByteSize());

      Vector2i curPos;

      Pattern<uint32_t> pattern(Vector2i::ONE * FieldSize);
      for(auto rIter = patternSort.rbegin(); rIter != patternSort.rend(); ++rIter)
      {
        patternDict[rIter->second]->first.Extract(pattern);

        for(uint32_t y = 0; y<FieldSize; ++y)
        {
          for(uint32_t x = 0; x<FieldSize; ++x)
          {
            Vector2i locPos(x,y);
            Vector2i globPos = curPos + locPos;
            *((uint32_t*)outImg.GetPixel(globPos.Y(), globPos.X())) = pattern[locPos] == 1 ? 0 : 0xFFFFFFFF;
          }
        }

        if(curPos.X() + FieldSize < imageSize.X())
        {
          curPos.X() += FieldSize + 1;
        }
        else
        {
          curPos.X() = 0;
          curPos.Y() += FieldSize + 1;
        }
      }

      return outImg;
    }

  protected:

    Vector<unsigned int> m_TempBuffer;

    WeightsMap m_WeightsMap;

    void _AddPattern(Pattern<unsigned int> const& iSample, bool iRotateSym);

    unsigned int GetValue(unsigned int iOldValue, Random& iRand);

    void ComputePatternReceptor(Pattern<unsigned int>& oPattern, Pattern<unsigned int> const& iSample, Vector2i const& iCoord) const;

    typename WeightsMap::iterator ComputeReceptorIndex(Pattern<unsigned int> const& iReceptor, bool iCreate);

    typename WeightsMap::iterator ComputeReceptorIndex(Pattern<unsigned int> const& iReceptor) const;

    double ComputeEnergy(Pattern<unsigned int>& temp, Pattern<unsigned int> const& iSample, Vector2i const& iCoord);

    Vector<unsigned int> m_Dict;
    Map<unsigned int, unsigned int> m_RevDict;
    bool m_Toroidal;

  };

#include <gen/convchains.inl>

}