<commit_before>#pragma once

//ASSERT_TRUE();
//ASSERT_STREQ(test.c_str(), ans.c_str());

//-----------------------------------------------------------------------------------------------------------------------------------------------

TEST(strEdit, theOthers){
    printf("■ strEdit\n");
    printf("  □ readAll_bin\n");
    std::vector<uint8> raw = sstd::readAll_bin("./test/test.png");
    sstd::printn_all(raw.size());
    printf("  □ writeAll_bin\n");
    if(!sstd::writeAll_bin("./test__writeAll_bin_char.png",             raw)){ sstd::pdbg("ERROR: sstd::writeAll_bin()\n"); }
    if(!sstd::writeAll_bin(std::string("./test__writeAll_bin_str.png"), raw)){ sstd::pdbg("ERROR: sstd::writeAll_bin()\n"); }

    printf("  □ readAll_withoutBOM & splitByLine\n");
//    std::string str_tI = sstd::readAll_withoutBOM(R"(./test/tinyInterpreter.txt)");
    std::string str_tI = sstd::readAll_withoutBOM(std::string(R"(./test/tinyInterpreter.txt)"));
    std::vector<std::string> splitLList = sstd::splitByLine(str_tI);
    printf("\n");
    printf("  ./test/tinyInterpreter.txt\n");
    printf("+----+---------------------------------------------------------------------+\n");
    for(uint i=0; i<splitLList.size(); i++){
        printf("| %2d | %-67s |\n", i, splitLList[i].c_str());
    }
    printf("+----+---------------------------------------------------------------------+\n");
    printf("\n");

    printf("  □ splitByX\n");
    std::vector<std::string> vecRow;
    vecRow = sstd::split("ABC DEF",       ' ');        sstd::printn(vecRow); // "ABC DEF" -> ["ABC", "DEF"]
    vecRow = sstd::split(" ABC   D EF  ", ' ');        sstd::printn(vecRow); // " ABC   D EF  " -> ["ABC", "D", "EF"]

    vecRow = sstd::split("ABC,DEF",              ','); sstd::printn(vecRow); // "ABC,DEF" -> ["ABC", "DEF"]
    vecRow = sstd::split(" ABC  , D,  EF ,GH  ", ','); sstd::printn(vecRow); // " ABC  , D,  EF ,GH  " -> ["ABC", "D", "EF",  "GH"]
}

//-----------------------------------------------------------------------------------------------------------------------------------------------

