<commit_before>// Copyright 2018 Google Inc.
//
// 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.
//
//  Dichotomy loop and default search implementation
//
// Author: Skal (pascal.massimino@gmail.com)

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include "sjpegi.h"

using namespace sjpeg;

////////////////////////////////////////////////////////////////////////////////
// dichotomy

#define DBG_PRINT 0

// convergence is considered reached if |dq| < kdQLimit.
static const float kdQLimit = 0.15;

static float Clamp(float v, float min, float max) {
  return (v < min) ? min : (v > max) ? max : v;
}

bool SearchHook::Setup(const SjpegEncodeParam& param) {
  for_size = (param.target_mode == SjpegEncodeParam::TARGET_SIZE);
  target = param.target_value;
  tolerance = param.tolerance / 100.;
  qmin = (param.qmin < 0) ? 0 : param.qmin;
  qmax = (param.qmax > 100) ? 100 :
         (param.qmax < param.qmin) ? param.qmin : param.qmax;
  q = Clamp(SjpegEstimateQuality(param.GetQuantMatrix(0), false), qmin, qmax);
  value = 0;   // undefined for at this point
  return true;
}

bool SearchHook::Update(float result) {
  value = result;
  bool done = (fabs(value - target) < tolerance * target);
  if (done) return true;

  if (value > target) {
    qmax = q;
  } else {
    qmin = q;
  }
  const float last_q = q;
  q = (qmin + qmax) / 2.;
  done = (fabs(q - last_q) < kdQLimit);
  if (DBG_PRINT) {
    printf(" -> next-q=%.2f\n", last_q);
  }
  return done;
}

void SearchHook::NextMatrix(int idx, uint8_t dst[64]) {
  SetQuantMatrix(kDefaultMatrices[idx], GetQFactor(q), dst);
}

////////////////////////////////////////////////////////////////////////////////
// Helpers for the search

void Encoder::StoreRunLevels(DCTCoeffs* coeffs) {
  assert(use_extra_memory_);
  assert(reuse_run_levels_);

  const QuantizeBlockFunc quantize_block = use_trellis_ ? TrellisQuantizeBlock
                                                        : quantize_block_;
  if (use_trellis_) InitCodes(true);

  ResetDCs();
  nb_run_levels_ = 0;
  int16_t* in = in_blocks_;
  for (int n = 0; n < mb_w_ * mb_h_; ++n) {
    CheckBuffers();
    for (int c = 0; c < nb_comps_; ++c) {
      for (int i = 0; i < nb_blocks_[c]; ++i) {
        RunLevel* const run_levels = all_run_levels_ + nb_run_levels_;
        const int dc = quantize_block(in, c, &quants_[quant_idx_[c]],
                                      coeffs, run_levels);
        coeffs->dc_code_ = GenerateDCDiffCode(dc, &DCs_[c]);
        nb_run_levels_ += coeffs->nb_coeffs_;
        ++coeffs;
        in += 64;
      }
    }
  }
}

void Encoder::LoopScan() {
  assert(use_extra_memory_);
  assert(reuse_run_levels_);

  if (use_adaptive_quant_) {
    CollectHistograms();
  } else {
    CollectCoeffs();   // we just need the coeffs
  }

  const size_t nb_mbs = mb_w_ * mb_h_ * mcu_blocks_;
  DCTCoeffs* const base_coeffs = new DCTCoeffs[nb_mbs];

  uint8_t opt_quants[2][64];

  // Dichotomy passes
  float best = 0.;     // best distance
  float best_q = 0.;  // informative value to return to the user
  float best_result = 0.;
  for (int p = 0; p < passes_; ++p) {
    // set new matrices to evaluate
    for (int c = 0; c < 2; ++c) {
      search_hook_->NextMatrix(c, quants_[c].quant_);
      FinalizeQuantMatrix(&quants_[c], q_bias_);
    }
    if (use_adaptive_quant_) {
      AnalyseHisto();   // adjust quant_[] matrices
    }

    float result;
    if (search_hook_->for_size) {
      // compute pass to store coeffs / runs / dc_code_
      StoreRunLevels(base_coeffs);
      if (optimize_size_) {
        StoreOptimalHuffmanTables(nb_mbs, base_coeffs);
        if (use_trellis_) InitCodes(true);
      }
      result = ComputeSize(base_coeffs);
    } else {
      // if we're just targeting PSNR, we don't need to compute the
      // run/levels within the loop. We just need to quantize the coeffs
      // and measure the distortion.
      result = ComputePSNR();
    }
    if (DBG_PRINT) printf("pass #%d: q=%.2f value:%.2f ",
                          p, search_hook_->q, result);

    if (p == 0 || fabs(result - search_hook_->target) < best) {
      // save the matrices for later, if they are better
      for (int c = 0; c < 2; ++c) {
        CopyQuantMatrix(quants_[c].quant_, opt_quants[c]);
      }
      best = fabs(result - search_hook_->target);
      best_q = search_hook_->q;
      best_result = result;
    }
    if (search_hook_->Update(result)) break;
  }
  // transfer back the final matrices
  SetQuantMatrices(opt_quants);
  for (int c = 0; c < 2; ++c) FinalizeQuantMatrix(&quants_[c], q_bias_);

  // return informative values to the user
  search_hook_->q = best_q;
  search_hook_->value = best_result;

  // optimize Huffman table now, if we haven't already during the search
  if (!search_hook_->for_size) {
    StoreRunLevels(base_coeffs);
    if (optimize_size_) {
      StoreOptimalHuffmanTables(nb_mbs, base_coeffs);
    }
  }

  // finish bitstream
  WriteDQT();
  WriteSOF();
  WriteDHT();
  WriteSOS();
  FinalPassScan(nb_mbs, base_coeffs);

  delete[] base_coeffs;
}

////////////////////////////////////////////////////////////////////////////////
// Size & PSNR computation, mostly for dichotomy

size_t Encoder::HeaderSize() const {
  size_t size = 0;
  size += 20;    // APP0
  size += app_markers_.size();
  if (exif_.size() > 0) {
    size += 8 + exif_.size();
  }
  if (iccp_.size() > 0) {
    const size_t chunk_size_max = 0xffff - 12 - 4;
    const size_t num_chunks = (iccp_.size() - 1) / chunk_size_max + 1;
    size += num_chunks * (12 + 4 + 2);
    size += iccp_.size();
  }
  if (xmp_.size() > 0) {
    size += 2 + 2 + 29 + xmp_.size();
  }
  size += 2 * 65 + 2 + 2;         // DQT
  size += 8 + 3 * nb_comps_ + 2;  // SOF
  size += 6 + 2 * nb_comps_ + 2;  // SOS
  size += 2;                      // EOI
  // DHT:
  for (int c = 0; c < (nb_comps_ == 1 ? 1 : 2); ++c) {   // luma, chroma
    for (int type = 0; type <= 1; ++type) {               // dc, ac
      const HuffmanTable* const h = Huffman_tables_[type * 2 + c];
      size += 2 + 3 + 16 + h->nb_syms_;
    }
  }
  return size * 8;
}

void Encoder::BlocksSize(int nb_mbs, const DCTCoeffs* coeffs,
                         const RunLevel* rl,
                         BitCounter* const bc) const {
  for (int n = 0; n < nb_mbs; ++n) {
    const DCTCoeffs& c = coeffs[n];
    const int idx = c.idx_;
    const int q_idx = quant_idx_[idx];

    // DC
    const int dc_len = c.dc_code_ & 0x0f;
    const uint32_t code = dc_codes_[q_idx][dc_len];
    bc->AddPackedCode(code);
    bc->AddBits(c.dc_code_ >> 4, dc_len);

    // AC
    const uint32_t* const codes = ac_codes_[q_idx];
    for (int i = 0; i < c.nb_coeffs_; ++i) {
      int run = rl[i].run_;
      while (run & ~15) {        // escapes
        bc->AddPackedCode(codes[0xf0]);
        run -= 16;
      }
      const uint32_t suffix = rl[i].level_;
      const size_t nbits = suffix & 0x0f;
      const int sym = (run << 4) | nbits;
      bc->AddPackedCode(codes[sym]);
      bc->AddBits(suffix >> 4, nbits);
    }
    if (c.last_ < 63) bc->AddPackedCode(codes[0x00]);  // EOB
    rl += c.nb_coeffs_;
  }
}

float Encoder::ComputeSize(const DCTCoeffs* coeffs) {
  InitCodes(false);
  size_t size = HeaderSize();
  BitCounter bc;
  BlocksSize(mb_w_ * mb_h_ * mcu_blocks_, coeffs, all_run_levels_, &bc);
  size += bc.Size();
  return size / 8.f;
}

////////////////////////////////////////////////////////////////////////////////

static float GetPSNR(uint64_t err, uint64_t size) {
  // This expression is written such that it gives the same result on ARM
  // and x86 (for large values of err/size in particular). Don't change it!
  return (err > 0 && size > 0) ? 4.3429448f * log(size / (err / 255. / 255.))
                               : 99.f;
}

float Encoder::ComputePSNR() const {
  uint64_t error = 0;
  const int16_t* in = in_blocks_;
  const size_t nb_mbs = mb_w_ * mb_h_;
  for (size_t n = 0; n < nb_mbs; ++n) {
    for (int c = 0; c < nb_comps_; ++c) {
      const Quantizer* const Q = &quants_[quant_idx_[c]];
      for (int i = 0; i < nb_blocks_[c]; ++i) {
        error += quantize_error_(in, Q);
        in += 64;
      }
    }
  }
  return GetPSNR(error, 64ull * nb_mbs * mcu_blocks_);
}
<commit_msg>Avoid undefined behaviour my not calling AddBits<commit_after>// Copyright 2018 Google Inc.
//
// 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.
//
//  Dichotomy loop and default search implementation
//
// Author: Skal (pascal.massimino@gmail.com)

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include "sjpegi.h"

using namespace sjpeg;

////////////////////////////////////////////////////////////////////////////////
// dichotomy

#define DBG_PRINT 0

// convergence is considered reached if |dq| < kdQLimit.
static const float kdQLimit = 0.15;

static float Clamp(float v, float min, float max) {
  return (v < min) ? min : (v > max) ? max : v;
}

bool SearchHook::Setup(const SjpegEncodeParam& param) {
  for_size = (param.target_mode == SjpegEncodeParam::TARGET_SIZE);
  target = param.target_value;
  tolerance = param.tolerance / 100.;
  qmin = (param.qmin < 0) ? 0 : param.qmin;
  qmax = (param.qmax > 100) ? 100 :
         (param.qmax < param.qmin) ? param.qmin : param.qmax;
  q = Clamp(SjpegEstimateQuality(param.GetQuantMatrix(0), false), qmin, qmax);
  value = 0;   // undefined for at this point
  return true;
}

bool SearchHook::Update(float result) {
  value = result;
  bool done = (fabs(value - target) < tolerance * target);
  if (done) return true;

  if (value > target) {
    qmax = q;
  } else {
    qmin = q;
  }
  const float last_q = q;
  q = (qmin + qmax) / 2.;
  done = (fabs(q - last_q) < kdQLimit);
  if (DBG_PRINT) {
    printf(" -> next-q=%.2f\n", last_q);
  }
  return done;
}

void SearchHook::NextMatrix(int idx, uint8_t dst[64]) {
  SetQuantMatrix(kDefaultMatrices[idx], GetQFactor(q), dst);
}

