mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-12-19 07:00:35 +08:00
refactor: Enhance docs, code, add tests in PageRank (#6642)
This commit is contained in:
@@ -2,94 +2,306 @@ package com.thealgorithms.others;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
class PageRank {
|
||||
/**
|
||||
* PageRank Algorithm Implementation
|
||||
*
|
||||
* <p>
|
||||
* The PageRank algorithm is used by Google Search to rank web pages in their
|
||||
* search engine
|
||||
* results. It was named after Larry Page, one of the founders of Google.
|
||||
* PageRank is a way of
|
||||
* measuring the importance of website pages.
|
||||
*
|
||||
* <p>
|
||||
* Algorithm: 1. Initialize PageRank values for all pages to 1/N (where N is the
|
||||
* total number
|
||||
* of pages) 2. For each iteration: - For each page, calculate the new PageRank
|
||||
* by summing the
|
||||
* contributions from all incoming links - Apply the damping factor: PR(page) =
|
||||
* (1-d) + d *
|
||||
* sum(PR(incoming_page) / outgoing_links(incoming_page)) 3. Repeat until
|
||||
* convergence
|
||||
*
|
||||
* @see <a href="https://en.wikipedia.org/wiki/PageRank">PageRank Algorithm</a>
|
||||
*/
|
||||
public final class PageRank {
|
||||
|
||||
public static void main(String[] args) {
|
||||
int nodes;
|
||||
int i;
|
||||
int j;
|
||||
Scanner in = new Scanner(System.in);
|
||||
System.out.print("Enter the Number of WebPages: ");
|
||||
nodes = in.nextInt();
|
||||
PageRank p = new PageRank();
|
||||
System.out.println("Enter the Adjacency Matrix with 1->PATH & 0->NO PATH Between two WebPages: ");
|
||||
for (i = 1; i <= nodes; i++) {
|
||||
for (j = 1; j <= nodes; j++) {
|
||||
p.path[i][j] = in.nextInt();
|
||||
if (j == i) {
|
||||
p.path[i][j] = 0;
|
||||
}
|
||||
}
|
||||
private static final int MAX_NODES = 10;
|
||||
private static final double DEFAULT_DAMPING_FACTOR = 0.85;
|
||||
private static final int DEFAULT_ITERATIONS = 2;
|
||||
|
||||
private int[][] adjacencyMatrix;
|
||||
private double[] pageRankValues;
|
||||
private int nodeCount;
|
||||
|
||||
/**
|
||||
* Constructor to initialize PageRank with specified number of nodes
|
||||
*
|
||||
* @param numberOfNodes the number of nodes/pages in the graph
|
||||
* @throws IllegalArgumentException if numberOfNodes is less than 1 or greater
|
||||
* than MAX_NODES
|
||||
*/
|
||||
public PageRank(int numberOfNodes) {
|
||||
if (numberOfNodes < 1 || numberOfNodes > MAX_NODES) {
|
||||
throw new IllegalArgumentException("Number of nodes must be between 1 and " + MAX_NODES);
|
||||
}
|
||||
p.calc(nodes);
|
||||
this.nodeCount = numberOfNodes;
|
||||
this.adjacencyMatrix = new int[MAX_NODES][MAX_NODES];
|
||||
this.pageRankValues = new double[MAX_NODES];
|
||||
}
|
||||
|
||||
public int[][] path = new int[10][10];
|
||||
public double[] pagerank = new double[10];
|
||||
/**
|
||||
* Default constructor for interactive mode
|
||||
*/
|
||||
public PageRank() {
|
||||
this.adjacencyMatrix = new int[MAX_NODES][MAX_NODES];
|
||||
this.pageRankValues = new double[MAX_NODES];
|
||||
}
|
||||
|
||||
public void calc(double totalNodes) {
|
||||
double initialPageRank;
|
||||
double outgoingLinks = 0;
|
||||
double dampingFactor = 0.85;
|
||||
double[] tempPageRank = new double[10];
|
||||
int externalNodeNumber;
|
||||
int internalNodeNumber;
|
||||
int k = 1; // For Traversing
|
||||
int iterationStep = 1;
|
||||
initialPageRank = 1 / totalNodes;
|
||||
System.out.printf(" Total Number of Nodes :" + totalNodes + "\t Initial PageRank of All Nodes :" + initialPageRank + "\n");
|
||||
/**
|
||||
* Main method for interactive PageRank calculation
|
||||
*
|
||||
* @param args command line arguments (not used)
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try (Scanner scanner = new Scanner(System.in)) {
|
||||
System.out.print("Enter the Number of WebPages: ");
|
||||
int nodes = scanner.nextInt();
|
||||
|
||||
// 0th ITERATION _ OR _ INITIALIZATION PHASE //
|
||||
for (k = 1; k <= totalNodes; k++) {
|
||||
this.pagerank[k] = initialPageRank;
|
||||
}
|
||||
System.out.print("\n Initial PageRank Values , 0th Step \n");
|
||||
PageRank pageRank = new PageRank(nodes);
|
||||
System.out.println("Enter the Adjacency Matrix with 1->PATH & 0->NO PATH Between two WebPages: ");
|
||||
|
||||
for (k = 1; k <= totalNodes; k++) {
|
||||
System.out.printf(" Page Rank of " + k + " is :\t" + this.pagerank[k] + "\n");
|
||||
}
|
||||
|
||||
while (iterationStep <= 2) { // Iterations
|
||||
// Store the PageRank for All Nodes in Temporary Array
|
||||
for (k = 1; k <= totalNodes; k++) {
|
||||
tempPageRank[k] = this.pagerank[k];
|
||||
this.pagerank[k] = 0;
|
||||
for (int i = 1; i <= nodes; i++) {
|
||||
for (int j = 1; j <= nodes; j++) {
|
||||
int value = scanner.nextInt();
|
||||
pageRank.setEdge(i, j, value);
|
||||
}
|
||||
}
|
||||
|
||||
for (internalNodeNumber = 1; internalNodeNumber <= totalNodes; internalNodeNumber++) {
|
||||
for (externalNodeNumber = 1; externalNodeNumber <= totalNodes; externalNodeNumber++) {
|
||||
if (this.path[externalNodeNumber][internalNodeNumber] == 1) {
|
||||
k = 1;
|
||||
outgoingLinks = 0; // Count the Number of Outgoing Links for each externalNodeNumber
|
||||
while (k <= totalNodes) {
|
||||
if (this.path[externalNodeNumber][k] == 1) {
|
||||
outgoingLinks = outgoingLinks + 1; // Counter for Outgoing Links
|
||||
}
|
||||
k = k + 1;
|
||||
}
|
||||
// Calculate PageRank
|
||||
this.pagerank[internalNodeNumber] += tempPageRank[externalNodeNumber] * (1 / outgoingLinks);
|
||||
pageRank.calculatePageRank(nodes, DEFAULT_DAMPING_FACTOR, DEFAULT_ITERATIONS, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an edge in the adjacency matrix
|
||||
*
|
||||
* @param from source node (1-indexed)
|
||||
* @param to destination node (1-indexed)
|
||||
* @param value 1 if edge exists, 0 otherwise
|
||||
*/
|
||||
public void setEdge(int from, int to, int value) {
|
||||
if (from == to) {
|
||||
adjacencyMatrix[from][to] = 0; // No self-loops
|
||||
} else {
|
||||
adjacencyMatrix[from][to] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the adjacency matrix for the graph
|
||||
*
|
||||
* @param matrix the adjacency matrix (1-indexed)
|
||||
*/
|
||||
public void setAdjacencyMatrix(int[][] matrix) {
|
||||
for (int i = 1; i <= nodeCount; i++) {
|
||||
for (int j = 1; j <= nodeCount; j++) {
|
||||
setEdge(i, j, matrix[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the PageRank value for a specific node
|
||||
*
|
||||
* @param node the node index (1-indexed)
|
||||
* @return the PageRank value
|
||||
*/
|
||||
public double getPageRank(int node) {
|
||||
if (node < 1 || node > nodeCount) {
|
||||
throw new IllegalArgumentException("Node index out of bounds");
|
||||
}
|
||||
return pageRankValues[node];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all PageRank values
|
||||
*
|
||||
* @return array of PageRank values (1-indexed)
|
||||
*/
|
||||
public double[] getAllPageRanks() {
|
||||
return pageRankValues.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates PageRank using the default damping factor and iterations
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @return array of PageRank values
|
||||
*/
|
||||
public double[] calculatePageRank(int totalNodes) {
|
||||
return calculatePageRank(totalNodes, DEFAULT_DAMPING_FACTOR, DEFAULT_ITERATIONS, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates PageRank with custom parameters
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @param dampingFactor the damping factor (typically 0.85)
|
||||
* @param iterations number of iterations to perform
|
||||
* @param verbose whether to print detailed output
|
||||
* @return array of PageRank values
|
||||
*/
|
||||
public double[] calculatePageRank(int totalNodes, double dampingFactor, int iterations, boolean verbose) {
|
||||
validateInputParameters(totalNodes, dampingFactor, iterations);
|
||||
|
||||
this.nodeCount = totalNodes;
|
||||
double initialPageRank = 1.0 / totalNodes;
|
||||
|
||||
if (verbose) {
|
||||
System.out.printf("Total Number of Nodes: %d\tInitial PageRank of All Nodes: %.6f%n", totalNodes, initialPageRank);
|
||||
}
|
||||
|
||||
initializePageRanks(totalNodes, initialPageRank, verbose);
|
||||
performIterations(totalNodes, dampingFactor, iterations, verbose);
|
||||
|
||||
if (verbose) {
|
||||
System.out.println("\nFinal PageRank:");
|
||||
printPageRanks(totalNodes);
|
||||
}
|
||||
|
||||
return pageRankValues.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates input parameters for PageRank calculation
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @param dampingFactor the damping factor
|
||||
* @param iterations number of iterations
|
||||
* @throws IllegalArgumentException if parameters are invalid
|
||||
*/
|
||||
private void validateInputParameters(int totalNodes, double dampingFactor, int iterations) {
|
||||
if (totalNodes < 1 || totalNodes > MAX_NODES) {
|
||||
throw new IllegalArgumentException("Total nodes must be between 1 and " + MAX_NODES);
|
||||
}
|
||||
if (dampingFactor < 0 || dampingFactor > 1) {
|
||||
throw new IllegalArgumentException("Damping factor must be between 0 and 1");
|
||||
}
|
||||
if (iterations < 1) {
|
||||
throw new IllegalArgumentException("Iterations must be at least 1");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes PageRank values for all nodes
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @param initialPageRank the initial PageRank value
|
||||
* @param verbose whether to print output
|
||||
*/
|
||||
private void initializePageRanks(int totalNodes, double initialPageRank, boolean verbose) {
|
||||
for (int i = 1; i <= totalNodes; i++) {
|
||||
pageRankValues[i] = initialPageRank;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
System.out.println("\nInitial PageRank Values, 0th Step");
|
||||
printPageRanks(totalNodes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the iterative PageRank calculation
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @param dampingFactor the damping factor
|
||||
* @param iterations number of iterations
|
||||
* @param verbose whether to print output
|
||||
*/
|
||||
private void performIterations(int totalNodes, double dampingFactor, int iterations, boolean verbose) {
|
||||
for (int iteration = 1; iteration <= iterations; iteration++) {
|
||||
double[] tempPageRank = storeCurrentPageRanks(totalNodes);
|
||||
calculateNewPageRanks(totalNodes, tempPageRank);
|
||||
applyDampingFactor(totalNodes, dampingFactor);
|
||||
|
||||
if (verbose) {
|
||||
System.out.printf("%nAfter %d iteration(s)%n", iteration);
|
||||
printPageRanks(totalNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores current PageRank values in a temporary array
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @return temporary array with current PageRank values
|
||||
*/
|
||||
private double[] storeCurrentPageRanks(int totalNodes) {
|
||||
double[] tempPageRank = new double[MAX_NODES];
|
||||
for (int i = 1; i <= totalNodes; i++) {
|
||||
tempPageRank[i] = pageRankValues[i];
|
||||
pageRankValues[i] = 0;
|
||||
}
|
||||
return tempPageRank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates new PageRank values based on incoming links
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @param tempPageRank temporary array with previous PageRank values
|
||||
*/
|
||||
private void calculateNewPageRanks(int totalNodes, double[] tempPageRank) {
|
||||
for (int targetNode = 1; targetNode <= totalNodes; targetNode++) {
|
||||
for (int sourceNode = 1; sourceNode <= totalNodes; sourceNode++) {
|
||||
if (adjacencyMatrix[sourceNode][targetNode] == 1) {
|
||||
int outgoingLinks = countOutgoingLinks(sourceNode, totalNodes);
|
||||
if (outgoingLinks > 0) {
|
||||
pageRankValues[targetNode] += tempPageRank[sourceNode] / outgoingLinks;
|
||||
}
|
||||
}
|
||||
System.out.printf("\n After " + iterationStep + "th Step \n");
|
||||
|
||||
for (k = 1; k <= totalNodes; k++) {
|
||||
System.out.printf(" Page Rank of " + k + " is :\t" + this.pagerank[k] + "\n");
|
||||
}
|
||||
|
||||
iterationStep = iterationStep + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the Damping Factor to PageRank
|
||||
for (k = 1; k <= totalNodes; k++) {
|
||||
this.pagerank[k] = (1 - dampingFactor) + dampingFactor * this.pagerank[k];
|
||||
}
|
||||
/**
|
||||
* Applies the damping factor to all PageRank values
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
* @param dampingFactor the damping factor
|
||||
*/
|
||||
private void applyDampingFactor(int totalNodes, double dampingFactor) {
|
||||
for (int i = 1; i <= totalNodes; i++) {
|
||||
pageRankValues[i] = (1 - dampingFactor) + dampingFactor * pageRankValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Display PageRank
|
||||
System.out.print("\n Final Page Rank : \n");
|
||||
for (k = 1; k <= totalNodes; k++) {
|
||||
System.out.printf(" Page Rank of " + k + " is :\t" + this.pagerank[k] + "\n");
|
||||
/**
|
||||
* Counts the number of outgoing links from a node
|
||||
*
|
||||
* @param node the source node (1-indexed)
|
||||
* @param totalNodes total number of nodes
|
||||
* @return the count of outgoing links
|
||||
*/
|
||||
private int countOutgoingLinks(int node, int totalNodes) {
|
||||
int count = 0;
|
||||
for (int i = 1; i <= totalNodes; i++) {
|
||||
if (adjacencyMatrix[node][i] == 1) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the PageRank values for all nodes
|
||||
*
|
||||
* @param totalNodes the total number of nodes
|
||||
*/
|
||||
private void printPageRanks(int totalNodes) {
|
||||
for (int i = 1; i <= totalNodes; i++) {
|
||||
System.out.printf("PageRank of %d: %.6f%n", i, pageRankValues[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
319
src/test/java/com/thealgorithms/others/PageRankTest.java
Normal file
319
src/test/java/com/thealgorithms/others/PageRankTest.java
Normal file
@@ -0,0 +1,319 @@
|
||||
package com.thealgorithms.others;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test class for PageRank algorithm implementation
|
||||
*
|
||||
* @author Hardvan
|
||||
*/
|
||||
class PageRankTest {
|
||||
|
||||
private static final double EPSILON = 0.0001; // Tolerance for floating point comparisons
|
||||
|
||||
/**
|
||||
* Test basic PageRank calculation with a simple 3-node graph
|
||||
* Graph: 1 -> 2, 2 -> 3, 3 -> 1
|
||||
*/
|
||||
@Test
|
||||
void testSimpleThreeNodeGraph() {
|
||||
PageRank pageRank = new PageRank(3);
|
||||
|
||||
// Create a simple circular graph: 1 -> 2 -> 3 -> 1
|
||||
int[][] adjacencyMatrix = new int[10][10];
|
||||
adjacencyMatrix[1][2] = 1; // Node 1 links to Node 2
|
||||
adjacencyMatrix[2][3] = 1; // Node 2 links to Node 3
|
||||
adjacencyMatrix[3][1] = 1; // Node 3 links to Node 1
|
||||
|
||||
pageRank.setAdjacencyMatrix(adjacencyMatrix);
|
||||
double[] result = pageRank.calculatePageRank(3);
|
||||
|
||||
// All nodes should have equal PageRank in a circular graph
|
||||
assertNotNull(result);
|
||||
assertEquals(result[1], result[2], EPSILON);
|
||||
assertEquals(result[2], result[3], EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test PageRank with a two-node graph where one node points to another
|
||||
*/
|
||||
@Test
|
||||
void testTwoNodeGraph() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
|
||||
// Node 1 links to Node 2
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
|
||||
double[] result = pageRank.calculatePageRank(2);
|
||||
|
||||
// Node 2 should have higher PageRank than Node 1 (after 2 iterations)
|
||||
assertNotNull(result);
|
||||
assertEquals(0.2775, result[2], EPSILON);
|
||||
assertEquals(0.15, result[1], EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test PageRank with a single node (no links)
|
||||
*/
|
||||
@Test
|
||||
void testSingleNode() {
|
||||
PageRank pageRank = new PageRank(1);
|
||||
|
||||
double[] result = pageRank.calculatePageRank(1);
|
||||
|
||||
// Single node should have (1-d) = 0.15 after applying damping
|
||||
assertNotNull(result);
|
||||
assertEquals(0.15, result[1], EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test PageRank with a hub-and-spoke configuration
|
||||
* Node 1 is the hub, pointing to nodes 2, 3, and 4
|
||||
*/
|
||||
@Test
|
||||
void testHubAndSpokeGraph() {
|
||||
PageRank pageRank = new PageRank(4);
|
||||
|
||||
// Hub node (1) links to all other nodes
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
pageRank.setEdge(1, 3, 1);
|
||||
pageRank.setEdge(1, 4, 1);
|
||||
|
||||
// All spokes link back to hub
|
||||
pageRank.setEdge(2, 1, 1);
|
||||
pageRank.setEdge(3, 1, 1);
|
||||
pageRank.setEdge(4, 1, 1);
|
||||
|
||||
double[] result = pageRank.calculatePageRank(4);
|
||||
|
||||
assertNotNull(result);
|
||||
// Hub should have higher PageRank
|
||||
assertEquals(result[2], result[3], EPSILON);
|
||||
assertEquals(result[3], result[4], EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test PageRank with multiple iterations
|
||||
*/
|
||||
@Test
|
||||
void testMultipleIterations() {
|
||||
PageRank pageRank = new PageRank(3);
|
||||
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
pageRank.setEdge(2, 3, 1);
|
||||
pageRank.setEdge(3, 1, 1);
|
||||
|
||||
double[] result2Iterations = pageRank.calculatePageRank(3, 0.85, 2, false);
|
||||
double[] result5Iterations = pageRank.calculatePageRank(3, 0.85, 5, false);
|
||||
|
||||
assertNotNull(result2Iterations);
|
||||
assertNotNull(result5Iterations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getPageRank method for individual node
|
||||
*/
|
||||
@Test
|
||||
void testGetPageRank() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
pageRank.calculatePageRank(2);
|
||||
|
||||
double node1PageRank = pageRank.getPageRank(1);
|
||||
double node2PageRank = pageRank.getPageRank(2);
|
||||
|
||||
assertEquals(0.15, node1PageRank, EPSILON);
|
||||
assertEquals(0.2775, node2PageRank, EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getAllPageRanks method
|
||||
*/
|
||||
@Test
|
||||
void testGetAllPageRanks() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
pageRank.calculatePageRank(2);
|
||||
|
||||
double[] allPageRanks = pageRank.getAllPageRanks();
|
||||
|
||||
assertNotNull(allPageRanks);
|
||||
assertEquals(0.15, allPageRanks[1], EPSILON);
|
||||
assertEquals(0.2775, allPageRanks[2], EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that self-loops are not allowed
|
||||
*/
|
||||
@Test
|
||||
void testNoSelfLoops() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
|
||||
// Try to set a self-loop
|
||||
pageRank.setEdge(1, 1, 1);
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
|
||||
double[] result = pageRank.calculatePageRank(2);
|
||||
|
||||
assertNotNull(result);
|
||||
// Self-loop should be ignored
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exception when node count is too small
|
||||
*/
|
||||
@Test
|
||||
void testInvalidNodeCountTooSmall() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new PageRank(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exception when node count is too large
|
||||
*/
|
||||
@Test
|
||||
void testInvalidNodeCountTooLarge() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new PageRank(11));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exception for invalid damping factor (negative)
|
||||
*/
|
||||
@Test
|
||||
void testInvalidDampingFactorNegative() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> pageRank.calculatePageRank(2, -0.1, 2, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exception for invalid damping factor (greater than 1)
|
||||
*/
|
||||
@Test
|
||||
void testInvalidDampingFactorTooLarge() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> pageRank.calculatePageRank(2, 1.5, 2, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exception for invalid iterations (less than 1)
|
||||
*/
|
||||
@Test
|
||||
void testInvalidIterations() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> pageRank.calculatePageRank(2, 0.85, 0, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exception when getting PageRank for invalid node
|
||||
*/
|
||||
@Test
|
||||
void testGetPageRankInvalidNode() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
pageRank.calculatePageRank(2);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> pageRank.getPageRank(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exception when getting PageRank for node less than 1
|
||||
*/
|
||||
@Test
|
||||
void testGetPageRankNodeLessThanOne() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
pageRank.calculatePageRank(2);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> pageRank.getPageRank(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test complex graph with multiple incoming and outgoing links
|
||||
*/
|
||||
@Test
|
||||
void testComplexGraph() {
|
||||
PageRank pageRank = new PageRank(4);
|
||||
|
||||
// Create a more complex graph
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
pageRank.setEdge(1, 3, 1);
|
||||
pageRank.setEdge(2, 3, 1);
|
||||
pageRank.setEdge(3, 4, 1);
|
||||
pageRank.setEdge(4, 1, 1);
|
||||
|
||||
double[] result = pageRank.calculatePageRank(4);
|
||||
|
||||
assertNotNull(result);
|
||||
// Node 3 should have high PageRank (receives links from nodes 1 and 2)
|
||||
// After 2 iterations, the sum will not equal total nodes
|
||||
double sum = result[1] + result[2] + result[3] + result[4];
|
||||
assertEquals(1.8325, sum, EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that PageRank values sum after 2 iterations
|
||||
*/
|
||||
@Test
|
||||
void testPageRankSum() {
|
||||
PageRank pageRank = new PageRank(5);
|
||||
|
||||
// Create arbitrary graph
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
pageRank.setEdge(2, 3, 1);
|
||||
pageRank.setEdge(3, 4, 1);
|
||||
pageRank.setEdge(4, 5, 1);
|
||||
pageRank.setEdge(5, 1, 1);
|
||||
|
||||
double[] result = pageRank.calculatePageRank(5);
|
||||
|
||||
double sum = 0;
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
sum += result[i];
|
||||
}
|
||||
|
||||
// Sum after 2 iterations with default damping factor
|
||||
assertEquals(2.11, sum, EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test graph with isolated node (no incoming or outgoing links)
|
||||
*/
|
||||
@Test
|
||||
void testGraphWithIsolatedNode() {
|
||||
PageRank pageRank = new PageRank(3);
|
||||
|
||||
// Node 1 and 2 are connected, Node 3 is isolated
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
pageRank.setEdge(2, 1, 1);
|
||||
|
||||
double[] result = pageRank.calculatePageRank(3);
|
||||
|
||||
assertNotNull(result);
|
||||
// Isolated node should have some PageRank due to damping factor
|
||||
assertEquals(0.15, result[3], EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test verbose mode (should not throw exception)
|
||||
*/
|
||||
@Test
|
||||
void testVerboseMode() {
|
||||
PageRank pageRank = new PageRank(2);
|
||||
|
||||
pageRank.setEdge(1, 2, 1);
|
||||
|
||||
// This should execute without throwing an exception
|
||||
double[] result = pageRank.calculatePageRank(2, 0.85, 2, true);
|
||||
|
||||
assertNotNull(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user