001 // Copyright 2012, 2013 Brad Block, Pawjaw, LLC. (an Ohio Limited Liability Company) 002 // 003 // This file is part of JFPPR. 004 // 005 // JFPPR is free software: you can redistribute it and/or modify 006 // it under the terms of the GNU General Public License as published by 007 // the Free Software Foundation, either version 3 of the License, or 008 // (at your option) any later version. 009 // 010 // JFPPR is distributed in the hope that it will be useful, 011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 // GNU General Public License for more details. 014 // 015 // You should have received a copy of the GNU General Public License 016 // along with JFPPR. If not, see <http://www.gnu.org/licenses/>. 017 018 package com.pawjaw.graph.fppr; 019 020 import com.pawjaw.graph.fppr.Graph.Step; 021 import java.util.Random; 022 023 /** 024 * Each element in the PageRank {@link Graph} is represented by an instance of 025 * this class. Vertex elements are by the Graph instance when the Graph is 026 * instantiated. The number of Vertex elements is specified when the Graph is 027 * instantiated. Vertex elements are labeled by contiguous increasing integer ids 028 * starting at zero. The process for adding outgoing edges from a Vertex is by 029 * retrieving the source Vertex from the Graph instance, then specifying a 030 * destination Vertex also retrieved from the Graph instance as well as a 031 * non-negative weight. 032 * 033 * @see Graph 034 */ 035 public final class Vertex implements Comparable<Vertex> { 036 /** 037 * The id of this vertex. 038 */ 039 public final int id; 040 041 private int visits = 0; 042 private float outgoing_edge_weight_sum = 0; 043 private Segment next_segment = null; 044 private Segment last_segment = null; 045 private Segment first_segment = null; 046 private OutgoingEdge last_outgoing_edge = null; 047 private OutgoingEdge first_outgoing_edge = null; 048 049 private static final Random R = new Random(); 050 051 protected Vertex(int id) { 052 this.id = id; 053 } 054 055 /** 056 * Add a directed outgoing edge from this Vertex to a destination Vertex. 057 * Use the {@link Graph#vertex} method to retrieve source and destination 058 * Vertex elements. 059 * <p>Here is an example of creating a Graph with 10 Vertex 060 * elements and adding an outgoing edge from Vertex with vertex id: 7 to 061 * Vertex with vertex id: 2 with transition weight 0.5: 062 * <p><code> 063 * Graph g = new Graph(10);<br> 064 * Vertex source = g.vertex(7);<br> 065 * Vertex destination = g.vertex(2);<br> 066 * source.addOutgoingEdge(destination, 0.5); 067 * </code> 068 * 069 * @param destination the destination of this outgoing edge 070 * @param weight a non-negative transition weight for sampling walk steps 071 * 072 * @see Graph#vertex(int) 073 */ 074 public void addOutgoingEdge(Vertex destination, float weight) { 075 outgoing_edge_weight_sum += weight; 076 if(first_outgoing_edge == null) 077 first_outgoing_edge = last_outgoing_edge = new OutgoingEdge(destination, weight); 078 else 079 last_outgoing_edge = last_outgoing_edge.next_outgoing_edge = new OutgoingEdge(destination, weight); 080 } 081 082 protected void addSegment(Step step) { 083 if(first_segment == null) 084 next_segment = first_segment = last_segment = new Segment(step); 085 else 086 last_segment = last_segment.next_segment = new Segment(step); 087 } 088 089 protected void reset() { 090 visits = 0; 091 next_segment = first_segment; 092 } 093 094 protected void visit() { 095 visits++; 096 } 097 098 protected int visits() { 099 return visits; 100 } 101 102 protected Step nextSegmentStart() { 103 Segment _next_segment; 104 if(next_segment == null) 105 return null; 106 _next_segment = next_segment; 107 next_segment = next_segment.next_segment; 108 return _next_segment.segment_start; 109 } 110 111 protected Vertex sampleNeighbor() { 112 float r = R.nextFloat() * outgoing_edge_weight_sum; 113 OutgoingEdge next_outgoing_edge = first_outgoing_edge; 114 while(next_outgoing_edge != null) 115 if((r -= next_outgoing_edge.weight) <= 0) 116 return next_outgoing_edge.destination; 117 else 118 next_outgoing_edge = next_outgoing_edge.next_outgoing_edge; 119 // if no neighbors, treat as if exists single loop edge back 120 return this; 121 } 122 123 public int compareTo(Vertex o) { 124 return visits < o.visits ? 1 : -1; 125 } 126 127 private static class OutgoingEdge { 128 float weight; 129 Vertex destination; 130 OutgoingEdge next_outgoing_edge = null; 131 132 OutgoingEdge(Vertex destination, float weight) { 133 this.destination = destination; 134 this.weight = Math.max(0, weight); 135 } 136 } 137 138 private static class Segment { 139 Step segment_start; 140 Segment next_segment = null; 141 142 Segment(Step step) { 143 this.segment_start = step; 144 } 145 } 146 }