////////////////////////////////////////////////////////////////////////////////
// Helpers for the search

void Encoder::StoreRunLevels(DCTCoeffs* coeffs) {
  assert(use_extra_memory_);
  assert(reuse_run_levels_);

  const QuantizeBlockFunc quantize_block = use_trellis_ ? TrellisQuantizeBlock
                                                        : quantize_block_;
  if (use_trellis_) InitCodes(true);

  ResetDCs();
  nb_run_levels_ = 0;
  int16_t* in = in_blocks_;
  for (int n = 0; n < mb_w_ * mb_h_; ++n) {
    CheckBuffers();
    for (int c = 0; c < nb_comps_; ++c) {
      for (int i = 0; i < nb_blocks_[c]; ++i) {
        RunLevel* const run_levels = all_run_levels_ + nb_run_levels_;
        const int dc = quantize_block(in, c, &quants_[quant_idx_[c]],
                                      coeffs, run_levels);
        coeffs->dc_code_ = GenerateDCDiffCode(dc, &DCs_[c]);
        nb_run_levels_ += coeffs->nb_coeffs_;
        ++coeffs;
        in += 64;
      }
    }
  }
}

void Encoder::LoopScan() {
  assert(use_extra_memory_);
  assert(reuse_run_levels_);

  if (use_adaptive_quant_) {
    CollectHistograms();
  } else {
    CollectCoeffs();   // we just need the coeffs
  }

  const size_t nb_mbs = mb_w_ * mb_h_ * mcu_blocks_;
  DCTCoeffs* const base_coeffs = new DCTCoeffs[nb_mbs];

  uint8_t opt_quants[2][64];

  // Dichotomy passes
  float best = 0.;     // best distance
  float best_q = 0.;  // informative value to return to the user
  float best_result = 0.;
  for (int p = 0; p < passes_; ++p) {
    // set new matrices to evaluate
    for (int c = 0; c < 2; ++c) {
      search_hook_->NextMatrix(c, quants_[c].quant_);
      FinalizeQuantMatrix(&quants_[c], q_bias_);
    }
    if (use_adaptive_quant_) {
      AnalyseHisto();   // adjust quant_[] matrices
    }

    float result;
    if (search_hook_->for_size) {
      // compute pass to store coeffs / runs / dc_code_
      StoreRunLevels(base_coeffs);
      if (optimize_size_) {
        StoreOptimalHuffmanTables(nb_mbs, base_coeffs);
        if (use_trellis_) InitCodes(true);
      }
      result = ComputeSize(base_coeffs);
    } else {
      // if we're just targeting PSNR, we don't need to compute the
      // run/levels within the loop. We just need to quantize the coeffs
      // and measure the distortion.
      result = ComputePSNR();
    }
    if (DBG_PRINT) printf("pass #%d: q=%.2f value:%.2f ",
                          p, search_hook_->q, result);

    if (p == 0 || fabs(result - search_hook_->target) < best) {
      // save the matrices for later, if they are better
      for (int c = 0; c < 2; ++c) {
        CopyQuantMatrix(quants_[c].quant_, opt_quants[c]);
      }
      best = fabs(result - search_hook_->target);
      best_q = search_hook_->q;
      best_result = result;
    }
    if (search_hook_->Update(result)) break;
  }
  // transfer back the final matrices
  SetQuantMatrices(opt_quants);
  for (int c = 0; c < 2; ++c) FinalizeQuantMatrix(&quants_[c], q_bias_);

  // return informative values to the user
  search_hook_->q = best_q;
  search_hook_->value = best_result;

  // optimize Huffman table now, if we haven't already during the search
  if (!search_hook_->for_size) {
    StoreRunLevels(base_coeffs);
    if (optimize_size_) {
      StoreOptimalHuffmanTables(nb_mbs, base_coeffs);
    }
  }

  // finish bitstream
  WriteDQT();
  WriteSOF();
  WriteDHT();
  WriteSOS();
  FinalPassScan(nb_mbs, base_coeffs);

  delete[] base_coeffs;
}

////////////////////////////////////////////////////////////////////////////////
// Size & PSNR computation, mostly for dichotomy

size_t Encoder::HeaderSize() const {
  size_t size = 0;
  size += 20;    // APP0
  size += app_markers_.size();
  if (exif_.size() > 0) {
    size += 8 + exif_.size();
  }
  if (iccp_.size() > 0) {
    const size_t chunk_size_max = 0xffff - 12 - 4;
    const size_t num_chunks = (iccp_.size() - 1) / chunk_size_max + 1;
    size += num_chunks * (12 + 4 + 2);
    size += iccp_.size();
  }
  if (xmp_.size() > 0) {
    size += 2 + 2 + 29 + xmp_.size();
  }
  size += 2 * 65 + 2 + 2;         // DQT
  size += 8 + 3 * nb_comps_ + 2;  // SOF
  size += 6 + 2 * nb_comps_ + 2;  // SOS
  size += 2;                      // EOI
  // DHT:
  for (int c = 0; c < (nb_comps_ == 1 ? 1 : 2); ++c) {   // luma, chroma
    for (int type = 0; type <= 1; ++type) {               // dc, ac
      const HuffmanTable* const h = Huffman_tables_[type * 2 + c];
      size += 2 + 3 + 16 + h->nb_syms_;
    }
  }
  return size * 8;
}

void Encoder::BlocksSize(int nb_mbs, const DCTCoeffs* coeffs,
                         const RunLevel* rl,
                         BitCounter* const bc) const {
  for (int n = 0; n < nb_mbs; ++n) {
    const DCTCoeffs& c = coeffs[n];
    const int idx = c.idx_;
    const int q_idx = quant_idx_[idx];

    // DC
    const int dc_len = c.dc_code_ & 0x0f;
    const uint32_t code = dc_codes_[q_idx][dc_len];
    bc->AddPackedCode(code);
    if (dc_len) bc->AddBits(c.dc_code_ >> 4, dc_len);

    // AC
    const uint32_t* const codes = ac_codes_[q_idx];
    for (int i = 0; i < c.nb_coeffs_; ++i) {
      int run = rl[i].run_;
      while (run & ~15) {        // escapes
        bc->AddPackedCode(codes[0xf0]);
        run -= 16;
      }
      const uint32_t suffix = rl[i].level_;
      const size_t nbits = suffix & 0x0f;
      const int sym = (run << 4) | nbits;
      bc->AddPackedCode(codes[sym]);
      bc->AddBits(suffix >> 4, nbits);
    }
    if (c.last_ < 63) bc->AddPackedCode(codes[0x00]);  // EOB
    rl += c.nb_coeffs_;
  }
}

float Encoder::ComputeSize(const DCTCoeffs* coeffs) {
  InitCodes(false);
  size_t size = HeaderSize();
  BitCounter bc;
  BlocksSize(mb_w_ * mb_h_ * mcu_blocks_, coeffs, all_run_levels_, &bc);
  size += bc.Size();
  return size / 8.f;
}

////////////////////////////////////////////////////////////////////////////////

static float GetPSNR(uint64_t err, uint64_t size) {
  // This expression is written such that it gives the same result on ARM
  // and x86 (for large values of err/size in particular). Don't change it!
  return (err > 0 && size > 0) ? 4.3429448f * log(size / (err / 255. / 255.))
                               : 99.f;
}

