haskell-igraph-0.8.0: igraph/src/drl_graph_3d.cpp
/*
* Copyright 2007 Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
* certain rights in this software.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Sandia National Laboratories nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This file contains the member definitions of the master class
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
#include "drl_graph_3d.h"
#include "igraph_random.h"
#include "igraph_interface.h"
#include "igraph_progress.h"
#include "igraph_interrupt_internal.h"
#ifdef MUSE_MPI
#include <mpi.h>
#endif
namespace drl3d {
graph::graph(const igraph_t *igraph,
const igraph_layout_drl_options_t *options,
const igraph_vector_t *weights) {
myid = 0;
num_procs = 1;
STAGE = 0;
iterations = options->init_iterations;
temperature = options->init_temperature;
attraction = options->init_attraction;
damping_mult = options->init_damping_mult;
min_edges = 20;
first_add = fine_first_add = true;
fineDensity = false;
// Brian's original Vx schedule
liquid.iterations = options->liquid_iterations;
liquid.temperature = options->liquid_temperature;
liquid.attraction = options->liquid_attraction;
liquid.damping_mult = options->liquid_damping_mult;
liquid.time_elapsed = 0;
expansion.iterations = options->expansion_iterations;
expansion.temperature = options->expansion_temperature;
expansion.attraction = options->expansion_attraction;
expansion.damping_mult = options->expansion_damping_mult;
expansion.time_elapsed = 0;
cooldown.iterations = options->cooldown_iterations;
cooldown.temperature = options->cooldown_temperature;
cooldown.attraction = options->cooldown_attraction;
cooldown.damping_mult = options->cooldown_damping_mult;
cooldown.time_elapsed = 0;
crunch.iterations = options->crunch_iterations;
crunch.temperature = options->crunch_temperature;
crunch.attraction = options->crunch_attraction;
crunch.damping_mult = options->crunch_damping_mult;
crunch.time_elapsed = 0;
simmer.iterations = options->simmer_iterations;
simmer.temperature = options->simmer_temperature;
simmer.attraction = options->simmer_attraction;
simmer.damping_mult = options->simmer_damping_mult;
simmer.time_elapsed = 0;
// scan .int file for node info
highest_sim = 1.0;
num_nodes = igraph_vcount(igraph);
long int no_of_edges = igraph_ecount(igraph);
for (long int i = 0; i < num_nodes; i++) {
id_catalog[i] = 1;
}
map< int, int>::iterator cat_iter;
for ( cat_iter = id_catalog.begin();
cat_iter != id_catalog.end(); cat_iter++) {
cat_iter->second = cat_iter->first;
}
// populate node positions and ids
positions.reserve ( num_nodes );
for ( cat_iter = id_catalog.begin();
cat_iter != id_catalog.end();
cat_iter++ ) {
positions.push_back ( Node( cat_iter->first ) );
}
// read .int file for graph info
long int node_1, node_2;
double weight;
for (long int i = 0; i < no_of_edges; i++) {
node_1 = IGRAPH_FROM(igraph, i);
node_2 = IGRAPH_TO(igraph, i);
weight = weights ? VECTOR(*weights)[i] : 1.0 ;
(neighbors[id_catalog[node_1]])[id_catalog[node_2]] = weight;
(neighbors[id_catalog[node_2]])[id_catalog[node_1]] = weight;
}
// initialize density server
density_server.Init();
}
// init_parms -- this subroutine initializes the edge_cut variables
// used in the original VxOrd starting with the edge_cut parameter.
// In our version, edge_cut = 0 means no cutting, 1 = maximum cut.
// We also set the random seed here.
void graph::init_parms ( int rand_seed, float edge_cut, float real_parm ) {
IGRAPH_UNUSED(rand_seed);
// first we translate edge_cut the former tcl sliding scale
//CUT_END = cut_length_end = 39000.0 * (1.0 - edge_cut) + 1000.0;
CUT_END = cut_length_end = 40000.0 * (1.0 - edge_cut);
// cut_length_end cannot actually be 0
if ( cut_length_end <= 1.0 ) {
cut_length_end = 1.0;
}
float cut_length_start = 4.0 * cut_length_end;
// now we set the parameters used by ReCompute
cut_off_length = cut_length_start;
cut_rate = ( cut_length_start - cut_length_end ) / 400.0;
// finally set the number of iterations to leave .real coords fixed
int full_comp_iters;
full_comp_iters = liquid.iterations + expansion.iterations +
cooldown.iterations + crunch.iterations + 3;
// adjust real parm to iterations (do not enter simmer halfway)
if ( real_parm < 0 ) {
real_iterations = (int)real_parm;
} else if ( real_parm == 1) {
real_iterations = full_comp_iters + simmer.iterations + 100;
} else {
real_iterations = (int)(real_parm * full_comp_iters);
}
tot_iterations = 0;
if ( real_iterations > 0 ) {
real_fixed = true;
} else {
real_fixed = false;
}
// calculate total expected iterations (for progress bar display)
tot_expected_iterations = liquid.iterations +
expansion.iterations + cooldown.iterations +
crunch.iterations + simmer.iterations;
/*
// output edge_cutting parms (for debugging)
cout << "Processor " << myid << ": "
<< "cut_length_end = CUT_END = " << cut_length_end
<< ", cut_length_start = " << cut_length_start
<< ", cut_rate = " << cut_rate << endl;
*/
// set random seed
// srand ( rand_seed ); // Don't need this in igraph
}
void graph::init_parms(const igraph_layout_drl_options_t *options) {
double rand_seed = 0.0;
double real_in = -1.0;
init_parms(rand_seed, options->edge_cut, real_in);
}
int graph::read_real ( const igraph_matrix_t *real_mat,
const igraph_vector_bool_t *fixed) {
long int n = igraph_matrix_nrow(real_mat);
for (long int i = 0; i < n; i++) {
positions[id_catalog[i]].x = MATRIX(*real_mat, i, 0);
positions[id_catalog[i]].y = MATRIX(*real_mat, i, 1);
positions[id_catalog[i]].z = MATRIX(*real_mat, i, 2);
positions[id_catalog[i]].fixed = fixed ? VECTOR(*fixed)[i] : false;
if ( real_iterations > 0 ) {
density_server.Add ( positions[id_catalog[i]], fineDensity );
}
}
return 0;
}
/*********************************************
* Function: ReCompute *
* Description: Compute the graph locations *
* Modified from original code by B. Wylie *
********************************************/
int graph::ReCompute( ) {
// carryover from original VxOrd
int MIN = 1;
/*
// output parameters (for debugging)
cout << "ReCompute is using the following parameters: "<< endl;
cout << "STAGE: " << STAGE << ", iter: " << iterations << ", temp = " << temperature
<< ", attract = " << attraction << ", damping_mult = " << damping_mult
<< ", min_edges = " << min_edges << ", cut_off_length = " << cut_off_length
<< ", fineDensity = " << fineDensity << endl;
*/
/* igraph progress report */
float progress = (tot_iterations * 100.0 / tot_expected_iterations);
switch (STAGE) {
case 0:
if (iterations == 0) {
IGRAPH_PROGRESS("DrL layout (initialization stage)", progress, 0);
} else {
IGRAPH_PROGRESS("DrL layout (liquid stage)", progress, 0);
}
break;
case 1:
IGRAPH_PROGRESS("DrL layout (expansion stage)", progress, 0); break;
case 2:
IGRAPH_PROGRESS("DrL layout (cooldown and cluster phase)", progress, 0); break;
case 3:
IGRAPH_PROGRESS("DrL layout (crunch phase)", progress, 0); break;
case 5:
IGRAPH_PROGRESS("DrL layout (simmer phase)", progress, 0); break;
case 6:
IGRAPH_PROGRESS("DrL layout (final phase)", 100.0, 0); break;
default:
IGRAPH_PROGRESS("DrL layout (unknown phase)", 0.0, 0); break;
}
/* Compute Energies for individual nodes */
update_nodes ();
// check to see if we need to free fixed nodes
tot_iterations++;
if ( tot_iterations >= real_iterations ) {
real_fixed = false;
}
// ****************************************
// AUTOMATIC CONTROL SECTION
// ****************************************
// STAGE 0: LIQUID
if (STAGE == 0) {
if ( iterations == 0 ) {
start_time = time( NULL );
// if ( myid == 0 )
// cout << "Entering liquid stage ...";
}
if (iterations < liquid.iterations) {
temperature = liquid.temperature;
attraction = liquid.attraction;
damping_mult = liquid.damping_mult;
iterations++;
// if ( myid == 0 )
// cout << "." << flush;
} else {
stop_time = time( NULL );
liquid.time_elapsed = liquid.time_elapsed + (stop_time - start_time);
temperature = expansion.temperature;
attraction = expansion.attraction;
damping_mult = expansion.damping_mult;
iterations = 0;
// go to next stage
STAGE = 1;
start_time = time( NULL );
// if ( myid == 0 )
// cout << "Entering expansion stage ...";
}
}
// STAGE 1: EXPANSION
if (STAGE == 1) {
if (iterations < expansion.iterations) {
// Play with vars
if (attraction > 1) {
attraction -= .05;
}
if (min_edges > 12) {
min_edges -= .05;
}
cut_off_length -= cut_rate;
if (damping_mult > .1) {
damping_mult -= .005;
}
iterations++;
// if ( myid == 0 ) cout << "." << flush;
} else {
stop_time = time( NULL );
expansion.time_elapsed = expansion.time_elapsed + (stop_time - start_time);
min_edges = 12;
damping_mult = cooldown.damping_mult;
STAGE = 2;
attraction = cooldown.attraction;
temperature = cooldown.temperature;
iterations = 0;
start_time = time( NULL );
// if ( myid == 0 )
// cout << "Entering cool-down stage ...";
}
}
// STAGE 2: Cool down and cluster
else if (STAGE == 2) {
if (iterations < cooldown.iterations) {
// Reduce temperature
if (temperature > 50) {
temperature -= 10;
}
// Reduce cut length
if (cut_off_length > cut_length_end) {
cut_off_length -= cut_rate * 2;
}
if (min_edges > MIN) {
min_edges -= .2;
}
//min_edges = 99;
iterations++;
// if ( myid == 0 )
// cout << "." << flush;
} else {
stop_time = time( NULL );
cooldown.time_elapsed = cooldown.time_elapsed + (stop_time - start_time);
cut_off_length = cut_length_end;
temperature = crunch.temperature;
damping_mult = crunch.damping_mult;
min_edges = MIN;
//min_edges = 99; // In other words: no more cutting
STAGE = 3;
iterations = 0;
attraction = crunch.attraction;
start_time = time( NULL );
// if ( myid == 0 )
// cout << "Entering crunch stage ...";
}
}
// STAGE 3: Crunch
else if (STAGE == 3) {
if (iterations < crunch.iterations) {
iterations++;
// if ( myid == 0 ) cout << "." << flush;
} else {
stop_time = time( NULL );
crunch.time_elapsed = crunch.time_elapsed + (stop_time - start_time);
iterations = 0;
temperature = simmer.temperature;
attraction = simmer.attraction;
damping_mult = simmer.damping_mult;
min_edges = 99;
fineDensity = true;
STAGE = 5;
start_time = time( NULL );
// if ( myid == 0 )
// cout << "Entering simmer stage ...";
}
}
// STAGE 5: Simmer
else if ( STAGE == 5 ) {
if (iterations < simmer.iterations) {
if (temperature > 50) {
temperature -= 2;
}
iterations++;
// if ( myid == 0 ) cout << "." << flush;
} else {
stop_time = time( NULL );
simmer.time_elapsed = simmer.time_elapsed + (stop_time - start_time);
STAGE = 6;
// if ( myid == 0 )
// cout << "Layout calculation completed in " <<
// ( liquid.time_elapsed + expansion.time_elapsed +
// cooldown.time_elapsed + crunch.time_elapsed +
// simmer.time_elapsed )
// << " seconds (not including I/O)."
// << endl;
}
}
// STAGE 6: All Done!
else if ( STAGE == 6) {
/*
// output parameters (for debugging)
cout << "ReCompute is using the following parameters: "<< endl;
cout << "STAGE: " << STAGE << ", iter: " << iterations << ", temp = " << temperature
<< ", attract = " << attraction << ", damping_mult = " << damping_mult
<< ", min_edges = " << min_edges << ", cut_off_length = " << cut_off_length
<< ", fineDensity = " << fineDensity << endl;
*/
return 0;
}
// ****************************************
// END AUTOMATIC CONTROL SECTION
// ****************************************
// Still need more recomputation
return 1;
}
// update_nodes -- this function will complete the primary node update
// loop in layout's recompute routine. It follows exactly the same
// sequence to ensure similarity of parallel layout to the standard layout
void graph::update_nodes ( ) {
vector<int> node_indices; // node list of nodes currently being updated
float old_positions[2 * MAX_PROCS]; // positions before update
float new_positions[2 * MAX_PROCS]; // positions after update
bool all_fixed; // check if all nodes are fixed
// initial node list consists of 0,1,...,num_procs
for ( int i = 0; i < num_procs; i++ ) {
node_indices.push_back( i );
}
// next we calculate the number of nodes there would be if the
// num_nodes by num_procs schedule grid were perfectly square
int square_num_nodes = (int)(num_procs + num_procs * floor ((float)(num_nodes - 1) / (float)num_procs ));
for ( int i = myid; i < square_num_nodes; i += num_procs ) {
// get old positions
get_positions ( node_indices, old_positions );
// default new position is old position
get_positions ( node_indices, new_positions );
if ( i < num_nodes ) {
// advance random sequence according to myid
for ( int j = 0; j < 2 * myid; j++ ) {
RNG_UNIF01();
}
// rand();
// calculate node energy possibilities
if ( !(positions[i].fixed && real_fixed) ) {
update_node_pos ( i, old_positions, new_positions );
}
// advance random sequence for next iteration
for ( unsigned int j = 2 * myid; j < 2 * (node_indices.size() - 1); j++ ) {
RNG_UNIF01();
}
// rand();
} else {
// advance random sequence according to use by
// the other processors
for ( unsigned int j = 0; j < 2 * (node_indices.size()); j++ ) {
RNG_UNIF01();
}
//rand();
}
// check if anything was actually updated (e.g. everything was fixed)
all_fixed = true;
for ( unsigned int j = 0; j < node_indices.size (); j++ )
if ( !(positions [ node_indices[j] ].fixed && real_fixed) ) {
all_fixed = false;
}
// update positions across processors (if not all fixed)
if ( !all_fixed ) {
#ifdef MUSE_MPI
MPI_Allgather ( &new_positions[2 * myid], 2, MPI_FLOAT,
new_positions, 2, MPI_FLOAT, MPI_COMM_WORLD );
#endif
// update positions (old to new)
update_density ( node_indices, old_positions, new_positions );
}
/*
if ( myid == 0 )
{
// output node list (for debugging)
for ( unsigned int j = 0; j < node_indices.size(); j++ )
cout << node_indices[j] << " ";
cout << endl;
}
*/
// compute node list for next update
for ( unsigned int j = 0; j < node_indices.size(); j++ ) {
node_indices [j] += num_procs;
}
while ( !node_indices.empty() && node_indices.back() >= num_nodes ) {
node_indices.pop_back ( );
}
}
// update first_add and fine_first_add
first_add = false;
if ( fineDensity ) {
fine_first_add = false;
}
}
// The get_positions function takes the node_indices list
// and returns the corresponding positions in an array.
void graph::get_positions ( vector<int> &node_indices,
float return_positions[3 * MAX_PROCS] ) {
// fill positions
for (unsigned int i = 0; i < node_indices.size(); i++) {
return_positions[3 * i] = positions[ node_indices[i] ].x;
return_positions[3 * i + 1] = positions[ node_indices[i] ].y;
return_positions[3 * i + 2] = positions[ node_indices[i] ].z;
}
}
// update_node_pos -- this subroutine does the actual work of computing
// the new position of a given node. num_act_proc gives the number
// of active processes at this level for use by the random number
// generators.
void graph::update_node_pos ( int node_ind,
float old_positions[3 * MAX_PROCS],
float new_positions[3 * MAX_PROCS] ) {
float energies[2]; // node energies for possible positions
float updated_pos[2][3]; // possible positions
float pos_x, pos_y, pos_z;
// old VxOrd parameter
float jump_length = .010 * temperature;
// subtract old node
density_server.Subtract ( positions[node_ind], first_add, fine_first_add, fineDensity );
// compute node energy for old solution
energies[0] = Compute_Node_Energy ( node_ind );
// move node to centroid position
Solve_Analytic ( node_ind, pos_x, pos_y, pos_z );
positions[node_ind].x = updated_pos[0][0] = pos_x;
positions[node_ind].y = updated_pos[0][1] = pos_y;
positions[node_ind].z = updated_pos[0][2] = pos_z;
/*
// ouput random numbers (for debugging)
int rand_0, rand_1;
rand_0 = rand();
rand_1 = rand();
cout << myid << ": " << rand_0 << ", " << rand_1 << endl;
*/
// Do random method (RAND_MAX is C++ maximum random number)
updated_pos[1][0] = updated_pos[0][0] + (.5 - RNG_UNIF01()) * jump_length;
updated_pos[1][1] = updated_pos[0][1] + (.5 - RNG_UNIF01()) * jump_length;
updated_pos[1][2] = updated_pos[0][2] + (.5 - RNG_UNIF01()) * jump_length;
// compute node energy for random position
positions[node_ind].x = updated_pos[1][0];
positions[node_ind].y = updated_pos[1][1];
positions[node_ind].z = updated_pos[1][2];
energies[1] = Compute_Node_Energy ( node_ind );
/*
// output update possiblities (debugging):
cout << node_ind << ": (" << updated_pos[0][0] << "," << updated_pos[0][1]
<< "), " << energies[0] << "; (" << updated_pos[1][0] << ","
<< updated_pos[1][1] << "), " << energies[1] << endl;
*/
// add back old position
positions[node_ind].x = old_positions[3 * myid];
positions[node_ind].y = old_positions[3 * myid + 1];
positions[node_ind].z = old_positions[3 * myid + 2];
if ( !fineDensity && !first_add ) {
density_server.Add ( positions[node_ind], fineDensity );
} else if ( !fine_first_add ) {
density_server.Add ( positions[node_ind], fineDensity );
}
// choose updated node position with lowest energy
if ( energies[0] < energies[1] ) {
new_positions[3 * myid] = updated_pos[0][0];
new_positions[3 * myid + 1] = updated_pos[0][1];
new_positions[3 * myid + 2] = updated_pos[0][2];
positions[node_ind].energy = energies[0];
} else {
new_positions[3 * myid] = updated_pos[1][0];
new_positions[3 * myid + 1] = updated_pos[1][1];
new_positions[3 * myid + 2] = updated_pos[1][2];
positions[node_ind].energy = energies[1];
}
}
// update_density takes a sequence of node_indices and their positions and
// updates the positions by subtracting the old positions and adding the
// new positions to the density grid.
void graph::update_density ( vector<int> &node_indices,
float old_positions[3 * MAX_PROCS],
float new_positions[3 * MAX_PROCS] ) {
// go through each node and subtract old position from
// density grid before adding new position
for ( unsigned int i = 0; i < node_indices.size(); i++ ) {
positions[node_indices[i]].x = old_positions[3 * i];
positions[node_indices[i]].y = old_positions[3 * i + 1];
positions[node_indices[i]].z = old_positions[3 * i + 2];
density_server.Subtract ( positions[node_indices[i]],
first_add, fine_first_add, fineDensity );
positions[node_indices[i]].x = new_positions[3 * i];
positions[node_indices[i]].y = new_positions[3 * i + 1];
positions[node_indices[i]].z = new_positions[3 * i + 2];
density_server.Add ( positions[node_indices[i]], fineDensity );
}
}
/********************************************
* Function: Compute_Node_Energy *
* Description: Compute the node energy *
* This code has been modified from the *
* original code by B. Wylie. *
*********************************************/
float graph::Compute_Node_Energy( int node_ind ) {
/* Want to expand 4th power range of attraction */
float attraction_factor = attraction * attraction *
attraction * attraction * 2e-2;
map <int, float>::iterator EI;
float x_dis, y_dis, z_dis;
float energy_distance, weight;
float node_energy = 0;
// Add up all connection energies
for (EI = neighbors[node_ind].begin(); EI != neighbors[node_ind].end(); ++EI) {
// Get edge weight
weight = EI->second;
// Compute x,y distance
x_dis = positions[ node_ind ].x - positions[ EI->first ].x;
y_dis = positions[ node_ind ].y - positions[ EI->first ].y;
z_dis = positions[ node_ind ].z - positions[ EI->first ].z;
// Energy Distance
energy_distance = x_dis * x_dis + y_dis * y_dis + z_dis * z_dis;
if (STAGE < 2) {
energy_distance *= energy_distance;
}
// In the liquid phase we want to discourage long link distances
if (STAGE == 0) {
energy_distance *= energy_distance;
}
node_energy += weight * attraction_factor * energy_distance;
}
// output effect of density (debugging)
//cout << "[before: " << node_energy;
// add density
node_energy += density_server.GetDensity ( positions[ node_ind ].x, positions[ node_ind ].y,
positions[ node_ind ].z, fineDensity );
// after calling density server (debugging)
//cout << ", after: " << node_energy << "]" << endl;
// return computated energy
return node_energy;
}
/*********************************************
* Function: Solve_Analytic *
* Description: Compute the node position *
* This is a modified version of the function *
* originally written by B. Wylie *
*********************************************/
void graph::Solve_Analytic( int node_ind, float &pos_x, float &pos_y,
float &pos_z) {
map <int, float>::iterator EI;
float total_weight = 0;
float x_dis, y_dis, z_dis, x_cen = 0, y_cen = 0, z_cen = 0;
float x = 0, y = 0, z = 0, dis;
float damping, weight;
// Sum up all connections
for (EI = neighbors[node_ind].begin(); EI != neighbors[node_ind].end(); ++EI) {
weight = EI->second;
total_weight += weight;
x += weight * positions[ EI->first ].x;
y += weight * positions[ EI->first ].y;
z += weight * positions[ EI->first ].z;
}
// Now set node position
if (total_weight > 0) {
// Compute centriod
x_cen = x / total_weight;
y_cen = y / total_weight;
z_cen = z / total_weight;
damping = 1.0 - damping_mult;
pos_x = damping * positions[ node_ind ].x + (1.0 - damping) * x_cen;
pos_y = damping * positions[ node_ind ].y + (1.0 - damping) * y_cen;
pos_z = damping * positions[ node_ind ].z + (1.0 - damping) * z_cen;
}
// No cut edge flag (?)
if (min_edges == 99) {
return;
}
// Don't cut at end of scale
if ( CUT_END >= 39500 ) {
return;
}
float num_connections = (float)sqrt((float)neighbors[node_ind].size());
float maxLength = 0;
map<int, float>::iterator maxIndex;
// Go through nodes edges... cutting if necessary
for (EI = maxIndex = neighbors[node_ind].begin();
EI != neighbors[node_ind].end(); ++EI) {
// Check for at least min edges
if (neighbors[node_ind].size() < min_edges) {
continue;
}
x_dis = x_cen - positions[ EI->first ].x;
y_dis = y_cen - positions[ EI->first ].y;
z_dis = z_cen - positions[ EI->first ].z;
dis = x_dis * x_dis + y_dis * y_dis + z_dis * z_dis;
dis *= num_connections;
// Store maximum edge
if (dis > maxLength) {
maxLength = dis;
maxIndex = EI;
}
}
// If max length greater than cut_length then cut
if (maxLength > cut_off_length) {
neighbors[ node_ind ].erase( maxIndex );
}
}
// get_tot_energy adds up the energy for each node to give an estimate of the
// quality of the minimization.
float graph::get_tot_energy ( ) {
float my_tot_energy, tot_energy;
my_tot_energy = 0;
for ( int i = myid; i < num_nodes; i += num_procs ) {
my_tot_energy += positions[i].energy;
}
//vector<Node>::iterator i;
//for ( i = positions.begin(); i != positions.end(); i++ )
// tot_energy += i->energy;
#ifdef MUSE_MPI
MPI_Reduce ( &my_tot_energy, &tot_energy, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD );
#else
tot_energy = my_tot_energy;
#endif
return tot_energy;
}
int graph::draw_graph(igraph_matrix_t *res) {
int count_iter = 0;
while (ReCompute()) {
IGRAPH_ALLOW_INTERRUPTION();
count_iter++;
}
long int n = positions.size();
IGRAPH_CHECK(igraph_matrix_resize(res, n, 3));
for (long int i = 0; i < n; i++) {
MATRIX(*res, i, 0) = positions[i].x;
MATRIX(*res, i, 1) = positions[i].y;
MATRIX(*res, i, 2) = positions[i].z;
}
return 0;
}
} // namespace drl3d