/*
* Copyright 2008 Network Engine for Objects in Lund AB [neotechnology.com]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.graphalgo.benchmark.graphgeneration;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import org.neo4j.api.core.Direction;
import org.neo4j.api.core.NeoService;
import org.neo4j.api.core.Node;
import org.neo4j.api.core.Relationship;
import org.neo4j.api.core.RelationshipType;
import org.neo4j.api.core.Transaction;
import org.neo4j.graphalgo.benchmark.graphgeneration.GraphStore.Graph;
public class PreferentialAttachment implements GeneratedGraph
{
private final NeoService neo;
RelationshipType relationshipType;
int numberOfNodes;
int minimumDegree;
private long[] nodes;
private final Random random;
Transaction transaction;
int transactionCount = 0;
protected void renewTransaction()
{
if ( ++transactionCount > 1000 )
{
transactionCount = 0;
transaction.success();
transaction.finish();
transaction = neo.beginTx();
}
}
public Node getRandomNode( Node butNotThisOne )
{
while ( true )
{
long id = nodes[random.nextInt( nodes.length )];
if ( butNotThisOne != null && id == butNotThisOne.getId() )
{
continue;
}
return neo.getNodeById( id );
}
}
public Node getNodeByInternalId( long id )
{
return neo.getNodeById( nodes[(int) id] );
}
public Set<Relationship> getRelationships()
{
Set<Relationship> result = new HashSet<Relationship>();
for ( long nodeId : nodes )
{
Node node = neo.getNodeById( nodeId );
Iterable<Relationship> relationships = node
.getRelationships( Direction.OUTGOING );
for ( Relationship relationship : relationships )
{
result.add( relationship );
}
}
return result;
}
public Set<Node> getNodes()
{
Set<Node> result = new HashSet<Node>();
for ( long nodeId : nodes )
{
result.add( neo.getNodeById( nodeId ) );
}
return result;
}
public PreferentialAttachment( final NeoService neo, GraphStore graphStore,
RelationshipType relationshipType, int numberOfNodes, int minimumDegree )
{
super();
this.neo = neo;
this.relationshipType = relationshipType;
this.numberOfNodes = numberOfNodes;
this.minimumDegree = minimumDegree;
this.random = new Random( System.currentTimeMillis() );
String ident = "PreferentialAttachment," + relationshipType + ","
+ numberOfNodes + "," + minimumDegree;
if ( graphStore != null )
{
Graph graph = graphStore.loadGraph( ident );
if ( graph != null )
{
System.out.println( "Loading graph" );
this.nodes = graph.loadNodeIds();
}
}
// Generate if needed
if ( this.nodes == null )
{
generate();
if ( graphStore != null )
{
graphStore.createGraph( ident ).saveNodeIds( nodes );
}
}
}
public void generate()
{
transaction = neo.beginTx();
System.out.println( "Generating graph" );
nodes = new long[numberOfNodes];
ProgressBar progressBar = new ProgressBar( numberOfNodes
* minimumDegree );
int[] edges = new int[numberOfNodes * minimumDegree * 2];
for ( int v = 0; v < numberOfNodes; ++v )
{
nodes[v] = neo.createNode().getId();
renewTransaction();
for ( int i = 0; i < minimumDegree; ++i )
{
if ( v == 0 )
{
break;
}
// create an edge from the new node to some previous node, by
// randomly choosing among all previous relationships (and both
// ends of them)
int offset = 2 * (v * minimumDegree + i);
edges[offset] = v;
// TODO: this right now does not choose among its own previous
// relationships
int j = random.nextInt( 2 * v * minimumDegree );
edges[offset + 1] = edges[j];
// make it so in the neo network
Node node1 = neo.getNodeById( nodes[edges[offset]] );
Node node2 = neo.getNodeById( nodes[edges[offset + 1]] );
node1.createRelationshipTo( node2, relationshipType );
renewTransaction();
progressBar.Print();
}
}
transaction.success();
transaction.finish();
}
}