float Encoder::ComputePSNR() const {
  uint64_t error = 0;
  const int16_t* in = in_blocks_;
  const size_t nb_mbs = mb_w_ * mb_h_;
  for (size_t n = 0; n < nb_mbs; ++n) {
    for (int c = 0; c < nb_comps_; ++c) {
      const Quantizer* const Q = &quants_[quant_idx_[c]];
      for (int i = 0; i < nb_blocks_[c]; ++i) {
        error += quantize_error_(in, Q);
        in += 64;
      }
    }
  }
  return GetPSNR(error, 64ull * nb_mbs * mcu_blocks_);
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>

#include "axes_iterator.h"

linear::linear(const axis &a, std::size_t meta_index)
{
  auto update_func = [=](std::size_t inc_index,
                        std::vector<std::pair<axis, std::size_t>> &indices) {

    indices[meta_index] = {a, inc_index};
  };

  this->m_iter = make_space_iterator(1, a.m_length, update_func);
}
tie::tie(const std::vector<axis> &axes, std::vector<std::size_t> meta_indices)
{
  auto update_func = [=](std::size_t inc_index,
                        std::vector<std::pair<axis, std::size_t>> &indices) {

    for(std::size_t i = 0; i < axes.size(); ++i)
    {
      indices[meta_indices[i]] = {axes[i], inc_index};
    }
  };

  this->m_iter = make_space_iterator(axes.size(), axes[0].m_length, update_func);
}
user::user(std::size_t number_of_axes,
           std::size_t number_of_iterations,
           std::function<UpdateSignature>&& update_func)
{
  this->m_iter = make_space_iterator(number_of_axes, number_of_iterations, std::move(update_func));
}

void state_iterator::add_iteration_space(
    const axis_space_base &iteration_space) {
  auto& iter = iteration_space.m_iter;
  this->m_space.push_back(iter);
  this->m_axes_count += iter.m_number_of_axes;
  this->m_max_iteration *= iter.m_iteration_size;
}

void state_iterator::init() {
  this->m_current_space = 0;
  this->m_current_iteration = 0;
  }
bool state_iterator::iter_valid() const { return m_current_iteration < m_max_iteration; }
void state_iterator::next() {
  m_current_iteration++;

  for(auto&& space : this->m_space)
  {
    auto rolled_over = space.inc();
    if(rolled_over) {
      continue;
    }
    break;
  }
}

std::vector<std::pair<axis, std::size_t>>
state_iterator::get_current_indices() const {
  std::vector<std::pair<axis, std::size_t>> indices(m_axes_count);
  for (auto &m : m_space) {
    m.update_indices(indices);
  }
  return indices;
}

int main() {
  axis x{"X", 4};
  axis y{"Y", 4};
  axis z{"Z", 4};

  {
    state_iterator si;
    si.add_iteration_space(tie{{z, y}, {2, 1}});
    si.add_iteration_space(linear{x, 0});
    std::cout << "X\tY\tZ" << std::endl;
    for(si.init(); si.iter_valid(); si.next())
    {
      auto indices = si.get_current_indices();
      for(auto&& i : indices) {
        std::cout << i.second << "\t";
      }
      std::cout << std::endl;
    }
  }

  std::cout << std::endl << std::endl << std::endl;
  {
    state_iterator si;
    auto diag_under = [&](std::size_t inc_index,
                          std::vector<std::pair<axis, std::size_t>> &indices){

    };
    si.add_iteration_space(linear{x, 0});
    si.add_iteration_space(user{2, ((y.m_length * (z.m_length+1))/2), diag_under });

    std::cout << "X\tY\tZ" << std::endl;
    for(si.init(); si.iter_valid(); si.next())
    {
      auto indices = si.get_current_indices();
      for(auto&& i : indices) {
        std::cout << i.second << "\t";
      }
      std::cout << std::endl;
    }
  }

  return 0;
}
<commit_msg>first version of working user iterator<commit_after>#include <algorithm>
#include <iostream>

#include "axes_iterator.h"

linear::linear(const axis &a, std::size_t meta_index)
{
  auto update_func = [=](std::size_t inc_index,
                        std::vector<std::pair<axis, std::size_t>> &indices) {

    indices[meta_index] = {a, inc_index};
  };

  this->m_iter = make_space_iterator(1, a.m_length, update_func);
}
tie::tie(const std::vector<axis> &axes, std::vector<std::size_t> meta_indices)
{
  auto update_func = [=](std::size_t inc_index,
                        std::vector<std::pair<axis, std::size_t>> &indices) {

    for(std::size_t i = 0; i < axes.size(); ++i)
    {
      indices[meta_indices[i]] = {axes[i], inc_index};
    }
  };

  this->m_iter = make_space_iterator(axes.size(), axes[0].m_length, update_func);
}
user::user(std::size_t number_of_axes,
           std::size_t number_of_iterations,
           std::function<UpdateSignature>&& update_func)
{
  this->m_iter = make_space_iterator(number_of_axes, number_of_iterations, std::move(update_func));
}

void state_iterator::add_iteration_space(
    const axis_space_base &iteration_space) {
  auto& iter = iteration_space.m_iter;
  this->m_space.push_back(iter);
  this->m_axes_count += iter.m_number_of_axes;
  this->m_max_iteration *= iter.m_iteration_size;
}

void state_iterator::init() {
  this->m_current_space = 0;
  this->m_current_iteration = 0;
  }
bool state_iterator::iter_valid() const { return m_current_iteration < m_max_iteration; }
void state_iterator::next() {
  m_current_iteration++;

  for(auto&& space : this->m_space)
  {
    auto rolled_over = space.inc();
    if(rolled_over) {
      continue;
    }
    break;
  }
}

std::vector<std::pair<axis, std::size_t>>
state_iterator::get_current_indices() const {
  std::vector<std::pair<axis, std::size_t>> indices(m_axes_count);
  for (auto &m : m_space) {
    m.update_indices(indices);
  }
  return indices;
}

int main() {
  axis x{"X", 4};
  axis y{"Y", 4};
  axis z{"Z", 4};

  {
    state_iterator si;
    si.add_iteration_space(tie{{z, y}, {2, 1}});
    si.add_iteration_space(linear{x, 0});
    std::cout << "X\tY\tZ tie(y,z)" << std::endl;
    for(si.init(); si.iter_valid(); si.next())
    {
      auto indices = si.get_current_indices();
      for(auto&& i : indices) {
        std::cout << i.second << "\t";
      }
      std::cout << std::endl;
    }
  }

  std::cout << std::endl << std::endl << std::endl;
  {
    state_iterator si;
    auto diag_under = [&](std::size_t inc_index,
                          std::vector<std::pair<axis, std::size_t>> &indices){

      // I think we need a `inc()` lambda to make this easier to write
      std::size_t y_pos = 0, inc = 0;
      for(std::size_t i=0; i < inc_index; i++)
      {
        y_pos++;
        if(y_pos == y.m_length) {
          y_pos = ++inc;
        }
      }

      size_t z_pos = 0; inc = y.m_length + 1;
      for(std::size_t i=0; i <= inc_index; i+=inc)
      {
        z_pos = ((y.m_length + 1) - (inc));
        --inc;
      }
      indices[1] = {y, y_pos};
      indices[2] = {z, z_pos};

    };
    size_t iteration_length = ((y.m_length * (z.m_length+1))/2);

    std::cout << iteration_length << std::endl;
    si.add_iteration_space(linear{x, 0});
    si.add_iteration_space(user{2, iteration_length, diag_under });

    std::cout << "X\tY\tZ diag(y/z)" << std::endl;
    for(si.init(); si.iter_valid(); si.next())
    {
      auto indices = si.get_current_indices();
      for(auto&& i : indices) {
        std::cout << i.second << "\t";
      }
      std::cout << std::endl;
    }
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "playing_screen.h"

#include "game_manager.h"
#include "../hmi/hmi_manager.h"

void PlayingScreen::init() {
	ball.init();
	ball.set_queue(true);
	pad1.init();
	pad1.reverse(true);
	pad2.init();

	ball_local_speed = 0;
	if (game.data.last_winner == PLAYER2) {
		ball_position = HMI_WIDTH;
		ball_direction = -1;
	} else {
		ball_position = -HMI_WIDTH;
		ball_direction = 1;
	}
	inhibed_controls = true;

	ball_speed.init();
	if (game.mode == CONQUER) {
		ball_speed.set_duration(10000);
	} else if (game.mode == NORMAL) {
		ball_speed.set_duration(21000);
	}
	ball_speed.start();

	quit = 0;

	hmi.log("C'est (re)parti !\n");
}

void PlayingScreen::animate() {
	hmi.leds.clear();
	ball_speed.animate();
	// Compute ball speed and new position
	float real_speed = HMI_DTMS / (600.0 + (1 - ball_speed) * 4000.0 - ball_local_speed) * HMI_WIDTH * 2;
	if (real_speed > HMI_DTMS / 500.0 * HMI_WIDTH * 2)
		real_speed = HMI_DTMS / 500.0 * HMI_WIDTH * 2;
	ball_position += real_speed * ball_direction;
	ball.set_shiny(
		(HMI_WIDTH - 20 < ball_position && ball_direction > 0) ||
		(20 - HMI_WIDTH > ball_position && ball_direction < 0)
	);
	ball.set_position(ball_position);
	if (ball_position < HMI_WIDTH - 21 && ball_position > 21 - HMI_WIDTH)
		inhibed_controls = false;

	if (!quit) {
		// Check for win
		if (ball_position < -HMI_WIDTH) {
			game.data.last_winner = PLAYER2;
			game.data.p2score += 1;
			if (game.mode == NORMAL && game.data.p2score + game.data.p1score >= MAX_POINTS)
				game.data.p1score = MAX_POINTS - game.data.p2score;
			quit = true;
		}
		if (ball_position > HMI_WIDTH) {
			game.data.last_winner = PLAYER1;
			game.data.p1score += 1;
			if (game.mode == CONQUER && game.data.p2score + game.data.p1score >= MAX_POINTS)
				game.data.p2score = MAX_POINTS - game.data.p1score;
			quit = true;
		}

		// Play pads
		if (hmi.btn1.stouched() && pad1.can_fire() && !inhibed_controls) {
			if (20 - HMI_WIDTH > ball_position) {
				pad1.fire(HMI_WIDTH + ball_position);
				ball_direction = 1;
				ball_local_speed = 50 * (20 - HMI_WIDTH - ball_position);
			} else {
				pad1.fire(20);
			}
		}
		if (hmi.btn2.stouched() && pad2.can_fire() && !inhibed_controls) {
			if (HMI_WIDTH - 20 < ball_position) {
				pad2.fire(HMI_WIDTH - ball_position);
				ball_direction = -1;
				ball_local_speed = 50 * (20 - HMI_WIDTH + ball_position);
			} else {
				pad2.fire(20);
			}
		}
		ball.animate();
	} else if (pad1.can_fire() && pad2.can_fire()) {
		game.show_scores();
	}

	// Update all
	pad1.animate();
	pad2.animate();
}
<commit_msg>game: increase initial speed<commit_after>#include "playing_screen.h"

#include "game_manager.h"
#include "../hmi/hmi_manager.h"

void PlayingScreen::init() {
	ball.init();
	ball.set_queue(true);
	pad1.init();
	pad1.reverse(true);
	pad2.init();

	ball_local_speed = 0;
	if (game.data.last_winner == PLAYER2) {
		ball_position = HMI_WIDTH;
		ball_direction = -1;
	} else {
		ball_position = -HMI_WIDTH;
		ball_direction = 1;
	}
	inhibed_controls = true;

	ball_speed.init();
	if (game.mode == CONQUER) {
		ball_speed.set_duration(10000);
	} else if (game.mode == NORMAL) {
		ball_speed.set_duration(21000);
	}
	ball_speed.start();

	quit = 0;

	hmi.log("C'est (re)parti !\n");
}

void PlayingScreen::animate() {
	hmi.leds.clear();
	ball_speed.animate();
	// Compute ball speed and new position
	float real_speed = HMI_DTMS / (800.0 + (1 - ball_speed) * 4000.0 - ball_local_speed) * HMI_WIDTH * 2;
	if (real_speed > HMI_DTMS / 500.0 * HMI_WIDTH * 2)
		real_speed = HMI_DTMS / 500.0 * HMI_WIDTH * 2;
	ball_position += real_speed * ball_direction;
	ball.set_shiny(
		(HMI_WIDTH - 20 < ball_position && ball_direction > 0) ||
		(20 - HMI_WIDTH > ball_position && ball_direction < 0)
	);
	ball.set_position(ball_position);
	if (ball_position < HMI_WIDTH - 21 && ball_position > 21 - HMI_WIDTH)
		inhibed_controls = false;

	if (!quit) {
		// Check for win
		if (ball_position < -HMI_WIDTH) {
			game.data.last_winner = PLAYER2;
			game.data.p2score += 1;
			if (game.mode == NORMAL && game.data.p2score + game.data.p1score >= MAX_POINTS)
				game.data.p1score = MAX_POINTS - game.data.p2score;
			quit = true;
		}
		if (ball_position > HMI_WIDTH) {
			game.data.last_winner = PLAYER1;
			game.data.p1score += 1;
			if (game.mode == CONQUER && game.data.p2score + game.data.p1score >= MAX_POINTS)
				game.data.p2score = MAX_POINTS - game.data.p1score;
			quit = true;
		}

		// Play pads
		if (hmi.btn1.stouched() && pad1.can_fire() && !inhibed_controls) {
			if (20 - HMI_WIDTH > ball_position) {
				pad1.fire(HMI_WIDTH + ball_position);
				ball_direction = 1;
				ball_local_speed = 50 * (20 - HMI_WIDTH - ball_position);
			} else {
				pad1.fire(20);
			}
		}
		if (hmi.btn2.stouched() && pad2.can_fire() && !inhibed_controls) {
			if (HMI_WIDTH - 20 < ball_position) {
				pad2.fire(HMI_WIDTH - ball_position);
				ball_direction = -1;
				ball_local_speed = 50 * (20 - HMI_WIDTH + ball_position);
			} else {
				pad2.fire(20);
			}
		}
		ball.animate();
	} else if (pad1.can_fire() && pad2.can_fire()) {
		game.show_scores();
	}

	// Update all
	pad1.animate();
	pad2.animate();
}
<|endoftext|>


<commit_before>// Copyright 2010 Jens-Michael Hoffmann <jmho@c-xx.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library. If not, see <http://www.gnu.org/licenses/>.

#include "TileLoader.h"

#include <QtCore/QDateTime>
#include <QtCore/QFileInfo>
#include <QtCore/QMetaType>
#include <QtGui/QImage>

#include "GeoSceneDocument.h"
#include "GeoSceneHead.h"
#include "GeoSceneMap.h"
#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "MapThemeManager.h"
#include "MarbleDebug.h"
#include "MarbleDirs.h"
#include "TileLoaderHelper.h"

Q_DECLARE_METATYPE( Marble::DownloadUsage )

namespace Marble
{

TileLoader::TileLoader( HttpDownloadManager * const downloadManager, MapThemeManager const * mapThemeManager )
    : m_mapThemeManager( mapThemeManager )
{
    qRegisterMetaType<DownloadUsage>( "DownloadUsage" );
    connect( this, SIGNAL( downloadTile( QUrl, QString, QString, DownloadUsage )),
             downloadManager, SLOT( addJob( QUrl, QString, QString, DownloadUsage )));
    connect( downloadManager, SIGNAL( downloadComplete( QByteArray, QString )),
             SLOT( updateTile( QByteArray, QString )));
    connect( m_mapThemeManager, SIGNAL( themesChanged() ),
             this, SLOT( updateTextureLayers() ) );
    updateTextureLayers();
}

// If the tile is locally available:
//     - if not expired: create TextureTile, set state to "uptodate", return it => done
//     - if expired: create TextureTile, state is set to Expired by default, trigger dl,

QImage TileLoader::loadTile( TileId const & tileId, DownloadUsage const usage )
{
    GeoSceneTexture const * const textureLayer = findTextureLayer( tileId );
    QString const fileName = tileFileName( tileId );
    QImage const image( fileName );
    if ( !image.isNull() ) {
        // file is there, so create and return a tile object in any case,
        // but check if an update should be triggered

        const QDateTime lastModified = QFileInfo( fileName ).lastModified();
        const int expireSecs = textureLayer->expire();
        const bool isExpired = lastModified.secsTo( QDateTime::currentDateTime() ) >= expireSecs;

        if ( !isExpired ) {
            mDebug() << "TileLoader::loadTile" << tileId.toString() << "StateUptodate";
        } else {
            mDebug() << "TileLoader::loadTile" << tileId.toString() << "StateExpired";
            m_waitingForUpdate.insert( tileId );
            triggerDownload( tileId, usage );
        }

        return image;
    }

    // tile was not locally available => trigger download and look for tiles in other levels
    // for scaling
    QImage replacementTile = scaledLowerLevelTile( tileId );
    Q_ASSERT( !replacementTile.isNull() );

    m_waitingForUpdate.insert( tileId );
    triggerDownload( tileId, usage );

    return replacementTile;
}

// This method triggers a download of the given tile (without checking
// expiration). It is called by upper layer (StackedTileLoader) when the tile
// that should be reloaded is currently loaded in memory.
//
// post condition
//     - download is triggered, but only if not in progress (indicated by
//       m_waitingForUpdate)
void TileLoader::reloadTile( TileId const &tileId, DownloadUsage const usage )
{
    if ( m_waitingForUpdate.contains( tileId ) )
        return;
    m_waitingForUpdate.insert( tileId );
    triggerDownload( tileId, usage );
}

void TileLoader::downloadTile( TileId const & tileId )
{
    triggerDownload( tileId, DownloadBulk );
}

int TileLoader::maximumTileLevel( GeoSceneTexture const & texture )
{
    // if maximum tile level is configured in the DGML files,
    // then use it, otherwise use old detection code.
    if ( texture.maximumTileLevel() >= 0 ) {
        return texture.maximumTileLevel();
    }

    int maximumTileLevel = -1;
    QString tilepath = MarbleDirs::path( texture.themeStr() );
    //    mDebug() << "StackedTileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks
                                                        | QDir::NoDotAndDotDot );

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        bool ok = true;
        const int value = (*it).toInt( &ok, 10 );

        if ( ok && value > maximumTileLevel )
            maximumTileLevel = value;
    }

    //    mDebug() << "Detected maximum tile level that contains data: "
    //             << maxtilelevel;
    return maximumTileLevel + 1;
}

bool TileLoader::baseTilesAvailable( GeoSceneTexture const & texture )
{
    const int  levelZeroColumns = texture.levelZeroColumns();
    const int  levelZeroRows    = texture.levelZeroRows();

    bool result = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; result && column < levelZeroColumns; ++column ) {
        for ( int row = 0; result && row < levelZeroRows; ++row ) {

            const QString tilepath = MarbleDirs::path( texture.relativeTileFileName(
                TileId( texture.sourceDir(), 0, column, row )));
            result = QFile::exists( tilepath );
        }
    }

    return result;
}

void TileLoader::updateTile( QByteArray const & data, QString const & tileId )
{
    TileId const id = TileId::fromString( tileId );

    // preliminary fix for reload map crash
    // TODO: fix properly
    if ( !m_waitingForUpdate.contains( id ) )
        return;

    m_waitingForUpdate.remove( id );

    QImage const tileImage = QImage::fromData( data );
    if ( tileImage.isNull() )
        return;

    emit tileCompleted( id, tileImage );
}

void TileLoader::updateTextureLayers()
{
    m_textureLayers.clear();

    QHash<uint, GeoSceneLayer const *> sceneLayers;

    QList<GeoSceneDocument const *> const & mapThemes = m_mapThemeManager->mapThemes();
    QList<GeoSceneDocument const *>::const_iterator pos = mapThemes.constBegin();
    QList<GeoSceneDocument const *>::const_iterator const end = mapThemes.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneHead const * head = (*pos)->head();
        Q_ASSERT( head );
        const QString mapThemeId = head->target() + '/' + head->theme();
        mDebug() << "TileLoader::updateTextureLayers" << mapThemeId;

        GeoSceneMap const * map = (*pos)->map();
        Q_ASSERT( map );
        GeoSceneLayer const * sceneLayer = map->layer( head->theme() );
        if ( !sceneLayer ) {
            mDebug() << "ignoring, has no GeoSceneLayer for" << head->theme();
            continue;
        }

        uint const mapThemeIdHash = qHash( mapThemeId );
        if ( sceneLayers.contains( mapThemeIdHash ) ) {
            mDebug() << "TileLoader::updateTextureLayers:"
                     << mapThemeIdHash << mapThemeId
                     << "already exists";
            continue;
        }

        sceneLayers.insert( mapThemeIdHash, sceneLayer );

        // find all texture layers
        QVector<GeoSceneAbstractDataset *> layers = sceneLayer->datasets();
        QVector<GeoSceneAbstractDataset *>::const_iterator pos = layers.constBegin();
        QVector<GeoSceneAbstractDataset *>::const_iterator const end = layers.constEnd();
        for (; pos != end; ++pos ) {
            GeoSceneTexture const * const textureLayer = dynamic_cast<GeoSceneTexture *>( *pos );
            if ( !textureLayer ) {
                mDebug() << "ignoring dataset, is not a texture layer";
                continue;
            }
            m_textureLayers.insert( qHash( textureLayer->sourceDir() ), textureLayer );
            mDebug() << "TileLoader::updateTextureLayers" << "added texture layer:"
                     << qHash( textureLayer->sourceDir() ) << textureLayer->sourceDir();
        }
    }
}