TEST(strEdit, lstrip){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans =     "abcd \t ";
    ASSERT_TRUE(sstd::lstrip(str_in.c_str()) == str_ans);
    ASSERT_TRUE(sstd::lstrip(str_in        ) == str_ans);
}
TEST(strEdit, lstrip_ow){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans =     "abcd \t ";
    sstd::lstrip_ow(str_in);
    ASSERT_TRUE(str_in == str_ans);
}
TEST(strEdit, rstrip){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = " \t abcd";
    ASSERT_TRUE(sstd::rstrip(str_in.c_str()) == str_ans);
    ASSERT_TRUE(sstd::rstrip(str_in        ) == str_ans);
}
TEST(strEdit, rstrip_ow){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = " \t abcd";
    sstd::rstrip_ow(str_in);
    ASSERT_TRUE(str_in == str_ans);
}
TEST(strEdit, strip){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = "abcd";
    ASSERT_TRUE(sstd::strip(str_in.c_str()) == str_ans);
    ASSERT_TRUE(sstd::strip(str_in        ) == str_ans);
}
TEST(strEdit, strip_ow){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = "abcd";
    sstd::strip_ow(str_in);
    ASSERT_TRUE(str_in == str_ans);
}
TEST(strEdit, strip_vec){
    std::vector<std::string> vecStr_in  = {" \t abcd01 \t ", " \t abcd02 \t ", " \t abcd03 \t "};
    std::vector<std::string> vecStr_ans = {"abcd01", "abcd02", "abcd03"};
    ASSERT_TRUE(sstd::strip(vecStr_in) == vecStr_ans);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------
/*
// 実装完了 (処理時間短縮のため，コメントアウト)
TEST(strEdit, strIn){
    {
        std::string lhs = "";
        std::string rhs = "";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "ABCD";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "BCD";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "DEFG";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "ABCDEFG";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "AXCDEFG";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(!ret);
    }
}
//*/

//-----------------------------------------------------------------------------------------------------------------------------------------------
<commit_msg>test sort<commit_after>#pragma once

//ASSERT_TRUE();
//ASSERT_STREQ(test.c_str(), ans.c_str());

//-----------------------------------------------------------------------------------------------------------------------------------------------

TEST(strEdit, theOthers){
    printf("■ strEdit\n");
    printf("  □ readAll_bin\n");
    std::vector<uint8> raw = sstd::readAll_bin("./test/test.png");
    sstd::printn_all(raw.size());
    printf("  □ writeAll_bin\n");
    if(!sstd::writeAll_bin("./test__writeAll_bin_char.png",             raw)){ sstd::pdbg("ERROR: sstd::writeAll_bin()\n"); }
    if(!sstd::writeAll_bin(std::string("./test__writeAll_bin_str.png"), raw)){ sstd::pdbg("ERROR: sstd::writeAll_bin()\n"); }

    printf("  □ readAll_withoutBOM & splitByLine\n");
//    std::string str_tI = sstd::readAll_withoutBOM(R"(./test/tinyInterpreter.txt)");
    std::string str_tI = sstd::readAll_withoutBOM(std::string(R"(./test/tinyInterpreter.txt)"));
    std::vector<std::string> splitLList = sstd::splitByLine(str_tI);
    printf("\n");
    printf("  ./test/tinyInterpreter.txt\n");
    printf("+----+---------------------------------------------------------------------+\n");
    for(uint i=0; i<splitLList.size(); i++){
        printf("| %2d | %-67s |\n", i, splitLList[i].c_str());
    }
    printf("+----+---------------------------------------------------------------------+\n");
    printf("\n");

    printf("  □ splitByX\n");
    std::vector<std::string> vecRow;
    vecRow = sstd::split("ABC DEF",       ' ');        sstd::printn(vecRow); // "ABC DEF" -> ["ABC", "DEF"]
    vecRow = sstd::split(" ABC   D EF  ", ' ');        sstd::printn(vecRow); // " ABC   D EF  " -> ["ABC", "D", "EF"]

    vecRow = sstd::split("ABC,DEF",              ','); sstd::printn(vecRow); // "ABC,DEF" -> ["ABC", "DEF"]
    vecRow = sstd::split(" ABC  , D,  EF ,GH  ", ','); sstd::printn(vecRow); // " ABC  , D,  EF ,GH  " -> ["ABC", "D", "EF",  "GH"]
}

//-----------------------------------------------------------------------------------------------------------------------------------------------

TEST(strEdit, lstrip){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans =     "abcd \t ";
    ASSERT_TRUE(sstd::lstrip(str_in.c_str()) == str_ans);
    ASSERT_TRUE(sstd::lstrip(str_in        ) == str_ans);
}
TEST(strEdit, lstrip_ow){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans =     "abcd \t ";
    sstd::lstrip_ow(str_in);
    ASSERT_TRUE(str_in == str_ans);
}
TEST(strEdit, rstrip){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = " \t abcd";
    ASSERT_TRUE(sstd::rstrip(str_in.c_str()) == str_ans);
    ASSERT_TRUE(sstd::rstrip(str_in        ) == str_ans);
}
TEST(strEdit, rstrip_ow){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = " \t abcd";
    sstd::rstrip_ow(str_in);
    ASSERT_TRUE(str_in == str_ans);
}
TEST(strEdit, strip){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = "abcd";
    ASSERT_TRUE(sstd::strip(str_in.c_str()) == str_ans);
    ASSERT_TRUE(sstd::strip(str_in        ) == str_ans);
}
TEST(strEdit, strip_ow){
    std::string str_in  = " \t abcd \t ";
    std::string str_ans = "abcd";
    sstd::strip_ow(str_in);
    ASSERT_TRUE(str_in == str_ans);
}
TEST(strEdit, strip_vec){
    std::vector<std::string> vecStr_in  = {" \t abcd01 \t ", " \t abcd02 \t ", " \t abcd03 \t "};
    std::vector<std::string> vecStr_ans = {"abcd01", "abcd02", "abcd03"};
    ASSERT_TRUE(sstd::strip(vecStr_in) == vecStr_ans);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------
/*
// 実装完了 (処理時間短縮のため，コメントアウト)
TEST(strEdit, strIn){
    {
        std::string lhs = "";
        std::string rhs = "";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "ABCD";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "BCD";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "DEFG";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "ABCDEFG";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(ret);
    }
    {
        std::string lhs = "AXCDEFG";
        std::string rhs = "ABCDEFG";
        bool ret=sstd::strIn(lhs, rhs); ASSERT_TRUE(!ret);
    }
}
//*/

//-----------------------------------------------------------------------------------------------------------------------------------------------
<|endoftext|>


<commit_before>/* Copyright (c) 2008-2021 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "command.h"
#include "progressbar.h"
#include "math/rng.h"
#include "math/SH.h"
#include "dwi/gradient.h"
#include "dwi/directions/file.h"

#include <random>
#include <functional>

using namespace MR;
using namespace App;

void usage ()
{
  AUTHOR = "J-Donald Tournier (jdtournier@gmail.com)";

  SYNOPSIS = "Reorder a set of directions to ensure near-uniformity upon truncation";

  DESCRIPTION
  + "The intent of this command is to reorder a set of gradient directions such that "
    "if a scan is terminated prematurely, at any point, the acquired directions will "
    "still be close to optimally distributed on the half-sphere.";

  ARGUMENTS
    + Argument ("input", "the input directions file").type_file_in()
    + Argument ("output", "the output directions file").type_file_out();

  OPTIONS
    + Option ("cartesian", "Output the directions in Cartesian coordinates [x y z] instead of [az el].");
}

using value_type = double;

vector<size_t> optimise (const Eigen::MatrixXd& directions, const size_t first_volume)
{
  vector<size_t> indices (1, first_volume);
  vector<size_t> remaining;
  for (size_t n = 0; n < size_t(directions.rows()); ++n)
    if (n != indices[0])
      remaining.push_back (n);

  while (remaining.size()) {
    ssize_t best = 0;
    value_type best_E = std::numeric_limits<value_type>::max();

    for (size_t n = 0; n < remaining.size(); ++n) {
      value_type E = 0.0;
      ssize_t a = remaining[n];
      for (size_t i = 0; i < indices.size(); ++i) {
        ssize_t b = indices[i];
        E += 1.0 / (directions.row(a) - directions.row(b)).norm();
        E += 1.0 / (directions.row(a) + directions.row(b)).norm();
      }
      if (E < best_E) {
        best_E = E;
        best = n;
      }
    }

    indices.push_back (remaining[best]);
    remaining.erase (remaining.begin()+best);
  }

  return indices;
}

value_type calc_cost (const Eigen::MatrixXd& directions, const vector<size_t>& order)
{
  const size_t start = Math::SH::NforL (2);
  if (directions.rows() <= start)
    return value_type(0);
  Eigen::MatrixXd subset (start, 3);
  for (size_t i = 0; i != start; ++i)
    subset.row(i) = directions.row(order[i]);
  value_type cost = value_type(0);
  for (size_t N = start+1; N < size_t(directions.rows()); ++N) {
    // Don't include condition numbers where precisely the number of coefficients
    //   for that spherical harmonic degree are included, as these tend to
    //   be outliers
    const size_t lmax = Math::SH::LforN (N-1);
    subset.conservativeResize (N, 3);
    subset.row(N-1) = directions.row(order[N-1]);
    const value_type cond = DWI::condition_number_for_lmax (subset, lmax);
    cost += cond;
  }
  return cost;
}

void run ()
{
  auto directions = DWI::Directions::load_cartesian (argument[0]);

  size_t last_candidate_first_volume = directions.rows();
  if (directions.rows() <= Math::SH::NforL (2)) {
    WARN ("Very few directions in input ("
          + str(directions.rows())
          + "); selection of first direction cannot be optimised"
          + " (first direction in input will be first direction in output)");
    last_candidate_first_volume = 1;
  }

  value_type min_cost = std::numeric_limits<value_type>::infinity();
  vector<size_t> best_order;
  ProgressBar progress ("Determining best reordering", directions.rows());
  for (size_t first_volume = 0; first_volume != last_candidate_first_volume; ++first_volume) {
    const vector<size_t> order = optimise (directions, first_volume);
    const value_type cost = calc_cost (directions, order);
    if (cost < min_cost) {
      min_cost = cost;
      best_order = order;
    }
    ++progress;
  }

  decltype(directions) output (directions.rows(), 3);
  for (ssize_t n = 0; n < directions.rows(); ++n)
    output.row(n) = directions.row (best_order[n]);

  DWI::Directions::save (output, argument[1], get_options("cartesian").size());
}

<commit_msg>diroder: Fix compiler warning<commit_after>/* Copyright (c) 2008-2021 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "command.h"
#include "progressbar.h"
#include "math/rng.h"
#include "math/SH.h"
#include "dwi/gradient.h"
#include "dwi/directions/file.h"

#include <random>
#include <functional>

using namespace MR;
using namespace App;

void usage ()
{
  AUTHOR = "J-Donald Tournier (jdtournier@gmail.com)";

  SYNOPSIS = "Reorder a set of directions to ensure near-uniformity upon truncation";

  DESCRIPTION
  + "The intent of this command is to reorder a set of gradient directions such that "
    "if a scan is terminated prematurely, at any point, the acquired directions will "
    "still be close to optimally distributed on the half-sphere.";

  ARGUMENTS
    + Argument ("input", "the input directions file").type_file_in()
    + Argument ("output", "the output directions file").type_file_out();

  OPTIONS
    + Option ("cartesian", "Output the directions in Cartesian coordinates [x y z] instead of [az el].");
}

using value_type = double;

vector<size_t> optimise (const Eigen::MatrixXd& directions, const size_t first_volume)
{
  vector<size_t> indices (1, first_volume);
  vector<size_t> remaining;
  for (size_t n = 0; n < size_t(directions.rows()); ++n)
    if (n != indices[0])
      remaining.push_back (n);

  while (remaining.size()) {
    ssize_t best = 0;
    value_type best_E = std::numeric_limits<value_type>::max();

    for (size_t n = 0; n < remaining.size(); ++n) {
      value_type E = 0.0;
      ssize_t a = remaining[n];
      for (size_t i = 0; i < indices.size(); ++i) {
        ssize_t b = indices[i];
        E += 1.0 / (directions.row(a) - directions.row(b)).norm();
        E += 1.0 / (directions.row(a) + directions.row(b)).norm();
      }
      if (E < best_E) {
        best_E = E;
        best = n;
      }
    }

    indices.push_back (remaining[best]);
    remaining.erase (remaining.begin()+best);
  }

  return indices;
}

value_type calc_cost (const Eigen::MatrixXd& directions, const vector<size_t>& order)
{
  const size_t start = Math::SH::NforL (2);
  if (size_t(directions.rows()) <= start)
    return value_type(0);
  Eigen::MatrixXd subset (start, 3);
  for (size_t i = 0; i != start; ++i)
    subset.row(i) = directions.row(order[i]);
  value_type cost = value_type(0);
  for (size_t N = start+1; N < size_t(directions.rows()); ++N) {
    // Don't include condition numbers where precisely the number of coefficients
    //   for that spherical harmonic degree are included, as these tend to
    //   be outliers
    const size_t lmax = Math::SH::LforN (N-1);
    subset.conservativeResize (N, 3);
    subset.row(N-1) = directions.row(order[N-1]);
    const value_type cond = DWI::condition_number_for_lmax (subset, lmax);
    cost += cond;
  }
  return cost;
}

void run ()
{
  auto directions = DWI::Directions::load_cartesian (argument[0]);

  size_t last_candidate_first_volume = directions.rows();
  if (size_t(directions.rows()) <= Math::SH::NforL (2)) {
    WARN ("Very few directions in input ("
          + str(directions.rows())
          + "); selection of first direction cannot be optimised"
          + " (first direction in input will be first direction in output)");
    last_candidate_first_volume = 1;
  }

  value_type min_cost = std::numeric_limits<value_type>::infinity();
  vector<size_t> best_order;
  ProgressBar progress ("Determining best reordering", directions.rows());
  for (size_t first_volume = 0; first_volume != last_candidate_first_volume; ++first_volume) {
    const vector<size_t> order = optimise (directions, first_volume);
    const value_type cost = calc_cost (directions, order);
    if (cost < min_cost) {
      min_cost = cost;
      best_order = order;
    }
    ++progress;
  }

  decltype(directions) output (directions.rows(), 3);
  for (ssize_t n = 0; n < directions.rows(); ++n)
    output.row(n) = directions.row (best_order[n]);

  DWI::Directions::save (output, argument[1], get_options("cartesian").size());
}

<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// own
#include "Importer.h"
// ospcommon
#include "ospcommon/FileName.h"
// tinyxml
#include "TinyXML2.h"
// std
#include <stdexcept>

namespace ospray {
  namespace importer {

    void importVolumeRAW(const FileName &fileName, Volume *volume);
    void importVolumeRM(const FileName &fileName, Volume *volume);

    void importVolume(const FileName &fileName, Volume *volume)
    {
      const std::string ext = fileName.ext();
      if (ext == "raw" || ext == "gz") {
        importVolumeRAW(fileName, volume);
      } else if (ext == "bob") {
        importVolumeRM(fileName, volume);
      } else {
        throw std::runtime_error("unknown volume format '"+ext+"'");
      }

      // post-checks
      assert(volume->handle != nullptr);
      assert(!volume->bounds.empty());
    }

    vec2i parseInt2(const tinyxml2::XMLNode *node)
    {
      vec2i v;
      int rc = sscanf(node->ToElement()->GetText(),"%i %i",&v.x,&v.y);
      (void)rc;
      assert(rc == 2);
      return v;
    }
    vec3i parseInt3(const tinyxml2::XMLNode *node)
    {
      vec3i v;
      int rc = sscanf(node->ToElement()->GetText(),"%i %i %i",&v.x,&v.y,&v.z);
      (void)rc;
      assert(rc == 3);
      return v;
    }

    float parseFloat1(const tinyxml2::XMLNode *node)
    {
      float v;
      int rc = sscanf(node->ToElement()->GetText(),"%f",&v);
      (void)rc;
      assert(rc == 1);
      return v;
    }
    vec2f parseFloat2(const tinyxml2::XMLNode *node)
    {
      vec2f v;
      int rc = sscanf(node->ToElement()->GetText(),"%f %f",&v.x,&v.y);
      (void)rc;
      assert(rc == 2);
      return v;
    }
    vec3f parseFloat3(const tinyxml2::XMLNode *node)
    {
      vec3f v;
      int rc = sscanf(node->ToElement()->GetText(),"%f %f %f",&v.x,&v.y,&v.z);
      (void)rc;
      assert(rc == 3);
      return v;
    }

    void importVolume(const FileName &orgFileName,
                      Group *group,
                      const tinyxml2::XMLNode *root)
    {
      auto dpFromEnv = getEnvVar<std::string>("OSPRAY_DATA_PARALLEL");

      Volume *volume = new Volume;
      if (dpFromEnv.first) {
        // Create the OSPRay object.
        osp::vec3i blockDims;
        int rc = sscanf(dpFromEnv.second.c_str(), "%dx%dx%d",
                        &blockDims.x, &blockDims.y, &blockDims.z);
        if (rc != 3) {
          throw std::runtime_error("could not parse OSPRAY_DATA_PARALLEL "
                                   "env-var. Must be of format <X>x<Y>x<>Z "
                                   "(e.g., '4x4x4'");
        }
        volume->handle = ospNewVolume("data_distributed_volume");
        if (volume->handle == nullptr) {
          throw std::runtime_error("#loaders.ospObjectFile: could not create "
                                   "volume ...");
        }
        ospSetVec3i(volume->handle, "num_dp_blocks", blockDims);
      } else {
        // Create the OSPRay object.
        std::string volumeType = "block_bricked_volume";

        auto volTypeFromEnv = getEnvVar<std::string>("OSPRAY_USE_VOLUME_TYPE");
        if (volTypeFromEnv.first)
          volumeType = volTypeFromEnv.second;

        volume->handle = ospNewVolume(volumeType.c_str());
      }

      if (volume->handle == nullptr) {
        throw std::runtime_error("#loaders.ospObjectFile: could not create "
                                 "volume ...");
      }

      // Temporary storage for the file name attribute if specified.
      const char *volumeFilename = nullptr;

      // Iterate over object attributes.
      for (const tinyxml2::XMLNode *node = root->FirstChild();
           node;
           node = node->NextSibling()) {

        // Volume size in voxels per dimension.
        if (!strcmp(node->ToElement()->Name(), "dimensions")) {
          volume->dimensions = parseInt3(node);
          continue;
        }

        // File containing a volume specification and / or voxel data.
        if (!strcmp(node->ToElement()->Name(), "filename")) {
          volumeFilename = node->ToElement()->GetText();
          continue;
        }

        // Grid origin in world coordinates.
        if (!strcmp(node->ToElement()->Name(), "gridOrigin")) {
          volume->gridOrigin = parseFloat3(node);
          ospSetVec3f(volume->handle, "gridOrigin", (osp::vec3f&)volume->gridOrigin);
          continue;
        }

        // Grid spacing in each dimension in world coordinates.
        if (!strcmp(node->ToElement()->Name(), "gridSpacing")) {
          volume->gridSpacing = parseFloat3(node);
          ospSetVec3f(volume->handle, "gridSpacing", (osp::vec3f&)volume->gridSpacing);
          continue;
        }

        // Sampling rate for ray casting based renderers.
        if (!strcmp(node->ToElement()->Name(), "samplingRate")) {
          volume->samplingRate = parseFloat1(node);
          ospSet1f(volume->handle, "samplingRate", volume->samplingRate);
          continue;
        }

        // Volume scale factor.
        if (!strcmp(node->ToElement()->Name(), "scaleFactor")) {
          volume->scaleFactor = parseFloat3(node);
          std::cout << "Got scaleFactor = " << volume->scaleFactor << std::endl;
          ospSetVec3f(volume->handle, "scaleFactor", (osp::vec3f&)volume->scaleFactor);
          continue;
        }

        // Subvolume offset from origin within the full volume.
        if (!strcmp(node->ToElement()->Name(), "subvolumeOffsets")) {
          volume->subVolumeOffsets = parseInt3(node);
          continue;
        }

        // Subvolume dimensions within the full volume.
        if (!strcmp(node->ToElement()->Name(), "subvolumeDimensions")) {
          volume->subVolumeDimensions = parseInt3(node);
          continue;
        }

        // Subvolume steps in each dimension; can be used to subsample.
        if (!strcmp(node->ToElement()->Name(), "subvolumeSteps")) {
          volume->subVolumeSteps = parseInt3(node);
          continue;
        }

        // Voxel value range.
        if (!strcmp(node->ToElement()->Name(), "voxelRange")) {
          volume->voxelRange = parseFloat2(node);
          continue;
        }

        // Voxel type string.
        if (!strcmp(node->ToElement()->Name(), "voxelType")) {
          volume->voxelType = node->ToElement()->GetText();
          continue;
        }

        // Error check.
        exitOnCondition(true, "unrecognized XML element type '" +
                        std::string(node->ToElement()->Name()) + "'");
      }

      // Load the contents of the volume file if specified.
      if (volumeFilename != nullptr) {
        // The volume file path is absolute.
        if (volumeFilename[0] == '/')
          importVolume(volumeFilename, volume);
        else {
          importVolume((orgFileName.path().str()
                        + "/" + volumeFilename).c_str(), volume);
        }
      }

      group->volume.push_back(volume);
    }

    void importTriangleMesh(Group *group, const tinyxml2::XMLNode *node)
    {
      throw std::runtime_error("importTriangleMesh: not yet implemented");
    }

    void importLight(Group *group, const tinyxml2::XMLNode *node)
    {
      throw std::runtime_error("importLight: not yet implemented");
    }

    void importObject(const FileName &orgFileName,
                      Group *group,
                      const tinyxml2::XMLNode *node)
    {
      // OSPRay light object.
      if (!strcmp(node->ToElement()->Name(), "light"))
        importLight(group,node);

      // OSPRay triangle mesh object.
      else if (!strcmp(node->ToElement()->Name(), "triangleMesh"))
        importTriangleMesh(group,node);

      // OSPRay volume object.
      else if (!strcmp(node->ToElement()->Name(), "volume"))
        importVolume(orgFileName,group,node);

      // No other object types are currently supported.
      else
        exitOnCondition(true, "unrecognized XML element type '"
                        + std::string(node->ToElement()->Name()) + "'");
    }

    void importOSP(const FileName &fileName, Group *existingGroupToAddTo)
    {
      // The XML document container.
      tinyxml2::XMLDocument xml(true, tinyxml2::COLLAPSE_WHITESPACE);

      // Read the XML object file.
      exitOnCondition(xml.LoadFile(fileName.str().c_str()) != tinyxml2::XML_SUCCESS,
                      "unable to read object file '" + fileName.str() + "'");

      Group *group = existingGroupToAddTo ? existingGroupToAddTo : new Group;

      // Iterate over the object entries, skip the XML declaration and comments.
      for (const tinyxml2::XMLNode *node = xml.FirstChild();
           node;
           node = node->NextSibling()) {
        if (node->ToElement())
          importObject(fileName,group,node);
      }

      // post-checks:
      for (size_t i = 0; i < group->volume.size(); i++) {
        assert(group->volume[i]->handle != nullptr);
        assert(!group->volume[i]->bounds.empty());
      }
    }
  }
}
<commit_msg>Works on mac<commit_after>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// own
#include "Importer.h"
// ospcommon
#include "ospcommon/FileName.h"
// tinyxml
#include "TinyXML2.h"
// std
#include <stdexcept>

namespace ospray {
  namespace importer {

    void importVolumeRAW(const FileName &fileName, Volume *volume);
    void importVolumeRM(const FileName &fileName, Volume *volume);

    void importVolume(const FileName &fileName, Volume *volume)
    {
      const std::string ext = fileName.ext();
      if (ext == "raw" || ext == "gz") {
        importVolumeRAW(fileName, volume);
      } else if (ext == "bob") {
        importVolumeRM(fileName, volume);
      } else {
        throw std::runtime_error("unknown volume format '"+ext+"'");
      }

      // post-checks
      assert(volume->handle != nullptr);
      assert(!volume->bounds.empty());
    }

    vec2i parseInt2(const tinyxml2::XMLNode *node)
    {
      vec2i v;
      int rc = sscanf(node->ToElement()->GetText(),"%i %i",&v.x,&v.y);
      (void)rc;
      assert(rc == 2);
      return v;
    }
    vec3i parseInt3(const tinyxml2::XMLNode *node)
    {
      vec3i v;
      int rc = sscanf(node->ToElement()->GetText(),"%i %i %i",&v.x,&v.y,&v.z);
      (void)rc;
      assert(rc == 3);
      return v;
    }

    float parseFloat1(const tinyxml2::XMLNode *node)
    {
      float v;
      int rc = sscanf(node->ToElement()->GetText(),"%f",&v);
      (void)rc;
      assert(rc == 1);
      return v;
    }
    vec2f parseFloat2(const tinyxml2::XMLNode *node)
    {
      vec2f v;
      int rc = sscanf(node->ToElement()->GetText(),"%f %f",&v.x,&v.y);
      (void)rc;
      assert(rc == 2);
      return v;
    }
    vec3f parseFloat3(const tinyxml2::XMLNode *node)
    {
      vec3f v;
      int rc = sscanf(node->ToElement()->GetText(),"%f %f %f",&v.x,&v.y,&v.z);
      (void)rc;
      assert(rc == 3);
      return v;
    }

    void importVolume(const FileName &orgFileName,
                      Group *group,
                      const tinyxml2::XMLNode *root)
    {
      auto dpFromEnv = std::make_pair(false, std::string());//getEnvVar<std::string>("OSPRAY_DATA_PARALLEL");

      Volume *volume = new Volume;
      if (dpFromEnv.first) {
        // Create the OSPRay object.
        osp::vec3i blockDims;
        int rc = sscanf(dpFromEnv.second.c_str(), "%dx%dx%d",
                        &blockDims.x, &blockDims.y, &blockDims.z);
        if (rc != 3) {
          throw std::runtime_error("could not parse OSPRAY_DATA_PARALLEL "
                                   "env-var. Must be of format <X>x<Y>x<>Z "
                                   "(e.g., '4x4x4'");
        }
        volume->handle = ospNewVolume("data_distributed_volume");
        if (volume->handle == nullptr) {
          throw std::runtime_error("#loaders.ospObjectFile: could not create "
                                   "volume ...");
        }
        ospSetVec3i(volume->handle, "num_dp_blocks", blockDims);
      } else {
        // Create the OSPRay object.
        std::string volumeType = "block_bricked_volume";

        auto volTypeFromEnv = std::make_pair(false, std::string());//getEnvVar<std::string>("OSPRAY_USE_VOLUME_TYPE");
        if (volTypeFromEnv.first)
          volumeType = volTypeFromEnv.second;

        volume->handle = ospNewVolume(volumeType.c_str());
      }

      if (volume->handle == nullptr) {
        throw std::runtime_error("#loaders.ospObjectFile: could not create "
                                 "volume ...");
      }

      // Temporary storage for the file name attribute if specified.
      const char *volumeFilename = nullptr;

      // Iterate over object attributes.
      for (const tinyxml2::XMLNode *node = root->FirstChild();
           node;
           node = node->NextSibling()) {

        // Volume size in voxels per dimension.
        if (!strcmp(node->ToElement()->Name(), "dimensions")) {
          volume->dimensions = parseInt3(node);
          continue;
        }

        // File containing a volume specification and / or voxel data.
        if (!strcmp(node->ToElement()->Name(), "filename")) {
          volumeFilename = node->ToElement()->GetText();
          continue;
        }

        // Grid origin in world coordinates.
        if (!strcmp(node->ToElement()->Name(), "gridOrigin")) {
          volume->gridOrigin = parseFloat3(node);
          ospSetVec3f(volume->handle, "gridOrigin", (osp::vec3f&)volume->gridOrigin);
          continue;
        }

        // Grid spacing in each dimension in world coordinates.
        if (!strcmp(node->ToElement()->Name(), "gridSpacing")) {
          volume->gridSpacing = parseFloat3(node);
          ospSetVec3f(volume->handle, "gridSpacing", (osp::vec3f&)volume->gridSpacing);
          continue;
        }

        // Sampling rate for ray casting based renderers.
        if (!strcmp(node->ToElement()->Name(), "samplingRate")) {
          volume->samplingRate = parseFloat1(node);
          ospSet1f(volume->handle, "samplingRate", volume->samplingRate);
          continue;
        }

        // Volume scale factor.
        if (!strcmp(node->ToElement()->Name(), "scaleFactor")) {
          volume->scaleFactor = parseFloat3(node);
          std::cout << "Got scaleFactor = " << volume->scaleFactor << std::endl;
          ospSetVec3f(volume->handle, "scaleFactor", (osp::vec3f&)volume->scaleFactor);
          continue;
        }

        // Subvolume offset from origin within the full volume.
        if (!strcmp(node->ToElement()->Name(), "subvolumeOffsets")) {
          volume->subVolumeOffsets = parseInt3(node);
          continue;
        }

        // Subvolume dimensions within the full volume.
        if (!strcmp(node->ToElement()->Name(), "subvolumeDimensions")) {
          volume->subVolumeDimensions = parseInt3(node);
          continue;
        }

        // Subvolume steps in each dimension; can be used to subsample.
        if (!strcmp(node->ToElement()->Name(), "subvolumeSteps")) {
          volume->subVolumeSteps = parseInt3(node);
          continue;
        }

        // Voxel value range.
        if (!strcmp(node->ToElement()->Name(), "voxelRange")) {
          volume->voxelRange = parseFloat2(node);
          continue;
        }

        // Voxel type string.
        if (!strcmp(node->ToElement()->Name(), "voxelType")) {
          volume->voxelType = node->ToElement()->GetText();
          continue;
        }

        // Error check.
        exitOnCondition(true, "unrecognized XML element type '" +
                        std::string(node->ToElement()->Name()) + "'");
      }

      // Load the contents of the volume file if specified.
      if (volumeFilename != nullptr) {
        // The volume file path is absolute.
        if (volumeFilename[0] == '/')
          importVolume(volumeFilename, volume);
        else {
          importVolume((orgFileName.path()
                        + "/" + volumeFilename).c_str(), volume);
        }
      }

      group->volume.push_back(volume);
    }

    void importTriangleMesh(Group *group, const tinyxml2::XMLNode *node)
    {
      throw std::runtime_error("importTriangleMesh: not yet implemented");
    }

    void importLight(Group *group, const tinyxml2::XMLNode *node)
    {
      throw std::runtime_error("importLight: not yet implemented");
    }

    void importObject(const FileName &orgFileName,
                      Group *group,
                      const tinyxml2::XMLNode *node)
    {
      // OSPRay light object.
      if (!strcmp(node->ToElement()->Name(), "light"))
        importLight(group,node);

      // OSPRay triangle mesh object.
      else if (!strcmp(node->ToElement()->Name(), "triangleMesh"))
        importTriangleMesh(group,node);

      // OSPRay volume object.
      else if (!strcmp(node->ToElement()->Name(), "volume"))
        importVolume(orgFileName,group,node);

      // No other object types are currently supported.
      else
        exitOnCondition(true, "unrecognized XML element type '"
                        + std::string(node->ToElement()->Name()) + "'");
    }

    void importOSP(const FileName &fileName, Group *existingGroupToAddTo)
    {
      // The XML document container.
      tinyxml2::XMLDocument xml(true, tinyxml2::COLLAPSE_WHITESPACE);

      // Read the XML object file.
      exitOnCondition(xml.LoadFile(fileName.str().c_str()) != tinyxml2::XML_SUCCESS,
                      "unable to read object file '" + fileName.str() + "'");

      Group *group = existingGroupToAddTo ? existingGroupToAddTo : new Group;

      // Iterate over the object entries, skip the XML declaration and comments.
      for (const tinyxml2::XMLNode *node = xml.FirstChild();
           node;
           node = node->NextSibling()) {
        if (node->ToElement())
          importObject(fileName,group,node);
      }

      // post-checks:
      for (size_t i = 0; i < group->volume.size(); i++) {
        assert(group->volume[i]->handle != nullptr);
        assert(!group->volume[i]->bounds.empty());
      }
    }
  }
}
<|endoftext|>


<commit_before>#include <cassert>
#include <random>
#include "synthetic.hpp"
#include "network.hpp"
#include "tclap/ValueArg.h"

WARPED_REGISTER_POLYMORPHIC_SERIALIZABLE_CLASS(InternalEvent)
WARPED_REGISTER_POLYMORPHIC_SERIALIZABLE_CLASS(ExternalEvent)

inline std::string Node::lpName(const unsigned int lp_index) {

    return std::string("Node_") + std::to_string(lp_index);
}

std::vector<std::shared_ptr<warped::Event> > Node::initializeLP() {

    std::vector<std::shared_ptr<warped::Event> > events;

    /* Register random number generator */
    registerRNG<std::default_random_engine>(rng_);

    for (unsigned int i = 0; i < num_nodes_; i++) {
        unsigned int time = send_distribution_->nextTimeDelta(*rng_);
        events.emplace_back(new InternalEvent {time});
    }
    return events;
}

std::vector<std::shared_ptr<warped::Event> > Node::receiveEvent(const warped::Event& event) {

    std::vector<std::shared_ptr<warped::Event> > response_events;
    assert (event.sender_name_ == event.receiverName());
#if 0
    std::exponential_distribution<double> time_expo(1.0/mean_time_);
    std::uniform_int_distribution<int> ext_node(0, adjacency_list_.size()-1);

    /* Check if event received is a self/internal timer event */
    if (event.sender_name_ == event.receiverName()) {

        /* Restart the timer/internal event */
        unsigned int time = (unsigned int)std::ceil(time_expo(*rng_));
        response_events.emplace_back(new InternalEvent {time});

        /* Send an external event to one of the nodes in its adjacency list */
        auto id = (unsigned int) ext_node(*rng_);
        response_events.emplace_back(
                new ExternalEvent { adjacency_list_[id],
                                    1,
                                    time    });

    } else { /* Event received from other LPs/nodes */

    }
#endif
    return response_events;
}

int main(int argc, const char** argv) {

    unsigned int num_nodes                  = 100000;
    std::string network                     = "Watts-Strogatz,30,0.1";
    std::string node_selection              = "exponential,3.5";
    std::string event_processing_time       = "1000,1000";
    std::string state_size                  = "100,100";
    std::string event_send                  = "geometric,0.5,10";

    TCLAP::ValueArg<unsigned int> num_nodes_arg("n", "num-nodes",
            "Number of nodes", false, num_nodes, "unsigned int");
    TCLAP::ValueArg<std::string> network_arg("t", "network-params",
            "Network details - <type,param1,param2,...>", false, network, "string");
    TCLAP::ValueArg<std::string> node_selection_arg("o", "node-selection-params",
            "Node selection details - <distribution-type,<distribution-params>>",
            false, node_selection, "string");
    TCLAP::ValueArg<std::string> event_processing_time_arg("e", "event-processing-time-range",
            "Event processing time (as floating-point calculation count) range - <min,max>",
            false, event_processing_time, "string");
    TCLAP::ValueArg<std::string> state_size_arg("s", "state-size-range",
            "Size range (in bytes) for the LP state - <min,max>",
            false, state_size, "string");
    TCLAP::ValueArg<std::string> event_send_arg("p", "send-params",
            "Event send details - <distribution-type,<distribution-params>,ceiling-value>",
            "false", event_send, "string");

    std::vector<TCLAP::Arg*> args = {   &num_nodes_arg,
                                        &network_arg,
                                        &node_selection_arg,
                                        &event_processing_time_arg,
                                        &state_size_arg,
                                        &event_send_arg
                                    };

    warped::Simulation synthetic_sim {"Synthetic Simulation", argc, argv, args};

    num_nodes                   = num_nodes_arg.getValue();
    network                     = network_arg.getValue();
    node_selection              = node_selection_arg.getValue();
    event_processing_time       = event_processing_time_arg.getValue();
    state_size                  = state_size_arg.getValue();
    event_send                  = event_send_arg.getValue();

    std::vector<Node> lps;
    std::vector<std::string> lp_names;

    /* Create uniform distribution for event processing time */
    std::string delimiter = ",";
    size_t pos = event_processing_time.find(delimiter);
    unsigned int min_processing_time =
                    (unsigned int) std::stoul(event_processing_time.substr(0, pos));
    unsigned int max_processing_time =
                    (unsigned int) std::stoul(event_processing_time.substr(pos+1));
    std::uniform_int_distribution<unsigned int>
                event_processing_time_dist( min_processing_time, max_processing_time );

    /* Create uniform distribution for the state size */
    pos = state_size.find(delimiter);
    unsigned int min_state_size = (unsigned int) std::stoul(state_size.substr(0, pos));
    unsigned int max_state_size = (unsigned int) std::stoul(state_size.substr(pos+1));
    std::uniform_int_distribution<unsigned int>
                state_size_dist( min_state_size, max_state_size );

    /* Create the LPs */
    std::default_random_engine generator (num_nodes);
    for (unsigned int i = 0; i < num_nodes; i++) {
        auto name = Node::lpName(i);
        lp_names.push_back(name);
        lps.emplace_back(   name,
                            num_nodes,
                            event_processing_time_dist(generator),
                            state_size_dist(generator),
                            i
                        );
    }

    std::vector<warped::LogicalProcess*> lp_pointers;
    for (auto& lp : lps) {
        lp_pointers.push_back(&lp);
    }

    /* Create the Network */
    Network *ntwrk = nullptr;
    pos = network.find(delimiter);
    std::string type = network.substr(0, pos);
    network.erase(0, pos + delimiter.length());
    if (type == "Watts-Strogatz") { // If the choice is Watts-Strogatz
        pos = network.find(delimiter);
        std::string token = network.substr(0, pos);
        unsigned int k = (unsigned int) std::stoul(token);
        network.erase(0, pos + delimiter.length());
        double beta = std::stod(network);
        ntwrk = new WattsStrogatz(lp_names, k, beta);

    } else if (type == "Barabasi-Albert") { // If the choice is Barabasi-Albert
        pos = network.find(delimiter);
        std::string token = network.substr(0, pos);
        unsigned int m = (unsigned int) std::stoul(token);
        network.erase(0, pos + delimiter.length());
        double a = std::stod(network);
        ntwrk = new BarabasiAlbert(lp_names, m, a);

    } else { // Invalid choice
        std::cerr << "Invalid choice of network." << std::endl;
        abort();
    }

    /* Parse the event send distribution type and parameters */
    pos = event_send.find(delimiter);
    std::string distribution_type = event_send.substr(0, pos);
    event_send.erase(0, pos + delimiter.length());

    for (auto& lp : lps) {

        /* Create the send time distributions */
        if (distribution_type == "geometric") {
            lp.send_distribution_ = new Geometric(event_send);

        } else if (distribution_type == "exponential") {
            lp.send_distribution_ = new Exponential(event_send);

        } else if (distribution_type == "binomial") {
            lp.send_distribution_ = new Binomial(event_send);

        } else {
            std::cerr << "Invalid choice of event send distribution." << std::endl;
            abort();
        }

        /* Fetch the adjacency list for each node */
        lp.adjacency_list_ = ntwrk->adjacencyList(lp.name_);
        assert(lp.adjacency_list_.size());
    }
    delete ntwrk;

    /* Parse the node selection distribution type and parameters */
    pos = node_selection.find(delimiter);
    distribution_type = node_selection.substr(0, pos);
    node_selection.erase(0, pos + delimiter.length());

    for (auto& lp : lps) {
        node_selection += "," + lp.adjacency_list_.size();

        /* Create the node selection distributions */
        if (distribution_type == "geometric") {
            lp.node_sel_distribution_ = new Geometric(node_selection);

        } else if (distribution_type == "exponential") {
            lp.node_sel_distribution_ = new Exponential(node_selection);

        } else if (distribution_type == "binomial") {
            lp.node_sel_distribution_ = new Binomial(node_selection);

        } else {
            std::cerr << "Invalid choice of node select distribution." << std::endl;
            abort();
        }
    }

    /* Simulate the synthetic model */
    synthetic_sim.simulate(lp_pointers);

    return 0;
}

<commit_msg>completed receiveEvent()<commit_after>#include <cassert>
#include <random>
#include "synthetic.hpp"
#include "network.hpp"
#include "tclap/ValueArg.h"

WARPED_REGISTER_POLYMORPHIC_SERIALIZABLE_CLASS(InternalEvent)
WARPED_REGISTER_POLYMORPHIC_SERIALIZABLE_CLASS(ExternalEvent)

inline std::string Node::lpName(const unsigned int lp_index) {

    return std::string("Node_") + std::to_string(lp_index);
}

std::vector<std::shared_ptr<warped::Event> > Node::initializeLP() {

    std::vector<std::shared_ptr<warped::Event> > events;

    /* Register random number generator */
    registerRNG<std::default_random_engine>(rng_);

    for (unsigned int i = 0; i < num_nodes_; i++) {
        unsigned int time = send_distribution_->nextTimeDelta(*rng_);
        events.emplace_back(new InternalEvent {time});
    }
    return events;
}

std::vector<std::shared_ptr<warped::Event> > Node::receiveEvent(const warped::Event& event) {

    std::vector<std::shared_ptr<warped::Event> > response_events;

    /* Register random number generator */
    registerRNG<std::default_random_engine>(rng_);

    /* Check if event received is a self/internal timer event */
    if (event.sender_name_ == event.receiverName()) {

        /* Restart the processing_timer/internal event */
        unsigned int processing_time = send_distribution_->nextTimeDelta(*rng_);
        response_events.emplace_back(new InternalEvent {processing_time});

        /* Send an external event to one of the nodes in its adjacency list */

        /* selecting node using distribution */
        auto id = (unsigned int) node_sel_distribution_->nextTimeDelta(*rng_);

        /* Restart the timer/external event */
        unsigned int ts = send_distribution_->nextTimeDelta(*rng_);

        response_events.emplace_back(
                new ExternalEvent { adjacency_list_[id],
                                    processing_time,
                                    ts    });

    } else { /* Event received from other LPs/nodes */

    }
    return response_events;
}

int main(int argc, const char** argv) {

    unsigned int num_nodes                  = 100000;
    std::string network                     = "Watts-Strogatz,30,0.1";
    std::string node_selection              = "exponential,3.5";
    std::string event_processing_time       = "1000,1000";
    std::string state_size                  = "100,100";
    std::string event_send                  = "geometric,0.5,10";

    TCLAP::ValueArg<unsigned int> num_nodes_arg("n", "num-nodes",
            "Number of nodes", false, num_nodes, "unsigned int");
    TCLAP::ValueArg<std::string> network_arg("t", "network-params",
            "Network details - <type,param1,param2,...>", false, network, "string");
    TCLAP::ValueArg<std::string> node_selection_arg("o", "node-selection-params",
            "Node selection details - <distribution-type,<distribution-params>>",
            false, node_selection, "string");
    TCLAP::ValueArg<std::string> event_processing_time_arg("e", "event-processing-time-range",
            "Event processing time (as floating-point calculation count) range - <min,max>",
            false, event_processing_time, "string");
    TCLAP::ValueArg<std::string> state_size_arg("s", "state-size-range",
            "Size range (in bytes) for the LP state - <min,max>",
            false, state_size, "string");
    TCLAP::ValueArg<std::string> event_send_arg("p", "send-params",
            "Event send details - <distribution-type,<distribution-params>,ceiling-value>",
            "false", event_send, "string");

    std::vector<TCLAP::Arg*> args = {   &num_nodes_arg,
                                        &network_arg,
                                        &node_selection_arg,
                                        &event_processing_time_arg,
                                        &state_size_arg,
                                        &event_send_arg
                                    };

    warped::Simulation synthetic_sim {"Synthetic Simulation", argc, argv, args};

    num_nodes                   = num_nodes_arg.getValue();
    network                     = network_arg.getValue();
    node_selection              = node_selection_arg.getValue();
    event_processing_time       = event_processing_time_arg.getValue();
    state_size                  = state_size_arg.getValue();
    event_send                  = event_send_arg.getValue();

    std::vector<Node> lps;
    std::vector<std::string> lp_names;

    /* Create uniform distribution for event processing time */
    std::string delimiter = ",";
    size_t pos = event_processing_time.find(delimiter);
    unsigned int min_processing_time =
                    (unsigned int) std::stoul(event_processing_time.substr(0, pos));
    unsigned int max_processing_time =
                    (unsigned int) std::stoul(event_processing_time.substr(pos+1));
    std::uniform_int_distribution<unsigned int>
                event_processing_time_dist( min_processing_time, max_processing_time );

    /* Create uniform distribution for the state size */
    pos = state_size.find(delimiter);
    unsigned int min_state_size = (unsigned int) std::stoul(state_size.substr(0, pos));
    unsigned int max_state_size = (unsigned int) std::stoul(state_size.substr(pos+1));
    std::uniform_int_distribution<unsigned int>
                state_size_dist( min_state_size, max_state_size );

    /* Create the LPs */
    std::default_random_engine generator (num_nodes);
    for (unsigned int i = 0; i < num_nodes; i++) {
        auto name = Node::lpName(i);
        lp_names.push_back(name);
        lps.emplace_back(   name,
                            num_nodes,
                            event_processing_time_dist(generator),
                            state_size_dist(generator),
                            i
                        );
    }

    std::vector<warped::LogicalProcess*> lp_pointers;
    for (auto& lp : lps) {
        lp_pointers.push_back(&lp);
    }

    /* Create the Network */
    Network *ntwrk = nullptr;
    pos = network.find(delimiter);
    std::string type = network.substr(0, pos);
    network.erase(0, pos + delimiter.length());
    if (type == "Watts-Strogatz") { // If the choice is Watts-Strogatz
        pos = network.find(delimiter);
        std::string token = network.substr(0, pos);
        unsigned int k = (unsigned int) std::stoul(token);
        network.erase(0, pos + delimiter.length());
        double beta = std::stod(network);
        ntwrk = new WattsStrogatz(lp_names, k, beta);

    } else if (type == "Barabasi-Albert") { // If the choice is Barabasi-Albert
        pos = network.find(delimiter);
        std::string token = network.substr(0, pos);
        unsigned int m = (unsigned int) std::stoul(token);
        network.erase(0, pos + delimiter.length());
        double a = std::stod(network);
        ntwrk = new BarabasiAlbert(lp_names, m, a);

    } else { // Invalid choice
        std::cerr << "Invalid choice of network." << std::endl;
        abort();
    }

    /* Parse the event send distribution type and parameters */
    pos = event_send.find(delimiter);
    std::string distribution_type = event_send.substr(0, pos);
    event_send.erase(0, pos + delimiter.length());

    for (auto& lp : lps) {

        /* Create the send time distributions */
        if (distribution_type == "geometric") {
            lp.send_distribution_ = new Geometric(event_send);

        } else if (distribution_type == "exponential") {
            lp.send_distribution_ = new Exponential(event_send);

        } else if (distribution_type == "binomial") {
            lp.send_distribution_ = new Binomial(event_send);

        } else {
            std::cerr << "Invalid choice of event send distribution." << std::endl;
            abort();
        }

        /* Fetch the adjacency list for each node */
        lp.adjacency_list_ = ntwrk->adjacencyList(lp.name_);
        assert(lp.adjacency_list_.size());
    }
    delete ntwrk;

    /* Parse the node selection distribution type and parameters */
    pos = node_selection.find(delimiter);
    distribution_type = node_selection.substr(0, pos);
    node_selection.erase(0, pos + delimiter.length());

    for (auto& lp : lps) {
        node_selection += "," + lp.adjacency_list_.size();

        /* Create the node selection distributions */
        if (distribution_type == "geometric") {
            lp.node_sel_distribution_ = new Geometric(node_selection);

        } else if (distribution_type == "exponential") {
            lp.node_sel_distribution_ = new Exponential(node_selection);

        } else if (distribution_type == "binomial") {
            lp.node_sel_distribution_ = new Binomial(node_selection);

        } else {
            std::cerr << "Invalid choice of node select distribution." << std::endl;
            abort();
        }
    }

    /* Simulate the synthetic model */
    synthetic_sim.simulate(lp_pointers);

    return 0;
}

<|endoftext|>


<commit_before>#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <vector>
#include <stdexcept>
#include <cassert>
#include <ctime>
#include <omp.h>

void readpgm( const std::string &fn,
        unsigned char* &data,
        int &width,
        int &height ) {

    FILE*  stream = 0;

    stream = fopen(fn.c_str(),"r");
    if ( !stream ) {
        std::cerr << " Failed to read pgm." << std::endl;
        exit(-1);
    }

    int bsize;
    int read = fscanf(stream,"P5\n%d %d\n%d%*[\n]",&width,&height,&bsize);
    if ( read < 3 ) {
        std::cerr << " Failed to read pgm header." << std::endl;
        exit(-1);
    }

    data = new unsigned char[width*height];

    read = fread(data,1,width*height,stream);
    if ( read != width*height ) {
        std::cerr << " Failed to read pgm data." << std::endl;
        std::cerr << " Read " << read << " expected " << width*height
            <<  "." << std::endl;
        exit(-1);
    }

    fclose(stream);

}

void writepgm( const std::string &fn,
        unsigned char* &data,
        int &width,
        int &height ) {

    FILE*  stream = 0;

    stream = fopen(fn.c_str(),"w");
    if ( !stream ) {
        std::cerr << " Failed to write pgm." << std::endl;
        exit(-1);
    }

    int wrote = fprintf(stream,"P5\n%d %d\n%d\n",width,height,255);
    if ( wrote < 3 ) {
        std::cerr << " Failed to write pgm header." << std::endl;
        exit(-1);
    }

    wrote = fwrite(data,1,width*height,stream);
    if ( wrote != width*height ) {
        std::cerr << " Failed to write pgm data." << std::endl;
        std::cerr << " Wrote " << wrote << " expected " << width*height
            <<  "." << std::endl;
        exit(-1);
    }

    fclose(stream);

}

typedef struct _im {

    unsigned char *data;
    int width, height;

} im_t;

inline double smoothing_term( int *displut, unsigned char *disp, int width, int
        height, int y, int x, int thisdisp, double p1, double p2 ) {

    if ( y < 0 || y >= height || x < 0 || x >= width ) {
        return 0; /* TODO: Is this the correct behaviour? */
    }

    double smoothterm = 0;
    int absdisp = std::abs(displut[disp[y*width+x]] - thisdisp);
    if ( absdisp == 0 ) {
        smoothterm = 0;
    } else if (  absdisp == 1 ) {
        smoothterm = p1;
    } else {
        smoothterm = p2;
    }
    return smoothterm;
}

inline int sample_distribution( int n, double *prob, double norm ) {

    double unirand = (double) std::rand() / (double) RAND_MAX;

    double cumsum = 0;
    double invnorm = 1/norm;

    int reti = -1;

    for ( int i = 0; i < n; ++i ) {
        cumsum += prob[i] * invnorm;
        if ( unirand <= cumsum ) { /* This must eventually be true of any prob.
                                      dist. */
            reti = i;
            break;
        }
    }

    assert( reti >= 0 );

    return reti;

}

double calculate_energy( int ndisp,
        int mindisp,
        double p1,
        double p2,
        double temperature,
        int width, /* Image width */
        int height, /* Image width */
        unsigned char *ref,
        unsigned char *match,
        unsigned char *disp /* Disparity */) {

    int* displut = new int[ndisp];
    for ( int idisp = 0; idisp < ndisp; ++idisp ) {
        displut[idisp] = idisp + mindisp;
    }

    const double invtemperature = 1/temperature;

    double energy = 0;
    for ( int irow = 0; irow < height; ++irow ) {
        for ( int icol = 0; icol < width; ++icol ) {
            int refidx = irow * width + icol;
            int thisdisp = disp[irow*width + icol];
            int matchx = icol + thisdisp;
            if ( matchx < 0 || matchx >= width ) {
                continue;
            }
            int matchidx = irow*width + matchx;
            double dataterm = std::abs((int)(ref[refidx]) - (int)(match[matchidx])) * invtemperature ;
            double smoothterm = 0;
            smoothterm += smoothing_term(displut,disp,width,height,irow+1,icol,thisdisp,p1,p2);
            smoothterm += smoothing_term(displut,disp,width,height,irow,icol+1,thisdisp,p1,p2);
            energy += dataterm + smoothterm;
        }
    }

    delete[] displut;

    return energy;

}

void block_gibbs_iter( bool smooth,
        int partition, /* 0 or 1 */
        int ndisp,
        int mindisp,
        double p1,
        double p2,
        double temperature,
        int width, /* Image width */
        int height, /* Image width */
        unsigned char *ref,
        unsigned char *match,
        unsigned char *disp /* Disparity */) {

    int* displut = new int[ndisp];
    for ( int idisp = 0; idisp < ndisp; ++idisp ) {
        displut[idisp] = idisp + mindisp;
    }

    const double invtemperature = 1/temperature;

    int nthread = 1;
#pragma omp parallel
    {
        nthread = omp_get_num_threads();
    }
    double **probs = new double*[nthread];
    for ( int i = 0; i < nthread; ++i ){
        probs[i] = new double[ndisp];
    }
#pragma omp parallel for
    for ( int irow = 0; irow < height; ++irow ) {
        int omptid = omp_get_thread_num();
        double* prob = probs[omptid];
        int shift = (partition + irow) % 2; /* 0 or 1 aternating between rows */
        for ( int icol = shift; icol < width; icol += 2 ) {
            int refidx = irow * width + icol; /* Every second element */

            //Need to compute the energy for every possible disparity:
            for ( int idisp = 0; idisp < ndisp; ++idisp ) {
                int thisdisp = displut[idisp];
                int matchx = icol + thisdisp;
                if ( matchx < 0 || matchx >= width ) {
                    prob[idisp] = -1;
                    continue;
                }
                int matchidx = irow*width + matchx;
                double dataterm = std::abs((int)(ref[refidx]) - (int)(match[matchidx])) * invtemperature;

                //Smoothing term of the four neighbours.
                double smoothterm = 0;
                if ( smooth ) {
                    smoothterm += smoothing_term(displut,disp,width,height,irow+1,icol,thisdisp,p1,p2);
                    smoothterm += smoothing_term(displut,disp,width,height,irow-1,icol,thisdisp,p1,p2);
                    smoothterm += smoothing_term(displut,disp,width,height,irow,icol+1,thisdisp,p1,p2);
                    smoothterm += smoothing_term(displut,disp,width,height,irow,icol-1,thisdisp,p1,p2);
                }

                prob[idisp] = dataterm + smoothterm;
            }

            double partitionfunc = 0;
            for ( int idisp = 0; idisp < ndisp; ++idisp ) {
                if ( prob[idisp] >= 0 ) {
                    prob[idisp] = std::exp( - (prob[idisp]) );
                    partitionfunc += prob[idisp];
                } else {
                    prob[idisp] = 0;
                }
            }

            assert ( partitionfunc > 0 ); /* There must be some disparity with non-zero prob.*/

            disp[ refidx ] = sample_distribution(ndisp,prob,partitionfunc);

        }
    }

    delete[] displut;
    for ( int i = 0; i < nthread; ++i ) {
        delete[] probs[i];
    }
    delete[] probs;

}

void block_gibbs( int niter,
        int ndisp,
        int mindisp,
        double _p1,
        double _p2,
        double temperature,
        im_t &im1,
        im_t &im2,
        im_t &disp) {

    if ( !(im1.width == im2.width && im1.height == im2.height  ) ) {
        std::cerr << " Images are not same dimensions." << std::endl;
        exit(-1);
    }

    int width = im1.width;
    int height = im1.height;

    double p1,p2;
    p1 = _p1 / temperature;
    p2 = _p2 / temperature;

    unsigned char *ref   = im1.data;
    unsigned char *match = im2.data;
    unsigned char *out   = disp.data;

    for ( int iter = 0; iter < niter;
            ++iter ) {
        for ( int k = 0; k < 2; ++k ) {
            int partition = k;
            block_gibbs_iter( true, partition, ndisp, mindisp, p1, p2, temperature, width,
                    height, ref, match, out);
        }
        double energy = calculate_energy( ndisp, mindisp, p1, p2, temperature, width,
                height, ref, match, out );

        writepgm("disp_inprogress.pgm",
                disp.data,
                disp.width,
                disp.height);

        std::cout << " done block gibbs iter " << iter+1 << " of " <<
            niter << " energy: " << energy << std::endl;

    }

}

int main( int argc, char *argv[] ) {

    std::srand(time(NULL));

    im_t im1, im2, disp;

    std::cout << " Reading im1 " << std::endl;
    readpgm("cones_left.pgm",
            im1.data,
            im1.width,
            im1.height);

    std::cout << " Reading im2 " << std::endl;
    readpgm("cones_right.pgm",
            im2.data,
            im2.width,
            im2.height);

    disp.width  = im1.width;
    disp.height = im1.height;
    disp.data   = new unsigned char[disp.width*disp.height];

    std::fill(disp.data,disp.data+disp.width*disp.height,0);

    int niter1 = 0;
    int ndisp = 128;
    int mindisp = -(ndisp-1);
    double temperature = 10.; /* Temperature is unfortunately critical to
                                 methods based on block gibbs sampling. Higher
                                 temperature induces more variability and
                                 possibly non convergence, lower temperatures
                                 cause numeric instabilities as well as poor
                                 solutions that refuse to shift from their
                                 locally optimal solution. */

    std::cout << " ndisp: " << ndisp << std::endl;
    std::cout << " mindisp: " << mindisp << std::endl;
    std::cout << " temperature: " << temperature << std::endl;

    double p1, p2; /* The model that is minimized uses the same p1, p2
                      penalties as SGM and countless other stereo algorithms.
                      */
    int niter;

    std::cout << " calculating prior: " << std::endl;
    p1 = 0;
    p2 = 0;
    niter = 10;
    block_gibbs(niter,ndisp,mindisp,p1,p2,temperature,im1,im2,disp);
    std::cout << " done calculating prior " << std::endl;

    std::cout << " calculating posterior: " << std::endl;
    p1 = 5.;
    p2 = 50.;
    niter = 10000;
    block_gibbs(niter,ndisp,mindisp,p1,p2,temperature,im1,im2,disp);
    std::cout << " done calculating posterior " << std::endl;

    writepgm("disp.pgm",
            disp.data,
            disp.width,
            disp.height);

    delete[] im1.data;
    delete[] im2.data;
    delete[] disp.data;

    return 0;
}
<commit_msg>Gibbs stereo working, but can be tweaked a lot more.<commit_after>#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <vector>
#include <stdexcept>
#include <cassert>
#include <ctime>
#include <omp.h>
#include <limits>

void readpgm( const std::string &fn,
        unsigned char* &data,
        int &width,
        int &height ) {

    FILE*  stream = 0;

    stream = fopen(fn.c_str(),"r");
    if ( !stream ) {
        std::cerr << " Failed to read pgm." << std::endl;
        exit(-1);
    }

    int bsize;
    int read = fscanf(stream,"P5\n%d %d\n%d%*[\n]",&width,&height,&bsize);
    if ( read < 3 ) {
        std::cerr << " Failed to read pgm header." << std::endl;
        exit(-1);
    }

    data = new unsigned char[width*height];

    read = fread(data,1,width*height,stream);
    if ( read != width*height ) {
        std::cerr << " Failed to read pgm data." << std::endl;
        std::cerr << " Read " << read << " expected " << width*height
            <<  "." << std::endl;
        exit(-1);
    }

    fclose(stream);

}

void writepgm( const std::string &fn,
        unsigned char* &data,
        int &width,
        int &height ) {

    FILE*  stream = 0;

    stream = fopen(fn.c_str(),"w");
    if ( !stream ) {
        std::cerr << " Failed to write pgm." << std::endl;
        exit(-1);
    }

    int wrote = fprintf(stream,"P5\n%d %d\n%d\n",width,height,255);
    if ( wrote < 3 ) {
        std::cerr << " Failed to write pgm header." << std::endl;
        exit(-1);
    }

    wrote = fwrite(data,1,width*height,stream);
    if ( wrote != width*height ) {
        std::cerr << " Failed to write pgm data." << std::endl;
        std::cerr << " Wrote " << wrote << " expected " << width*height
            <<  "." << std::endl;
        exit(-1);
    }

    fclose(stream);

}

typedef struct _im {

    unsigned char *data;
    int width, height;

} im_t;

inline double smoothing_term( int *displut, unsigned char *disp, int width, int
        height, int y, int x, int thisdisp, double p1, double p2 ) {

    if ( y < 0 || y >= height || x < 0 || x >= width ) {
        return 0; /* TODO: Is this the correct behaviour? */
    }

    double smoothterm = 0;
    int absdisp = std::abs(displut[disp[y*width+x]] - thisdisp);
    if ( absdisp == 0 ) {
        smoothterm = 0;
    } else if (  absdisp == 1 ) {
        smoothterm = p1;
    } else {
        smoothterm = p2;
    }
    return smoothterm;
}

inline int sample_distribution( int n, double *prob, double norm ) {

    double unirand = (double) std::rand() / (double) RAND_MAX;

    double cumsum = 0;
    double invnorm = 1/norm;

    int reti = -1;

    for ( int i = 0; i < n; ++i ) {
        cumsum += prob[i] * invnorm;
        if ( unirand <= cumsum ) { /* This must eventually be true of any prob.
                                      dist. */
            reti = i;
            break;
        }
    }

    if ( reti < 0  ){ /* This seems to happen only in the case when the
                         comparison above fails which is extremely unlikely. */
        printf(" ****warning corner case in sampling detected:\n"
                "   cumsum=%g\n   unirand=%g\n", cumsum, unirand);
        reti = n-1; /* It almost always seems to be the case that unirand == 1
                       && cumsum == 1 but it is a precision error that fails
                       the comparison above. */
    }

    assert( reti >= 0 );

    return reti;

}

double calculate_energy( int ndisp,
        int mindisp,
        double p1,
        double p2,
        double temperature,
        int width, /* Image width */
        int height, /* Image width */
        unsigned char *dataterms,
        unsigned char *ref,
        unsigned char *match,
        unsigned char *disp /* Disparity */) {

    int* displut = new int[ndisp];
    for ( int idisp = 0; idisp < ndisp; ++idisp ) {
        displut[idisp] = idisp + mindisp;
    }

    const double invtemperature = 1/temperature;

    double energy = 0;
    for ( int irow = 0; irow < height; ++irow ) {
        for ( int icol = 0; icol < width; ++icol ) {
            int refidx = irow * width + icol;
            int idisp = disp[irow*width + icol];
            int thisdisp = displut[idisp];
            int matchx = icol + thisdisp;
            if ( matchx < 0 || matchx >= width ) {
                continue;
            }
            int matchidx = irow*width + matchx;
            double dataterm = dataterms[(irow*width+icol)*ndisp + idisp] * invtemperature;
            double smoothterm = 0;
            smoothterm += smoothing_term(displut,disp,width,height,irow+1,icol,thisdisp,p1,p2);
            smoothterm += smoothing_term(displut,disp,width,height,irow,icol+1,thisdisp,p1,p2);
            energy += dataterm + smoothterm;
        }
    }

    delete[] displut;

    return energy;

}

void block_gibbs_iter( bool smooth,
        int partition, /* 0 or 1 */
        int ndisp,
        int mindisp,
        double p1,
        double p2,
        double temperature,
        int width, /* Image width */
        int height, /* Image width */
        unsigned char *dataterms,
        unsigned char *ref,
        unsigned char *match,
        unsigned char *disp /* Disparity */) {

    int* displut = new int[ndisp];
    for ( int idisp = 0; idisp < ndisp; ++idisp ) {
        displut[idisp] = idisp + mindisp;
    }

    const double invtemperature = 1/temperature;

    int nthread = 1;
#pragma omp parallel
    {
        nthread = omp_get_num_threads();
    }
    double **probs = new double*[nthread];
    for ( int i = 0; i < nthread; ++i ){
        probs[i] = new double[ndisp];
    }
#pragma omp parallel for
    for ( int irow = 0; irow < height; ++irow ) {
        int omptid = omp_get_thread_num();
        double* prob = probs[omptid];
        int shift = (partition + irow) % 2; /* 0 or 1 aternating between rows */
        for ( int icol = shift; icol < width; icol += 2 ) {
            int refidx = irow * width + icol; /* Every second element */

            //Need to compute the energy for every possible disparity:
            for ( int idisp = 0; idisp < ndisp; ++idisp ) {
                int thisdisp = displut[idisp];
                int matchx = icol + thisdisp;
                if ( matchx < 0 || matchx >= width ) {
                    prob[idisp] = -1;
                    continue;
                }
                int matchidx = irow*width + matchx;
                double dataterm = dataterms[(irow*width+icol)*ndisp + idisp] * invtemperature;

                //Smoothing term of the four neighbours.
                double smoothterm = 0;
                if ( smooth ) {
                    smoothterm += smoothing_term(displut,disp,width,height,irow+1,icol,thisdisp,p1,p2);
                    smoothterm += smoothing_term(displut,disp,width,height,irow-1,icol,thisdisp,p1,p2);
                    smoothterm += smoothing_term(displut,disp,width,height,irow,icol+1,thisdisp,p1,p2);
                    smoothterm += smoothing_term(displut,disp,width,height,irow,icol-1,thisdisp,p1,p2);
                }

                prob[idisp] = dataterm + smoothterm;

            }

            double partitionfunc = 0;
            for ( int idisp = 0; idisp < ndisp; ++idisp ) {
                if ( prob[idisp] >= 0 ) {
                    prob[idisp] = std::exp( - (prob[idisp]) );
                    partitionfunc += prob[idisp];
                } else {
                    prob[idisp] = 0;
                }
            }

            assert ( partitionfunc > 0 ); /* There must be some disparity with non-zero prob.*/

            disp[ refidx ] = sample_distribution(ndisp,prob,partitionfunc);

        }
    }

    delete[] displut;
    for ( int i = 0; i < nthread; ++i ) {
        delete[] probs[i];
    }
    delete[] probs;

}

void block_gibbs( int niter,
        int ndisp,
        int mindisp,
        double _p1,
        double _p2,
        double temperature,
        unsigned char *dataterms,
        im_t &im1,
        im_t &im2,
        im_t &disp) {

    if ( !(im1.width == im2.width && im1.height == im2.height  ) ) {
        std::cerr << " Images are not same dimensions." << std::endl;
        exit(-1);
    }

    int width = im1.width;
    int height = im1.height;

    double p1,p2;
    p1 = _p1 / temperature;
    p2 = _p2 / temperature;

    unsigned char *ref   = im1.data;
    unsigned char *match = im2.data;
    unsigned char *out   = disp.data;

    for ( int iter = 0; iter < niter;
            ++iter ) {
        for ( int k = 0; k < 2; ++k ) {
            int partition = k;
            block_gibbs_iter( true, partition, ndisp, mindisp, p1, p2, temperature, width,
                    height, dataterms, ref, match, out);
        }
        double energy = calculate_energy( ndisp, mindisp, p1, p2, temperature, width,
                height, dataterms, ref, match, out );

        if ( iter % 2  == 0 ) {
            writepgm("disp_inprogress.pgm",
                    disp.data,
                    disp.width,
                    disp.height);
        }

        std::cout << " done block gibbs iter " << iter+1 << " of " <<
            niter << " energy: " << energy << std::endl;

    }

}

void calculate_dataterms( int ndisp,
        int mindisp,
        int rady,
        int radx,
        im_t &im1,
        im_t &im2,
        unsigned char *dataterms ) {

    if ( !(im1.width == im2.width && im1.height == im2.height  ) ) {
        std::cerr << " Images are not same dimensions." << std::endl;
        exit(-1);
    }

    int width = im1.width;
    int height = im1.height;

    unsigned char *ref   = im1.data;
    unsigned char *match = im2.data;

    int* displut = new int[ndisp];
    for ( int idisp = 0; idisp < ndisp; ++idisp ) {
        displut[idisp] = idisp + mindisp;
    }

#pragma omp parallel for
    for ( int irow = 0; irow < height; ++irow ) {

        int rsizey = 2*rady+1;
        int rsizex = 2*radx+1;
        double *refpx = new double[rsizey*rsizex];
        double *matchpx = new double[rsizey*rsizex];

        for ( int icol = 0; icol < width; ++icol ) {

            int refidx = irow * width + icol;

            for ( int idisp = 0; idisp < ndisp; ++idisp ) {
                int thisdisp = displut[idisp];
                int matchx = icol + thisdisp;
                if ( matchx < 0 || matchx >= width ) {
                    continue;
                }
                int matchidx = irow*width + matchx;

                refpx[0] = ref[refidx];
                matchpx[0] = match[matchidx];

                double refaggrterm = refpx[0];
                double matchaggrterm = matchpx[0];
                int countfound = 1;
                for ( int dy = -rady; dy <= rady; ++dy ) {
                    for ( int dx = -radx; dx <= radx; ++dx ) {
                        if ( dx == 0 && dy == 0 ) {
                            continue;
                        }
                        int x0, y0, x1, y1;
                        y0 = irow + dy;
                        x0 = matchx + dx;
                        y1 = y0;
                        x1 = icol + dx;
                        if ( x0 < 0 || x0 >= width || x1 < 0 || x1 >= width ||
                                y0 < 0 || y0 >= height ) {
                            continue;
                        }
                        refpx[countfound] = ref[y1*width+x1];
                        matchpx[countfound] = match[y0*width+x0];
                        refaggrterm += refpx[countfound];
                        matchaggrterm += matchpx[countfound];
                        countfound++;
                    }
                }

                //Compute means & std
                double refmean = refaggrterm / countfound;
                double matchmean = matchaggrterm / countfound;

                double refstd = 0;
                double matchstd = 0;

                for ( int ipx = 0; ipx < countfound; ++ipx ) {
                    double t;
                    t = (refpx[ipx] - refmean );
                    refstd += t*t;
                    t = (matchpx[ipx] - matchmean );
                    matchstd += t*t;
                }
                refstd = std::sqrt(refstd);
                matchstd = std::sqrt(matchstd);

                int stdthresh = 0;

                double norm = 1. / refstd / matchstd;
                double ncc = 0;
                for ( int ipx = 0; ipx < countfound; ++ipx ) {
                    ncc += (refpx[ipx] - refmean) * (matchpx[ipx] - matchmean ) * norm;
                }

                if ( matchstd > stdthresh && refstd >  stdthresh ) {
                    if ( !( ncc <= 1+1e-6 && ncc >= -1-1e-6) ) {
                        std::cout << " countfound: " << countfound << std::endl;
                        std::cout << " ncc: " << ncc << std::endl;
                        printf("nccp: %lf\n",ncc);
                        std::cout << " refstd: " << refstd << std::endl;
                        std::cout << " matchstd: " << matchstd << std::endl;
                        std::cout << " refmean: " << refmean << std::endl;
                        std::cout << " matchmean: " << matchmean << std::endl;
                        std::cout << " refpx: ";
                        for ( int ipx = 0; ipx < countfound; ++ipx ) {
                            std::cout << refpx[ipx] << ", ";
                        }
                        std::cout << std::endl;
                        std::cout << " matchpx: ";
                        for ( int ipx = 0; ipx < countfound; ++ipx ) {
                            std::cout << matchpx[ipx] << ", ";
                        }
                        std::cout << std::endl;
                    }
                    assert( ncc <= 1.+1e-6 && ncc >= -1.-1e-6);

                    double output = (1-ncc) * 128;
                    output = output < 0 ? 0 : output > 255 ? 255 : output;
                    dataterms[ (irow*width + icol)*ndisp + idisp ] = output;
                } else {
                    dataterms[ (irow*width + icol)*ndisp + idisp ] = 255;
                }

            }

        }

        delete[] refpx;
        delete[] matchpx;
    }

    delete[] displut;

}

int main( int argc, char *argv[] ) {

    std::srand(time(NULL));

    im_t im1, im2, disp;

    std::cout << " Reading im1 " << std::endl;
    readpgm("cones_left.pgm",
            im1.data,
            im1.width,
            im1.height);

    std::cout << " Reading im2 " << std::endl;
    readpgm("cones_right.pgm",
            im2.data,
            im2.width,
            im2.height);

    disp.width  = im1.width;
    disp.height = im1.height;
    disp.data   = new unsigned char[disp.width*disp.height];

    bool usecheckpoint = false;
    std::string checkpointfile = "";
    if ( usecheckpoint ) {
        readpgm(checkpointfile,
                disp.data,
                disp.width,
                disp.height);
    } else {
        std::fill(disp.data,disp.data+disp.width*disp.height,0);
    }

    int ndisp = 128;
    int mindisp = -(ndisp-1);
    double temperature;       /* Temperature is unfortunately critical to
                                 methods based on block gibbs sampling. Higher
                                 temperature induces more variability and
                                 possibly non convergence, lower temperatures
                                 cause numeric instabilities as well as poor
                                 solutions that refuse to shift from their
                                 locally optimal solution. */

    std::cout << " ndisp: " << ndisp << std::endl;
    std::cout << " mindisp: " << mindisp << std::endl;

    double p1, p2; /* The model that is minimized uses the same p1, p2
                      penalties as SGM and countless other stereo algorithms.
                      */

    /* Precompute the dataterms based on radius size */
    int drady = 1;
    int dradx = 1;
    unsigned char *dataterms = new unsigned char[im1.width*im1.height*ndisp];
    std::cout << " precomputing dataterms ... " << std::endl;
    calculate_dataterms(ndisp,mindisp,drady,dradx,im1,im2,dataterms);
    std::cout << " done precomputing dataterms " << std::endl;

    int niter;

    if ( !usecheckpoint ) {
        std::cout << " calculating prior ... " << std::endl;
        p1 = 0;
        p2 = 0;
        niter = 1;
        temperature = 1.;
        block_gibbs(niter,ndisp,mindisp,p1,p2,temperature,dataterms,im1,im2,disp);
        std::cout << " done calculating prior " << std::endl;
    }

    /* A very reasonable set of settings is:
     *
     * p1 = 10; p2 = 215; temperature = 80;
     *
     */

    std::cout << " calculating posterior ... " << std::endl;
    p1 = 10;
    p2 = 215;
    niter = 2000;
    temperature = 20.;
    block_gibbs(niter,ndisp,mindisp,p1,p2,temperature,dataterms,im1,im2,disp);

    writepgm("disp.pgm",
            disp.data,
            disp.width,
            disp.height);

    delete[] im1.data;
    delete[] im2.data;
    delete[] disp.data;
    delete[] dataterms;

    return 0;
}
<|endoftext|>