Program Listing for File Tran_Mat_Cell.cpp

Return to documentation for file (lib/Tran_Mat_Cell.cpp)

#include <range/v3/all.hpp>
#include <Tran_Mat_Cell.hpp>

using namespace std;
namespace rs = ranges;
using boost::edge;

Tran_Mat_Cell::Tran_Mat_Cell(int source, int target) {
  this->source = source;
  this->target = target;
}

// Add a path that starts with the start vertex and ends with the end vertex.
bool Tran_Mat_Cell::add_path(vector<int>& path) {
  if (path[0] == this->source && path.back() == this->target) {
    this->paths.push_back(path);
    return true;
  }

  return false;
}

void Tran_Mat_Cell::allocate_datastructures() {
  // TODO: Decide the correct initial value
  this->products = vector<double>(paths.size(), 0);
  this->beta2product.clear();

  for (unsigned long int p = 0; p < this->paths.size(); p++) {
    for (unsigned long int v = 0; v < this->paths[p].size() - 1; v++) {
      // Each β along this path is a factor of the product of this path.
      this->beta2product.insert(
          make_pair(make_pair(paths[p][v], paths[p][v + 1]), &products[p]));
    }
  }
}

// Computes the value of this cell from scratch.
// Should be called after adding all the paths using add_path()
// and calling allocate_datastructures()
//         θst
// ┏━━━━━━━━━━━━━━━━━┓
// ┃ θsx   θxy   θyt ↓
// 〇━━━>〇━━━>〇━━━>〇
// ┃  θsw      θwt   ↑
// ┗━━━━━━━>〇━━━━━━━┛
//
// We are computing
//   [tan(θst)] + [(tan(θsx) × tan(θxy) × tan(θyt)] + [tan(θsw) × tan(θwt)]
// In the transition matrix A, this cell is for all the paths starting at
// vertex s and ending at vertex t. If s and t are the indices of the
// respective vertexes, this cell is A[2 × t][2 × s + 1]
double Tran_Mat_Cell::compute_cell(const DiGraph& CAG) {
  for (unsigned long int p = 0; p < this->paths.size(); p++) {
    this->products[p] = 1; // 0;

    for (unsigned long int v = 0; v < this->paths[p].size() - 1; v++) {
      auto edg = edge(paths[p][v], paths[p][v + 1], CAG);
      // β = tan(θ)
      double beta = tan(CAG[edg.first].get_theta());

      this->products[p] *= beta; //+= 1;
    }
  }

  return rs::accumulate(products, 0.0);
}

void Tran_Mat_Cell::print_products() {
  for (double f : this->products) {
    cout << f << " ";
  }
  cout << endl;
}

void Tran_Mat_Cell::print_beta2product() {
  for (auto it = this->beta2product.begin(); it != this->beta2product.end();
       it++) {
    fmt::print(
        "({}, {} -> {})", it->first.first, it->first.second, *(it->second));
  }
}

// Given an edge (source, target vertex ids - a β=∂target/∂source),
// print all the products that are dependent on it.
void Tran_Mat_Cell::print(int source, int target) {
  pair<int, int> beta = make_pair(source, target);

  pair<MMAPIterator, MMAPIterator> res = this->beta2product.equal_range(beta);

  cout << "(" << beta.first << ", " << beta.second << ") -> ";
  for (MMAPIterator it = res.first; it != res.second; it++) {
    cout << *(it->second) << " ";
  }
  cout << endl;
}

void Tran_Mat_Cell::print_paths() {
  cout << endl
       << "Paths between vertices: " << this->source << " and " << this->target
       << endl;
  for (vector<int> path : this->paths) {
    for (int vert : path) {
      cout << vert << " -> ";
    }
    cout << endl;
  }
}

void Tran_Mat_Cell::get_paths_shorter_than_or_equal_to(int length,
                                                       bool from_beginning) {
  cout << endl
       << "Paths between vertices: " << this->source << " and " << this->target
       << endl;

  if (from_beginning) {
    for (vector<int> path : this->paths) {
      for (vector<int>::iterator vert = path.begin();
           vert < path.end() && vert <= path.begin() + length;
           vert++) {
        cout << *vert << " -> ";
      }
      cout << endl;
    }
  }
  else {
    for (vector<int> path : this->paths) {
      vector<int>::iterator vert =
          path.size() <= length ? path.begin() : path.end() - length - 1;
      for (; vert < path.end(); vert++) {
        cout << *vert << " -> ";
      }
      cout << endl;
    }
  }
}

unordered_set<int>
Tran_Mat_Cell::get_vertices_within_hops(int hops, bool from_beginning) {

  unordered_set<int> vertices_within_hops;

  if (from_beginning) {
    for (vector<int> path : this->paths) {
      for (vector<int>::iterator vert = path.begin();
           vert < path.end() && vert <= path.begin() + hops;
           vert++) {
        vertices_within_hops.insert(*vert);
      }
    }
  }
  else {
    for (vector<int> path : this->paths) {
      vector<int>::iterator vert =
          path.size() <= hops ? path.begin() : path.end() - hops - 1;
      for (; vert < path.end(); vert++) {
        vertices_within_hops.insert(*vert);
      }
    }
  }

  return vertices_within_hops;
}

unordered_set<int>
Tran_Mat_Cell::get_vertices_on_paths_shorter_than_or_equal_to(int hops) {

  unordered_set<int> vertices_on_shorter_paths;

  for (vector<int> path : this->paths) {
    if (path.size() <= hops + 1) {
      for (vector<int>::iterator vert = path.begin(); vert < path.end();
           vert++) {
        // cout << *vert << " -> ";
        vertices_on_shorter_paths.insert(*vert);
      }
      // cout << endl;
    }
  }

  return vertices_on_shorter_paths;
}

bool Tran_Mat_Cell::has_multiple_paths_longer_than_or_equal_to(int length) {
  int longer_path_count = 0;

  for (vector<int> path : this->paths) {
    // Note: A path records the sequence of nodes in the path
    //       e.g.: a -> b -> c-> d
    //       Therefore, the length of this path is
    //       path.size() - 1
    //       So, path.size() > length =>
    //           length of path >= length
    if (path.size() > length) {
      longer_path_count++;
    }
  }

  return longer_path_count > 1;
}