inline GeoSceneTexture const * TileLoader::findTextureLayer( TileId const & id ) const
{
    GeoSceneTexture const * const textureLayer = m_textureLayers.value( id.mapThemeIdHash(), 0 );
    Q_ASSERT( textureLayer );
    return textureLayer;
}

QString TileLoader::tileFileName( TileId const & tileId ) const
{
    GeoSceneTexture const * const textureLayer = findTextureLayer( tileId );
    QString const fileName = textureLayer->relativeTileFileName( tileId );
    QFileInfo const dirInfo( fileName );
    return dirInfo.isAbsolute() ? fileName : MarbleDirs::path( fileName );
}

void TileLoader::triggerDownload( TileId const & id, DownloadUsage const usage )
{
    GeoSceneTexture const * const textureLayer = findTextureLayer( id );
    QUrl const sourceUrl = textureLayer->downloadUrl( id );
    QString const destFileName = textureLayer->relativeTileFileName( id );
    emit downloadTile( sourceUrl, destFileName, id.toString(), usage );
}

QImage TileLoader::scaledLowerLevelTile( TileId const & id )
{
    mDebug() << "TileLoader::scaledLowerLevelTile" << id.toString();

    for ( int level = qMax<int>( 0, id.zoomLevel() - 1 ); level >= 0; --level ) {
        int const deltaLevel = id.zoomLevel() - level;
        TileId const replacementTileId( id.mapThemeIdHash(), level,
                                        id.x() >> deltaLevel, id.y() >> deltaLevel );
        QString const fileName = tileFileName( replacementTileId );
        mDebug() << "TileLoader::scaledLowerLevelTile" << "trying" << fileName;
        QImage const toScale( fileName );

        if ( !toScale.isNull() ) {
            // which rect to scale?
            int const restTileX = id.x() % ( 1 << deltaLevel );
            int const restTileY = id.y() % ( 1 << deltaLevel );
            int const partWidth = toScale.width() >> deltaLevel;
            int const partHeight = toScale.height() >> deltaLevel;
            int const startX = restTileX * partWidth;
            int const startY = restTileY * partHeight;
            mDebug() << "QImage::copy:" << startX << startY << partWidth << partHeight;
            QImage const part = toScale.copy( startX, startY, partWidth, partHeight );
            mDebug() << "QImage::scaled:" << toScale.size();
            return part.scaled( toScale.size() );
        }
    }

    mDebug() << "No level zero tile installed in map theme dir. Falling back to a transparent image for now.";
    GeoSceneTexture const * const textureLayer = findTextureLayer( id );
    QSize const tileSize = textureLayer->tileSize();
    Q_ASSERT( !tileSize.isEmpty() ); // assured by textureLayer
    QImage fallbackImage = QImage( tileSize, QImage::Format_ARGB32_Premultiplied );
    fallbackImage.fill( qRgba( 0, 0, 0, 0 ) );

    return fallbackImage;
}

}

#include "TileLoader.moc"
<commit_msg>Revert accidently committed stuff: "simplify TileLoader::scaledLowerLevelTile()"<commit_after>// Copyright 2010 Jens-Michael Hoffmann <jmho@c-xx.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library. If not, see <http://www.gnu.org/licenses/>.

#include "TileLoader.h"

#include <QtCore/QDateTime>
#include <QtCore/QFileInfo>
#include <QtCore/QMetaType>
#include <QtGui/QImage>

#include "GeoSceneDocument.h"
#include "GeoSceneHead.h"
#include "GeoSceneMap.h"
#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "MapThemeManager.h"
#include "MarbleDebug.h"
#include "MarbleDirs.h"
#include "TileLoaderHelper.h"

Q_DECLARE_METATYPE( Marble::DownloadUsage )

namespace Marble
{

TileLoader::TileLoader( HttpDownloadManager * const downloadManager, MapThemeManager const * mapThemeManager )
    : m_mapThemeManager( mapThemeManager )
{
    qRegisterMetaType<DownloadUsage>( "DownloadUsage" );
    connect( this, SIGNAL( downloadTile( QUrl, QString, QString, DownloadUsage )),
             downloadManager, SLOT( addJob( QUrl, QString, QString, DownloadUsage )));
    connect( downloadManager, SIGNAL( downloadComplete( QByteArray, QString )),
             SLOT( updateTile( QByteArray, QString )));
    connect( m_mapThemeManager, SIGNAL( themesChanged() ),
             this, SLOT( updateTextureLayers() ) );
    updateTextureLayers();
}

// If the tile is locally available:
//     - if not expired: create TextureTile, set state to "uptodate", return it => done
//     - if expired: create TextureTile, state is set to Expired by default, trigger dl,

QImage TileLoader::loadTile( TileId const & tileId, DownloadUsage const usage )
{
    GeoSceneTexture const * const textureLayer = findTextureLayer( tileId );
    QString const fileName = tileFileName( tileId );
    QImage const image( fileName );
    if ( !image.isNull() ) {
        // file is there, so create and return a tile object in any case,
        // but check if an update should be triggered

        const QDateTime lastModified = QFileInfo( fileName ).lastModified();
        const int expireSecs = textureLayer->expire();
        const bool isExpired = lastModified.secsTo( QDateTime::currentDateTime() ) >= expireSecs;

        if ( !isExpired ) {
            mDebug() << "TileLoader::loadTile" << tileId.toString() << "StateUptodate";
        } else {
            mDebug() << "TileLoader::loadTile" << tileId.toString() << "StateExpired";
            m_waitingForUpdate.insert( tileId );
            triggerDownload( tileId, usage );
        }

        return image;
    }

    // tile was not locally available => trigger download and look for tiles in other levels
    // for scaling
    QImage replacementTile = scaledLowerLevelTile( tileId );
    Q_ASSERT( !replacementTile.isNull() );

    m_waitingForUpdate.insert( tileId );
    triggerDownload( tileId, usage );

    return replacementTile;
}

// This method triggers a download of the given tile (without checking
// expiration). It is called by upper layer (StackedTileLoader) when the tile
// that should be reloaded is currently loaded in memory.
//
// post condition
//     - download is triggered, but only if not in progress (indicated by
//       m_waitingForUpdate)
void TileLoader::reloadTile( TileId const &tileId, DownloadUsage const usage )
{
    if ( m_waitingForUpdate.contains( tileId ) )
        return;
    m_waitingForUpdate.insert( tileId );
    triggerDownload( tileId, usage );
}

void TileLoader::downloadTile( TileId const & tileId )
{
    triggerDownload( tileId, DownloadBulk );
}

int TileLoader::maximumTileLevel( GeoSceneTexture const & texture )
{
    // if maximum tile level is configured in the DGML files,
    // then use it, otherwise use old detection code.
    if ( texture.maximumTileLevel() >= 0 ) {
        return texture.maximumTileLevel();
    }

    int maximumTileLevel = -1;
    QString tilepath = MarbleDirs::path( texture.themeStr() );
    //    mDebug() << "StackedTileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks
                                                        | QDir::NoDotAndDotDot );

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        bool ok = true;
        const int value = (*it).toInt( &ok, 10 );

        if ( ok && value > maximumTileLevel )
            maximumTileLevel = value;
    }

    //    mDebug() << "Detected maximum tile level that contains data: "
    //             << maxtilelevel;
    return maximumTileLevel + 1;
}

bool TileLoader::baseTilesAvailable( GeoSceneTexture const & texture )
{
    const int  levelZeroColumns = texture.levelZeroColumns();
    const int  levelZeroRows    = texture.levelZeroRows();

    bool result = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; result && column < levelZeroColumns; ++column ) {
        for ( int row = 0; result && row < levelZeroRows; ++row ) {

            const QString tilepath = MarbleDirs::path( texture.relativeTileFileName(
                TileId( texture.sourceDir(), 0, column, row )));
            result = QFile::exists( tilepath );
        }
    }

    return result;
}

void TileLoader::updateTile( QByteArray const & data, QString const & tileId )
{
    TileId const id = TileId::fromString( tileId );

    // preliminary fix for reload map crash
    // TODO: fix properly
    if ( !m_waitingForUpdate.contains( id ) )
        return;

    m_waitingForUpdate.remove( id );

    QImage const tileImage = QImage::fromData( data );
    if ( tileImage.isNull() )
        return;

    emit tileCompleted( id, tileImage );
}

void TileLoader::updateTextureLayers()
{
    m_textureLayers.clear();

    QHash<uint, GeoSceneLayer const *> sceneLayers;

    QList<GeoSceneDocument const *> const & mapThemes = m_mapThemeManager->mapThemes();
    QList<GeoSceneDocument const *>::const_iterator pos = mapThemes.constBegin();
    QList<GeoSceneDocument const *>::const_iterator const end = mapThemes.constEnd();
    for (; pos != end; ++pos ) {
        GeoSceneHead const * head = (*pos)->head();
        Q_ASSERT( head );
        const QString mapThemeId = head->target() + '/' + head->theme();
        mDebug() << "TileLoader::updateTextureLayers" << mapThemeId;

        GeoSceneMap const * map = (*pos)->map();
        Q_ASSERT( map );
        GeoSceneLayer const * sceneLayer = map->layer( head->theme() );
        if ( !sceneLayer ) {
            mDebug() << "ignoring, has no GeoSceneLayer for" << head->theme();
            continue;
        }

        uint const mapThemeIdHash = qHash( mapThemeId );
        if ( sceneLayers.contains( mapThemeIdHash ) ) {
            mDebug() << "TileLoader::updateTextureLayers:"
                     << mapThemeIdHash << mapThemeId
                     << "already exists";
            continue;
        }

        sceneLayers.insert( mapThemeIdHash, sceneLayer );

        // find all texture layers
        QVector<GeoSceneAbstractDataset *> layers = sceneLayer->datasets();
        QVector<GeoSceneAbstractDataset *>::const_iterator pos = layers.constBegin();
        QVector<GeoSceneAbstractDataset *>::const_iterator const end = layers.constEnd();
        for (; pos != end; ++pos ) {
            GeoSceneTexture const * const textureLayer = dynamic_cast<GeoSceneTexture *>( *pos );
            if ( !textureLayer ) {
                mDebug() << "ignoring dataset, is not a texture layer";
                continue;
            }
            m_textureLayers.insert( qHash( textureLayer->sourceDir() ), textureLayer );
            mDebug() << "TileLoader::updateTextureLayers" << "added texture layer:"
                     << qHash( textureLayer->sourceDir() ) << textureLayer->sourceDir();
        }
    }
}

inline GeoSceneTexture const * TileLoader::findTextureLayer( TileId const & id ) const
{
    GeoSceneTexture const * const textureLayer = m_textureLayers.value( id.mapThemeIdHash(), 0 );
    Q_ASSERT( textureLayer );
    return textureLayer;
}

QString TileLoader::tileFileName( TileId const & tileId ) const
{
    GeoSceneTexture const * const textureLayer = findTextureLayer( tileId );
    QString const fileName = textureLayer->relativeTileFileName( tileId );
    QFileInfo const dirInfo( fileName );
    return dirInfo.isAbsolute() ? fileName : MarbleDirs::path( fileName );
}

void TileLoader::triggerDownload( TileId const & id, DownloadUsage const usage )
{
    GeoSceneTexture const * const textureLayer = findTextureLayer( id );
    QUrl const sourceUrl = textureLayer->downloadUrl( id );
    QString const destFileName = textureLayer->relativeTileFileName( id );
    emit downloadTile( sourceUrl, destFileName, id.toString(), usage );
}

QImage TileLoader::scaledLowerLevelTile( TileId const & id )
{
    mDebug() << "TileLoader::scaledLowerLevelTile" << id.toString();

    for ( int level = qMax<int>( 0, id.zoomLevel() - 1 ); level >= 0; --level ) {
        int const deltaLevel = id.zoomLevel() - level;
        TileId const replacementTileId( id.mapThemeIdHash(), level,
                                        id.x() >> deltaLevel, id.y() >> deltaLevel );
        QString const fileName = tileFileName( replacementTileId );
        mDebug() << "TileLoader::scaledLowerLevelTile" << "trying" << fileName;
        QImage toScale( fileName );

        if ( level == 0 && toScale.isNull() ) {
            mDebug() << "No level zero tile installed in map theme dir. Falling back to a transparent image for now.";
            GeoSceneTexture const * const textureLayer = findTextureLayer( replacementTileId );
            QSize tileSize = textureLayer->tileSize();
            Q_ASSERT( !tileSize.isEmpty() ); // assured by textureLayer
            toScale = QImage( tileSize, QImage::Format_ARGB32_Premultiplied );
            toScale.fill( qRgba( 0, 0, 0, 0 ) );
        }

        if ( !toScale.isNull() ) {
            // which rect to scale?
            int const restTileX = id.x() % ( 1 << deltaLevel );
            int const restTileY = id.y() % ( 1 << deltaLevel );
            int const partWidth = toScale.width() >> deltaLevel;
            int const partHeight = toScale.height() >> deltaLevel;
            int const startX = restTileX * partWidth;
            int const startY = restTileY * partHeight;
            mDebug() << "QImage::copy:" << startX << startY << partWidth << partHeight;
            QImage const part = toScale.copy( startX, startY, partWidth, partHeight );
            mDebug() << "QImage::scaled:" << toScale.size();
            return part.scaled( toScale.size() );
        }
    }

    Q_ASSERT_X( false, "scaled image", "level zero image missing" ); // not reached
    return QImage();
}

}

#include "TileLoader.moc"
<|endoftext|>


<commit_before>/**
  *  @copyright Copyright (c) 2014, J-PET collaboration
  *  @file JPetCmdParserTest.cpp
  *  @author Wojciech Krzemien, wojciech.krzemien@if.uj.edu.pl
  */
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE JPetCmdParserTest
#include <boost/test/unit_test.hpp>
#include <cstdlib>
#define private public
#define protected public
#include "../../JPetCmdParser/JPetCmdParser.h"

//public method
//std::vector<JPetOptions> parseAndGenerateOptions(int argc, const char** argv);

using namespace std;

char* convertStringToCharP(const std::string& s)
{
  char* pc = new char[s.size() + 1];
  std::strcpy(pc, s.c_str());
  return pc;
}

std::vector<char*> createArgs(const std::string& commandLine)
{
  std::istringstream iss(commandLine);
  std::vector<std::string> args {std::istream_iterator<std::string>{iss},
                                 std::istream_iterator<std::string>{}
                                };
  std::vector<char*> args_char;
  std::transform(args.begin(), args.end(), std::back_inserter(args_char), convertStringToCharP);
  return args_char;
}

BOOST_AUTO_TEST_SUITE(FirstSuite)

BOOST_AUTO_TEST_CASE( parsing_1 )
{
  auto commandLine = "main.x -t hld -f testfile.hld -i 10";
  auto args_char = createArgs(commandLine);
  auto argc = args_char.size();
  auto argv = args_char.data();

  JPetCmdParser parser;
  auto options = parser.parseAndGenerateOptions(argc, const_cast<const char**>(argv));
  BOOST_REQUIRE_EQUAL(options.size(), 1);
  auto option = options.at(0);
  BOOST_REQUIRE(std::string(option.getInputFile()) == "testfile.hld");
  BOOST_REQUIRE_EQUAL(option.getFirstEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getLastEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getRunNumber(), 10);
  BOOST_REQUIRE(!option.isProgressBar());
  BOOST_REQUIRE_EQUAL(option.getInputFileType(), JPetOptions::kHld);
}

BOOST_AUTO_TEST_CASE( parsing_2 )
{
  auto commandLine = "main.x -t scope -f testfile.json ";
  auto args_char = createArgs(commandLine);
  auto argc = args_char.size();
  auto argv = args_char.data();

  JPetCmdParser parser;
  auto options = parser.parseAndGenerateOptions(argc, const_cast<const char**>(argv));
  BOOST_REQUIRE_EQUAL(options.size(), 1);
  auto option = options.at(0);
  BOOST_REQUIRE(std::string(option.getInputFile()) == "testfile.json");
  BOOST_REQUIRE_EQUAL(option.getFirstEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getLastEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getRunNumber(), -1);
  BOOST_REQUIRE(!option.isProgressBar());
  BOOST_REQUIRE_EQUAL(option.getInputFileType(), JPetOptions::kScope);
}
/*
  ("help,h", "produce help message")
  ("type,t", po::value<std::string>()->required(), "type of file: hld, root or scope")
  ("file,f", po::value< std::vector<std::string> >()->required()->multitoken(), "File(s) to open")
  ("range,r", po::value< std::vector<int> >()->multitoken()->default_value(tmp, ""), "Range of events to process.")
  ("param,p", po::value<std::string>(), "File with TRB numbers.")
  ("runId,i", po::value<int>(), "Run id.")
  ("progressBar,b", "Progress bar.");
*/
BOOST_AUTO_TEST_CASE(getOptionsDescriptionTest)
{
    JPetCmdParser cmdParser;
    auto optionDescription = cmdParser.getOptionsDescription();
    //optionDescription.add
    //optionDescription.find()
    cout << "andrzej" << endl;
    auto helpOptionDescription = optionDescription.find("help", true);
    //cout << helpOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(helpOptionDescription.description()) == "produce help message");
    //cout << helpOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(helpOptionDescription.format_name()) == "-h [ --help ]");

    auto typeOptionDescription = optionDescription.find("type", true);
    //cout << typeOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(typeOptionDescription.description()) == "type of file: hld, root or scope");
    //cout << typeOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(typeOptionDescription.format_name()) == "-t [ --type ]");

    auto fileOptionDescription = optionDescription.find("file", true);
    //cout << fileOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(fileOptionDescription.description()) == "File(s) to open");
    //cout << fileOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(fileOptionDescription.format_name()) == "-f [ --file ]");

    auto rangeOptionDescription = optionDescription.find("range", true);
    //cout << rangeOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(rangeOptionDescription.description()) == "Range of events to process.");
    //cout << rangeOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(rangeOptionDescription.format_name()) == "-r [ --range ]");

    auto paramOptionDescription = optionDescription.find("param", true);
    //cout << paramOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(paramOptionDescription.description()) == "File with TRB numbers.");
    //cout << paramOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(paramOptionDescription.format_name()) == "-p [ --param ]");

    auto runIdOptionDescription = optionDescription.find("runId", true);
    //cout << runIdOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(runIdOptionDescription.description()) == "Run id.");
    //cout << runIdOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(runIdOptionDescription.format_name()) == "-i [ --runId ]");

    auto progressBarOptionDescription = optionDescription.find("progressBar", true);
    //cout << progressBarOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(progressBarOptionDescription.description()) == "Progress bar.");
    //cout << progressBarOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(progressBarOptionDescription.format_name()) == "-b [ --progressBar ]");
}

BOOST_AUTO_TEST_CASE(fileTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -f data.hld";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("file,f", po::value<std::vector<std::string>>(), "File(s) to open")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    auto fileNames = cmdParser.getFileNames(variablesMap);
    BOOST_REQUIRE(fileNames.size() == 1);
    BOOST_REQUIRE(fileNames.front() == "data.hld");

    auto file = variablesMap["file"].as<std::vector<std::string>>();
    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("file") == 1);
    BOOST_REQUIRE(file.front() == "data.hld");
}

BOOST_AUTO_TEST_CASE(fileTypeTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -t hld";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("type,t", po::value<std::string>(), "type of file: hld, root or scope")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    auto fileType = variablesMap["type"].as<std::string>();

    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("type") > 0);
    BOOST_REQUIRE(fileType == "hld");
    BOOST_REQUIRE(cmdParser.isCorrectFileType(fileType));
    BOOST_REQUIRE(cmdParser.getFileType(variablesMap) == "hld");
    BOOST_REQUIRE(cmdParser.IsFileTypeSet(variablesMap));
}

BOOST_AUTO_TEST_CASE(rangeTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -r 4";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("range,r", po::value<std::vector<int>>(), "Range of events to process.")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    BOOST_REQUIRE(cmdParser.getLowerEventBound(variablesMap) == 4);

    auto range = variablesMap["range"].as<std::vector<int>>();
    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("range") == 1);
    BOOST_REQUIRE(range.front() == 4);
}
/* To remove */
BOOST_AUTO_TEST_CASE(dummyTest)
{
    JPetCmdParser cmdParser;
    po::variables_map variablesMap;
    //variablesMap.insert()
    //BOOST_REQUIRE(!cmdParser.IsFileTypeSet(variablesMap));
    //cmdParser.generateOptions(variablesMap);
    //BOOST_REQUIRE(cmdParser.areCorrectOptions(variablesMap));

    // Declare the supported options.

    auto commandLine = "main.x -h help -c 10";
    auto args_char = createArgs(commandLine);
    auto ac = args_char.size();
    auto av = args_char.data();

    po::options_description desc("Allowed options");
    desc.add_options()
            ("help,h", "produce help message")
            ("compression,c", po::value<int>(), "set compression level")
    ;

    po::variables_map vm;
    po::store(po::parse_command_line(ac, av, desc), vm);
    po::notify(vm);

    if (vm.count("help")) {
        cout << desc << "\n";
    }

    if (vm.count("compression")) {
        cout << "Compression level was set to "
     << vm["compression"].as<int>() << ".\n";
    } else {
        cout << "Compression level was not set.\n";
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Add unit tests for JPetCmdParser.<commit_after>/**
  *  @copyright Copyright (c) 2014, J-PET collaboration
  *  @file JPetCmdParserTest.cpp
  *  @author Wojciech Krzemien, wojciech.krzemien@if.uj.edu.pl
  */
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE JPetCmdParserTest
#include <boost/test/unit_test.hpp>
#include <cstdlib>
#define private public
#define protected public
#include "../../JPetCmdParser/JPetCmdParser.h"

//public method
//std::vector<JPetOptions> parseAndGenerateOptions(int argc, const char** argv);

using namespace std;

char* convertStringToCharP(const std::string& s)
{
  char* pc = new char[s.size() + 1];
  std::strcpy(pc, s.c_str());
  return pc;
}

std::vector<char*> createArgs(const std::string& commandLine)
{
  std::istringstream iss(commandLine);
  std::vector<std::string> args {std::istream_iterator<std::string>{iss},
                                 std::istream_iterator<std::string>{}
                                };
  std::vector<char*> args_char;
  std::transform(args.begin(), args.end(), std::back_inserter(args_char), convertStringToCharP);
  return args_char;
}

BOOST_AUTO_TEST_SUITE(FirstSuite)

BOOST_AUTO_TEST_CASE( parsing_1 )
{
  auto commandLine = "main.x -t hld -f testfile.hld -i 10";
  auto args_char = createArgs(commandLine);
  auto argc = args_char.size();
  auto argv = args_char.data();

  JPetCmdParser parser;
  auto options = parser.parseAndGenerateOptions(argc, const_cast<const char**>(argv));
  BOOST_REQUIRE_EQUAL(options.size(), 1);
  auto option = options.at(0);
  BOOST_REQUIRE(std::string(option.getInputFile()) == "testfile.hld");
  BOOST_REQUIRE_EQUAL(option.getFirstEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getLastEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getRunNumber(), 10);
  BOOST_REQUIRE(!option.isProgressBar());
  BOOST_REQUIRE_EQUAL(option.getInputFileType(), JPetOptions::kHld);
}

BOOST_AUTO_TEST_CASE( parsing_2 )
{
  auto commandLine = "main.x -t scope -f testfile.json ";
  auto args_char = createArgs(commandLine);
  auto argc = args_char.size();
  auto argv = args_char.data();

  JPetCmdParser parser;
  auto options = parser.parseAndGenerateOptions(argc, const_cast<const char**>(argv));
  BOOST_REQUIRE_EQUAL(options.size(), 1);
  auto option = options.at(0);
  BOOST_REQUIRE(std::string(option.getInputFile()) == "testfile.json");
  BOOST_REQUIRE_EQUAL(option.getFirstEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getLastEvent(), -1);
  BOOST_REQUIRE_EQUAL(option.getRunNumber(), -1);
  BOOST_REQUIRE(!option.isProgressBar());
  BOOST_REQUIRE_EQUAL(option.getInputFileType(), JPetOptions::kScope);
}
/*
  ("help,h", "produce help message")
  ("type,t", po::value<std::string>()->required(), "type of file: hld, root or scope")
  ("file,f", po::value< std::vector<std::string> >()->required()->multitoken(), "File(s) to open")
  ("range,r", po::value< std::vector<int> >()->multitoken()->default_value(tmp, ""), "Range of events to process.")
  ("param,p", po::value<std::string>(), "File with TRB numbers.")
  ("runId,i", po::value<int>(), "Run id.")
  ("progressBar,b", "Progress bar.");
*/
BOOST_AUTO_TEST_CASE(getOptionsDescriptionTest)
{
    JPetCmdParser cmdParser;
    auto optionDescription = cmdParser.getOptionsDescription();
    //optionDescription.add
    //optionDescription.find()
    cout << "andrzej" << endl;
    auto helpOptionDescription = optionDescription.find("help", true);
    //cout << helpOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(helpOptionDescription.description()) == "produce help message");
    //cout << helpOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(helpOptionDescription.format_name()) == "-h [ --help ]");

    auto typeOptionDescription = optionDescription.find("type", true);
    //cout << typeOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(typeOptionDescription.description()) == "type of file: hld, root or scope");
    //cout << typeOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(typeOptionDescription.format_name()) == "-t [ --type ]");

    auto fileOptionDescription = optionDescription.find("file", true);
    //cout << fileOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(fileOptionDescription.description()) == "File(s) to open");
    //cout << fileOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(fileOptionDescription.format_name()) == "-f [ --file ]");

    auto rangeOptionDescription = optionDescription.find("range", true);
    //cout << rangeOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(rangeOptionDescription.description()) == "Range of events to process.");
    //cout << rangeOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(rangeOptionDescription.format_name()) == "-r [ --range ]");

    auto paramOptionDescription = optionDescription.find("param", true);
    //cout << paramOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(paramOptionDescription.description()) == "File with TRB numbers.");
    //cout << paramOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(paramOptionDescription.format_name()) == "-p [ --param ]");

    auto runIdOptionDescription = optionDescription.find("runId", true);
    //cout << runIdOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(runIdOptionDescription.description()) == "Run id.");
    //cout << runIdOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(runIdOptionDescription.format_name()) == "-i [ --runId ]");

    auto progressBarOptionDescription = optionDescription.find("progressBar", true);
    //cout << progressBarOptionDescription.description() << endl;
    BOOST_REQUIRE(std::string(progressBarOptionDescription.description()) == "Progress bar.");
    //cout << progressBarOptionDescription.format_name() << endl;
    BOOST_REQUIRE(std::string(progressBarOptionDescription.format_name()) == "-b [ --progressBar ]");
}

BOOST_AUTO_TEST_CASE(fileTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -f data.hld";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("file,f", po::value<std::vector<std::string>>(), "File(s) to open")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    auto fileNames = cmdParser.getFileNames(variablesMap);
    BOOST_REQUIRE(fileNames.size() == 1);
    BOOST_REQUIRE(fileNames.front() == "data.hld");

    auto file = variablesMap["file"].as<std::vector<std::string>>();
    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("file") == 1);
    BOOST_REQUIRE(file.front() == "data.hld");
}

BOOST_AUTO_TEST_CASE(fileTypeTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -t hld";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("type,t", po::value<std::string>(), "type of file: hld, root or scope")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    auto fileType = variablesMap["type"].as<std::string>();

    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("type") > 0);
    BOOST_REQUIRE(fileType == "hld");
    BOOST_REQUIRE(cmdParser.isCorrectFileType(fileType));
    BOOST_REQUIRE(cmdParser.getFileType(variablesMap) == "hld");
    BOOST_REQUIRE(cmdParser.IsFileTypeSet(variablesMap));
}

BOOST_AUTO_TEST_CASE(rangeTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -r 4";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("range,r", po::value<std::vector<int>>(), "Range of events to process.")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    BOOST_REQUIRE(cmdParser.getLowerEventBound(variablesMap) == 4);

    auto range = variablesMap["range"].as<std::vector<int>>();
    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("range") == 1);
    BOOST_REQUIRE(range.front() == 4);
}

BOOST_AUTO_TEST_CASE(paramTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -p data.hld";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("param,p", po::value<std::string>(), "File with TRB numbers.")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    BOOST_REQUIRE(cmdParser.isParamSet(variablesMap) == true);
    BOOST_REQUIRE(cmdParser.getParam(variablesMap) == "data.hld");

    auto param = variablesMap["param"].as<std::string>();
    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("param") == 1);
    BOOST_REQUIRE(param == "data.hld");
}

BOOST_AUTO_TEST_CASE(runIdTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -i 231";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("runId,i", po::value<int>(), "Run id.")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    BOOST_REQUIRE(cmdParser.isRunNumberSet(variablesMap) == true);
    BOOST_REQUIRE(cmdParser.getRunNumber(variablesMap) == 231);

    auto runId = variablesMap["runId"].as<int>();
    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("runId") == 1);
    BOOST_REQUIRE(runId == 231);
}

BOOST_AUTO_TEST_CASE(progressBarTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -b 1";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("progressBar,b", po::value<int>(), "Progress bar.")
    ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    BOOST_REQUIRE(cmdParser.isProgressBarSet(variablesMap) == true);
    BOOST_REQUIRE(variablesMap.size() == 1);
    BOOST_REQUIRE(variablesMap.count("progressBar") == 1);
}

BOOST_AUTO_TEST_CASE(generateOptionsTest)
{
    JPetCmdParser cmdParser;

    auto commandLine = "main.x -f data.hld -t hld -r 4 -p data.hld -i 231 -b 1";
    auto args_char = createArgs(commandLine);
    auto argc = args_char.size();
    auto argv = args_char.data();

    po::options_description description("Allowed options");
    description.add_options()
            ("file,f", po::value<std::vector<std::string>>(), "File(s) to open")
            ("type,t", po::value<std::string>(), "type of file: hld, root or scope")
            ("range,r", po::value<std::vector<int>>(), "Range of events to process.")
            ("param,p", po::value<std::string>(), "File with TRB numbers.")
            ("runId,i", po::value<int>(), "Run id.")
            ("progressBar,b", po::value<int>(), "Progress bar.")
            ;

    po::variables_map variablesMap;
    po::store(po::parse_command_line(argc, argv, description), variablesMap);
    po::notify(variablesMap);

    auto options = cmdParser.generateOptions(variablesMap);
    auto firstOption = options.front();

    BOOST_REQUIRE(firstOption.getRunNumber() == 231);
    BOOST_REQUIRE(firstOption.isProgressBar() == true);
}

/* To remove */
BOOST_AUTO_TEST_CASE(dummyTest)
{
    JPetCmdParser cmdParser;
    po::variables_map variablesMap;
    //variablesMap.insert()
    //BOOST_REQUIRE(!cmdParser.IsFileTypeSet(variablesMap));
    //cmdParser.generateOptions(variablesMap);
    //BOOST_REQUIRE(cmdParser.areCorrectOptions(variablesMap));

    // Declare the supported options.

    auto commandLine = "main.x -h help -c 10";
    auto args_char = createArgs(commandLine);
    auto ac = args_char.size();
    auto av = args_char.data();

    po::options_description desc("Allowed options");
    desc.add_options()
            ("help,h", "produce help message")
            ("compression,c", po::value<int>(), "set compression level")
    ;

    po::variables_map vm;
    po::store(po::parse_command_line(ac, av, desc), vm);
    po::notify(vm);

    if (vm.count("help")) {
        cout << desc << "\n";
    }

    if (vm.count("compression")) {
        cout << "Compression level was set to "
     << vm["compression"].as<int>() << ".\n";
    } else {
        cout << "Compression level was not set.\n";
    }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "distance.h"
using namespace std;
namespace word2vecdistance
{

  distance::distance(string filename)
  {
    strcpy(file_name, filename.c_str());
    f = fopen(file_name, "rb");
    if (f == NULL) {
      printf("Input file not found\n");
      exit(-1);
    }
    fscanf(f, "%lld", &words);
    fscanf(f, "%lld", &size);
    vocab = (char *)malloc((long long)words * max_w * sizeof(char));
    for (a = 0; a < N; a++) bestw[a] = (char *)malloc(max_size * sizeof(char));
    M = (float *)malloc((long long)words * (long long)size * sizeof(float));
    if (M == NULL) {
      printf("Cannot allocate memory: %lld MB    %lld  %lld\n", (long long)words * size * sizeof(float) / 1048576, words, size);
      exit(-1);
    }
//     printf("Allocation of memory: %lld MB    %lld  %lld\n", (long long)words * size * sizeof(float) / 1048576, words, size);
    for (b = 0; b < words; b++) {
      a = 0;
      while (1) {
	vocab[b * max_w + a] = fgetc(f);
	if (feof(f) || (vocab[b * max_w + a] == ' ')) break;
	if ((a < max_w) && (vocab[b * max_w + a] != '\n')) a++;
      }
      vocab[b * max_w + a] = 0;
      for (a = 0; a < size; a++) fread(&M[a + b * size], sizeof(float), 1, f);
      len = 0;
      for (a = 0; a < size; a++) len += M[a + b * size] * M[a + b * size];
      len = sqrt(len);
      for (a = 0; a < size; a++) M[a + b * size] /= len;
    }
    fclose(f);
  }

  vector< pair< string, float > > distance::recherche(string s)
  {
    vector< pair< string, float > > to_return;
    float vec[max_size];
    for (a = 0; a < N; a++) bestd[a] = 0;
    for (a = 0; a < N; a++) bestw[a][0] = 0;
//     printf("Enter word or sentence (EXIT to break): ");
    a = 0;
//     while (1) {
//       st1[a] = fgetc(stdin);
//       if ((st1[a] == '\n') || (a >= max_size - 1)) {
//         st1[a] = 0;
//         break;
//       }
//       a++;
//     }
    char st1[max_size];
    strcpy(st1, s.c_str());
//     st1 = s.c_str();
//     if (!strcmp(st1, "EXIT")) break;
    cn = 0;
    b = 0;
    c = 0;
    while (1) {
      st[cn][b] = st1[c];
      b++;
      c++;
      st[cn][b] = 0;
      if (st1[c] == 0) break;
      if (st1[c] == ' ') {
        cn++;
        b = 0;
        c++;
      }
    }
    cn++;
    for (a = 0; a < cn; a++) {
      for (b = 0; b < words; b++) if (!strcmp(&vocab[b * max_w], st[a])) break;
      if (b == words) b = -1;
      bi[a] = b;
//       printf("\nWord: %s  Position in vocabulary: %lld\n", st[a], bi[a]);
      if (b == -1) {
	printf("%s: Out of dictionary word!\n",st[a]);
        return to_return;
      }
    }
    if (b == -1) return to_return;
//     printf("\n                                              Word       Cosine distance\n------------------------------------------------------------------------\n");
    for (a = 0; a < size; a++) vec[a] = 0;
    for (b = 0; b < cn; b++) {
      if (bi[b] == -1) continue;
      for (a = 0; a < size; a++) vec[a] += M[a + bi[b] * size];
    }
    len = 0;
    for (a = 0; a < size; a++) len += vec[a] * vec[a];
    len = sqrt(len);
    for (a = 0; a < size; a++) vec[a] /= len;
    for (a = 0; a < N; a++) bestd[a] = -1;
    for (a = 0; a < N; a++) bestw[a][0] = 0;
    for (c = 0; c < words; c++) {
      a = 0;
      for (b = 0; b < cn; b++) if (bi[b] == c) a = 1;
      if (a == 1) continue;
      dist = 0;
      for (a = 0; a < size; a++) dist += vec[a] * M[a + c * size];
      for (a = 0; a < N; a++) {
        if (dist > bestd[a]) {
          for (d = N - 1; d > a; d--) {
            bestd[d] = bestd[d - 1];
            strcpy(bestw[d], bestw[d - 1]);
          }
          bestd[a] = dist;
          strcpy(bestw[a], &vocab[c * max_w]);
          break;
        }
      }
    }

//       for (a = 0; a < N && a < 10 ; a++)
// 	printf("%50s\t\t%f\n", bestw[a], bestd[a]);
    for (a = 0; a < N; a++)
    {
      pair<string,float> l_p( string(bestw[a]), bestd[a]);
//       printf("%50s\t\t%f\n", bestw[a], bestd[a]);
      to_return.push_back(l_p);
    }
    return to_return;
  }
  float distance::getDistance(string s1, string s2)
  {
    float vec1[max_size];
    float vec2[max_size];
  //     vector< pair< string, float > > to_return;
      for (a = 0; a < N; a++) bestd[a] = 0;
      for (a = 0; a < N; a++) bestw[a][0] = 0;
//       printf("Enter word or sentence (EXIT to break): ");
      a = 0;
      char st1[max_size];
      char st2[max_size];
      strcpy(st1, s1.c_str());
      strcpy(st2, s2.c_str());
      cn = 0;
      b = 0;
      c = 0;
      int pos1, pos2;
      // supression des espaces
      while (1) {
	st[cn][b] = st1[c];
	b++;
	c++;
	st[cn][b] = 0;
	if (st1[c] == 0) break;
	if (st1[c] == ' ') {
	  cn++;
	  b = 0;
	  c++;
	}
      }
      cn++;
      // supression des espaces
      for (a = 0; a < cn; a++) {
	for (b = 0; b < words; b++) if (!strcmp(&vocab[b * max_w], st[a])) break;
	if (b == words) b = -1;
	bi[a] = b;
// 	printf("\nWord: %s  Position in vocabulary: %lld\n", st[a], bi[a]);
	pos1=bi[a];
	if (b == -1) {
	  printf("%s: Out of dictionary word!\n",st[a]);
	  return 0.0;
	}
      }
      // Verification de la présence dans le vocab
      cn = 0;
      b = 0;
      c = 0;
      // supression des espaces
      while (1) {
	st[cn][b] = st2[c];
	b++;
	c++;
	st[cn][b] = 0;
	if (st2[c] == 0) break;
	if (st2[c] == ' ') {
	  cn++;
	  b = 0;
	  c++;
	}
      }
      cn++;
      for (a = 0; a < cn; a++) {
//       cerr << a << " " << cn << endl;
	for (b = 0; b < words; b++) if (!strcmp(&vocab[b * max_w], st[a])) break;
	if (b == words) b = -1;
	bi[a] = b;
	pos2=bi[a];
// 	printf("\nWord: %s  Position in vocabulary: %lld\n", st[a], bi[a]);
	if (b == -1) {
	  printf("%s: Out of dictionary word!\n",st[a]);
	  return 0.0;
	}
      }

      if (b == -1) return 0.0;
  //     printf("\n                                              Word       Cosine distance\n------------------------------------------------------------------------\n");
      for (a = 0; a < size; a++) vec1[a] = 0;
      for (b = 0; b < cn; b++) {
	if (pos1 == -1) continue;
	for (a = 0; a < size; a++) vec1[a] += M[a + pos1 * size];
      }
      len = 0;
      for (a = 0; a < size; a++) len += vec1[a] * vec1[a];
      len = sqrt(len);
      for (a = 0; a < size; a++) vec1[a] /= len;

      for (a = 0; a < size; a++) vec2[a] = 0;
      for (b = 0; b < cn; b++) {
	if (pos2 == -1) continue;
	for (a = 0; a < size; a++) vec2[a] += M[a + pos2 * size];
      }
      len = 0;
      for (a = 0; a < size; a++) len += vec2[a] * vec2[a];
      len = sqrt(len);
      for (a = 0; a < size; a++) vec2[a] /= len;
      dist = 0;
      for (a = 0; a < size; a++) dist += vec1[a] * vec2[a];
      return dist;

//       for (a = 0; a < N; a++) bestd[a] = -1;
//       for (a = 0; a < N; a++) bestw[a][0] = 0;
//       for (c = 0; c < words; c++) {
// 	a = 0;
// 	for (b = 0; b < cn; b++) if (bi[b] == c) a = 1;
// 	if (a == 1) continue;
// 	dist = 0;
// 	for (a = 0; a < size; a++) dist += vec[a] * M[a + c * size];
// 	for (a = 0; a < N; a++) {
// 	  if (dist > bestd[a]) {
// 	    for (d = N - 1; d > a; d--) {
// 	      bestd[d] = bestd[d - 1];
// 	      strcpy(bestw[d], bestw[d - 1]);
// 	    }
// 	    bestd[a] = dist;
//
// 	    strcpy(bestw[a], &vocab[c * max_w]);
// 	    break;
// 	  }
// 	}
//       }
//       for (a = 0; a < N && a < 2 ; a++)
//       {
// 	pair<string,float> l_p( string(bestw[a]), bestd[a]);
// 	printf("%50s\t\t%f\n", bestw[a], bestd[a]);
//       }
//       return 1.0;
  }
}<commit_msg>New deep TER<commit_after>#include "distance.h"
using namespace std;
namespace word2vecdistance
{

  distance::distance(string filename)
  {
    strcpy(file_name, filename.c_str());
    f = fopen(file_name, "rb");
    if (f == NULL) {
      printf("Input file not found\n");
      exit(-1);
    }
    fscanf(f, "%lld", &words);
    fscanf(f, "%lld", &size);
    vocab = (char *)malloc((long long)words * max_w * sizeof(char));
    for (a = 0; a < N; a++) bestw[a] = (char *)malloc(max_size * sizeof(char));
    M = (float *)malloc((long long)words * (long long)size * sizeof(float));
    if (M == NULL) {
      printf("Cannot allocate memory: %lld MB    %lld  %lld\n", (long long)words * size * sizeof(float) / 1048576, words, size);
      exit(-1);
    }
//     printf("Allocation of memory: %lld MB    %lld  %lld\n", (long long)words * size * sizeof(float) / 1048576, words, size);
    for (b = 0; b < words; b++) {
      a = 0;
      while (1) {
	vocab[b * max_w + a] = fgetc(f);
	if (feof(f) || (vocab[b * max_w + a] == ' ')) break;
	if ((a < max_w) && (vocab[b * max_w + a] != '\n')) a++;
      }
      vocab[b * max_w + a] = 0;
      for (a = 0; a < size; a++) fread(&M[a + b * size], sizeof(float), 1, f);
      len = 0;
      for (a = 0; a < size; a++) len += M[a + b * size] * M[a + b * size];
      len = sqrt(len);
      for (a = 0; a < size; a++) M[a + b * size] /= len;
    }
    fclose(f);
  }

  vector< pair< string, float > > distance::recherche(string s)
  {
    vector< pair< string, float > > to_return;
    float vec[max_size];
    for (a = 0; a < N; a++) bestd[a] = 0;
    for (a = 0; a < N; a++) bestw[a][0] = 0;
//     printf("Enter word or sentence (EXIT to break): ");
    a = 0;
//     while (1) {
//       st1[a] = fgetc(stdin);
//       if ((st1[a] == '\n') || (a >= max_size - 1)) {
//         st1[a] = 0;
//         break;
//       }
//       a++;
//     }
    char st1[max_size];
    strcpy(st1, s.c_str());
//     st1 = s.c_str();
//     if (!strcmp(st1, "EXIT")) break;
    cn = 0;
    b = 0;
    c = 0;
    while (1) {
      st[cn][b] = st1[c];
      b++;
      c++;
      st[cn][b] = 0;
      if (st1[c] == 0) break;
      if (st1[c] == ' ') {
        cn++;
        b = 0;
        c++;
      }
    }
    cn++;
    for (a = 0; a < cn; a++) {
      for (b = 0; b < words; b++) if (!strcmp(&vocab[b * max_w], st[a])) break;
      if (b == words) b = -1;
      bi[a] = b;
//       printf("\nWord: %s  Position in vocabulary: %lld\n", st[a], bi[a]);
      if (b == -1) {
// 	printf("%s: Out of dictionary word!\n",st[a]);
        return to_return;
      }
    }
    if (b == -1) return to_return;
//     printf("\n                                              Word       Cosine distance\n------------------------------------------------------------------------\n");
    for (a = 0; a < size; a++) vec[a] = 0;
    for (b = 0; b < cn; b++) {
      if (bi[b] == -1) continue;
      for (a = 0; a < size; a++) vec[a] += M[a + bi[b] * size];
    }
    len = 0;
    for (a = 0; a < size; a++) len += vec[a] * vec[a];
    len = sqrt(len);
    for (a = 0; a < size; a++) vec[a] /= len;
    for (a = 0; a < N; a++) bestd[a] = -1;
    for (a = 0; a < N; a++) bestw[a][0] = 0;
    for (c = 0; c < words; c++) {
      a = 0;
      for (b = 0; b < cn; b++) if (bi[b] == c) a = 1;
      if (a == 1) continue;
      dist = 0;
      for (a = 0; a < size; a++) dist += vec[a] * M[a + c * size];
      for (a = 0; a < N; a++) {
        if (dist > bestd[a]) {
          for (d = N - 1; d > a; d--) {
            bestd[d] = bestd[d - 1];
            strcpy(bestw[d], bestw[d - 1]);
          }
          bestd[a] = dist;
          strcpy(bestw[a], &vocab[c * max_w]);
          break;
        }
      }
    }

//       for (a = 0; a < N && a < 10 ; a++)
// 	printf("%50s\t\t%f\n", bestw[a], bestd[a]);
    for (a = 0; a < N; a++)
    {
      pair<string,float> l_p( string(bestw[a]), bestd[a]);
//       printf("%50s\t\t%f\n", bestw[a], bestd[a]);
      to_return.push_back(l_p);
    }
    return to_return;
  }
  float distance::getDistance(string s1, string s2)
  {
    float vec1[max_size];
    float vec2[max_size];
  //     vector< pair< string, float > > to_return;
      for (a = 0; a < N; a++) bestd[a] = 0;
      for (a = 0; a < N; a++) bestw[a][0] = 0;
//       printf("Enter word or sentence (EXIT to break): ");
      a = 0;
      char st1[max_size];
      char st2[max_size];
      strcpy(st1, s1.c_str());
      strcpy(st2, s2.c_str());
      cn = 0;
      b = 0;
      c = 0;
      int pos1, pos2;
      // supression des espaces
      while (1) {
	st[cn][b] = st1[c];
	b++;
	c++;
	st[cn][b] = 0;
	if (st1[c] == 0) break;
	if (st1[c] == ' ') {
	  cn++;
	  b = 0;
	  c++;
	}
      }
      cn++;
      // supression des espaces
      for (a = 0; a < cn; a++) {
	for (b = 0; b < words; b++) if (!strcmp(&vocab[b * max_w], st[a])) break;
	if (b == words) b = -1;
	bi[a] = b;
// 	printf("\nWord: %s  Position in vocabulary: %lld\n", st[a], bi[a]);
	pos1=bi[a];
	if (b == -1) {
// 	  printf("%s: Out of dictionary word!\n",st[a]);
	  return 0.0;
	}
      }
      // Verification de la présence dans le vocab
      cn = 0;
      b = 0;
      c = 0;
      // supression des espaces
      while (1) {
	st[cn][b] = st2[c];
	b++;
	c++;
	st[cn][b] = 0;
	if (st2[c] == 0) break;
	if (st2[c] == ' ') {
	  cn++;
	  b = 0;
	  c++;
	}
      }
      cn++;
      for (a = 0; a < cn; a++) {
//       cerr << a << " " << cn << endl;
	for (b = 0; b < words; b++) if (!strcmp(&vocab[b * max_w], st[a])) break;
	if (b == words) b = -1;
	bi[a] = b;
	pos2=bi[a];
// 	printf("\nWord: %s  Position in vocabulary: %lld\n", st[a], bi[a]);
	if (b == -1) {
// 	  printf("%s: Out of dictionary word!\n",st[a]);
	  return 0.0;
	}
      }

      if (b == -1) return 0.0;
  //     printf("\n                                              Word       Cosine distance\n------------------------------------------------------------------------\n");
      for (a = 0; a < size; a++) vec1[a] = 0;
      for (b = 0; b < cn; b++) {
	if (pos1 == -1) continue;
	for (a = 0; a < size; a++) vec1[a] += M[a + pos1 * size];
      }
      len = 0;
      for (a = 0; a < size; a++) len += vec1[a] * vec1[a];
      len = sqrt(len);
      for (a = 0; a < size; a++) vec1[a] /= len;

      for (a = 0; a < size; a++) vec2[a] = 0;
      for (b = 0; b < cn; b++) {
	if (pos2 == -1) continue;
	for (a = 0; a < size; a++) vec2[a] += M[a + pos2 * size];
      }
      len = 0;
      for (a = 0; a < size; a++) len += vec2[a] * vec2[a];
      len = sqrt(len);
      for (a = 0; a < size; a++) vec2[a] /= len;
      dist = 0;
      for (a = 0; a < size; a++) dist += vec1[a] * vec2[a];
      return dist;

//       for (a = 0; a < N; a++) bestd[a] = -1;
//       for (a = 0; a < N; a++) bestw[a][0] = 0;
//       for (c = 0; c < words; c++) {
// 	a = 0;
// 	for (b = 0; b < cn; b++) if (bi[b] == c) a = 1;
// 	if (a == 1) continue;
// 	dist = 0;
// 	for (a = 0; a < size; a++) dist += vec[a] * M[a + c * size];
// 	for (a = 0; a < N; a++) {
// 	  if (dist > bestd[a]) {
// 	    for (d = N - 1; d > a; d--) {
// 	      bestd[d] = bestd[d - 1];
// 	      strcpy(bestw[d], bestw[d - 1]);
// 	    }
// 	    bestd[a] = dist;
//
// 	    strcpy(bestw[a], &vocab[c * max_w]);
// 	    break;
// 	  }
// 	}
//       }
//       for (a = 0; a < N && a < 2 ; a++)
//       {
// 	pair<string,float> l_p( string(bestw[a]), bestd[a]);
// 	printf("%50s\t\t%f\n", bestw[a], bestd[a]);
//       }
//       return 1.0;
  }
}<|endoftext|>