Поиск пути Java в общих деревьях — часть 3/4: демонстрация

  • Поиск путей Java в общих деревьях. Часть 1/4: классы моделей
  • Поиск пути Java в общих деревьях — Часть 2/4: алгоритмы
  • Поиск пути Java в общих деревьях — часть 3/4: демонстрация (этот пост)
  • Поиск пути Java в общих деревьях — часть 4/4: модульные тесты

В этом посте представлены средства для проведения демонстрации.

com.github.coderodde.pathfinding.StarTreeBuilder.java:

package com.github.coderodde.pathfinding;

import com.github.coderodde.pathfinding.WeightedTree.WeightedTreeNode;
import java.util.Objects;
import java.util.Random;

/**
 * This class is responsible for creating a star-shaped tree.
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.6 (Nov 5, 2022)
 * @since 1.6 (Nov 5, 2022)
 */
public final class StarTreeBuilder {

    private final int degree;
    private final int radius;
    private final Random random;

    private WeightedTree tree;
    private int currentId;

    public StarTreeBuilder(int degree, int radius, Random random) {
        this.degree = checkDegree(degree);
        this.radius = checkRadius(radius);
        this.random = Objects.requireNonNull(random, "Random is null.");
    }

    public WeightedTree build() {
        tree = new WeightedTree();
        currentId = 0;

        WeightedTreeNode root = tree.addTreeNode(currentId++);

        if (radius == 0) {
            return tree;
        }

        for (int i = 0; i < degree; i++) {
            WeightedTreeNode node = tree.addTreeNode(currentId++);
            tree.connect(root.getId(), node.getId(), random.nextDouble());
            createWeightedTreeUtil(node, radius - 1);
        }

        return tree;
    }

    private void createWeightedTreeUtil(WeightedTreeNode node, int radius) {
        if (radius == -1) {
            return;
        }

        for (int i = 0; i < degree - 1; i++) {
            WeightedTreeNode newNode = tree.addTreeNode(currentId++);

            tree.connect(newNode.getId(), node.getId(), random.nextDouble());

            createWeightedTreeUtil(newNode, radius - 1);
        }
    }

    private int checkDegree(int degree) {
        if (degree < 2) {
            throw new IllegalArgumentException(
                    "The degree is too small: "
                            + degree 
                            + ". Must be at least 2.");
        }

        return degree;
    }

    private int checkRadius(int radius) {
        if (radius < 0) {
            throw new IllegalArgumentException(
                    "The radius is too small: "
                            + radius 
                            + ". Must be at least 0.");
        }

        return radius;
    }
}

com.github.coderodde.pathfinding.Demo.java:

package com.github.coderodde.pathfinding;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public final class Demo {

    private static final int RADIUS = 12;
    private static final int DEGREE = 4;

    private static final List<Pathfinder> pathfinders = new ArrayList<>(5);

    static {
        pathfinders.add(new BreadthFirstSearchPathfinder());
        pathfinders.add(new BidirectionalBreadthFirstSearchPathfinder());
        pathfinders.add(new DepthFirstSearchPathfinder());
        pathfinders.add(new IterativeDeepeningDepthFirstSearchPathfinder());

        pathfinders.add(
            new BidirectionalIterativeDeepeningDepthFirstSearchPathfinder());
    }

    public static void main(String[] args) {
        long seed = System.nanoTime();
        Random random = new Random(seed);
        System.out.println("<<< Seed = " + seed + " >>>");

        long startTime = System.currentTimeMillis();
        WeightedTree tree = new StarTreeBuilder(DEGREE, RADIUS, random).build();
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;

        System.out.println("Built the tree in " + duration + " milliseconds.");
        System.out.println(
                "Number of nodes in the tree: " + tree.getNumberOfNodes());

        startTime = System.currentTimeMillis();
        boolean isCyclic = tree.isCyclic();
        endTime = System.currentTimeMillis();
        duration = endTime - startTime;

        System.out.println("The tree candidate is cyclic: " + isCyclic);
        System.out.println(
                "Acyclicity check in " 
                        + duration 
                        + " milliseconds.");

        startTime = System.currentTimeMillis();
        warmup(tree, new Random(seed + 1L));
        endTime = System.currentTimeMillis();
        duration = endTime - startTime;

        System.out.println("Warmup in " + duration + " milliseconds");

        startTime = System.currentTimeMillis();
        benchmark(tree, new Random(seed + 1L));
        endTime = System.currentTimeMillis();
        duration = endTime - startTime;

        System.out.println("Benchmark in " + duration + " milliseconds");
    }

    private static void warmup(WeightedTree tree, Random random) {
        run(tree, false, random);
    }

    private static void benchmark(WeightedTree tree, Random random) {
        run(tree, true, random);
    }

    private static void run(WeightedTree tree, boolean print, Random random) {
        int sourceNodeId = random.nextInt(tree.getNumberOfNodes());
        int targetNodeId = random.nextInt(tree.getNumberOfNodes());

        if (print) {
            System.out.println("Source: " + tree.getNode(sourceNodeId));
            System.out.println("Target: " + tree.getNode(targetNodeId));
        }

        List<WeightedPath> paths = new ArrayList<>();

        if (print) {
            System.out.println("---------------------------------------------");
        }

        for (Pathfinder pathfinder : pathfinders) {
            long startTime = System.currentTimeMillis();
            WeightedPath path = pathfinder.search(tree,
                                                  sourceNodeId, 
                                                  targetNodeId);
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            paths.add(path);

            if (print) {
                System.out.println(
                        pathfinder.getClass().getSimpleName() 
                                + " in " 
                                + duration 
                                + " milliseconds.");
            }
        }

        if (print) {
            System.out.println("---------------------------------------------");
        }

        if (print) {
            boolean pathsEqual = pathsAreEqual(paths);

            if (!pathsEqual) {
                System.out.println("Path mismatch!");
            } else {
                System.out.println("Algorithms agree on a path.");
                System.out.println();
                System.out.println("Shortest path:");
                System.out.println(paths.get(0));
                System.out.println(
                        "Shortest path distance: " 
                                + paths.get(0).getTotalCost());
            }
        }
    }

    private static boolean pathsAreEqual(List<WeightedPath> paths) {
        for (int i = 0; i < paths.size() - 1; i++) {
            if (!paths.get(i).equals(paths.get(i + 1))) {
                return false;
            }
        }

        return true;
    }
}

Типичный вывод

<<< Seed = 103563124048700 >>>
Built the tree in 2309 milliseconds.
Number of nodes in the tree: 3188645
The tree candidate is cyclic: false
Acyclicity check in 1024 milliseconds.
Warmup in 1713 milliseconds
Source: [WeightedTreeNode, id = 1122646]
Target: [WeightedTreeNode, id = 485067]
---------------------------------------------
BreadthFirstSearchPathfinder in 638 milliseconds.
BidirectionalBreadthFirstSearchPathfinder in 3 milliseconds.
DepthFirstSearchPathfinder in 110 milliseconds.
IterativeDeepeningDepthFirstSearchPathfinder in 512 milliseconds.
BidirectionalIterativeDeepeningDepthFirstSearchPathfinder in 4 milliseconds.
---------------------------------------------
Algorithms agree on a path.

Shortest path:
[WeightedTreeNode, id = 1122646]
[WeightedTreeNode, id = 1122644]
[WeightedTreeNode, id = 1122639]
[WeightedTreeNode, id = 1122625]
[WeightedTreeNode, id = 1122544]
[WeightedTreeNode, id = 1122301]
[WeightedTreeNode, id = 1121936]
[WeightedTreeNode, id = 1121935]
[WeightedTreeNode, id = 1121934]
[WeightedTreeNode, id = 1121933]
[WeightedTreeNode, id = 1062884]
[WeightedTreeNode, id = 1062883]
[WeightedTreeNode, id = 797162]
[WeightedTreeNode, id = 0]
[WeightedTreeNode, id = 1]
[WeightedTreeNode, id = 265722]
[WeightedTreeNode, id = 442869]
[WeightedTreeNode, id = 472394]
[WeightedTreeNode, id = 482236]
[WeightedTreeNode, id = 482237]
[WeightedTreeNode, id = 484424]
[WeightedTreeNode, id = 484789]
[WeightedTreeNode, id = 485032]
[WeightedTreeNode, id = 485033]
[WeightedTreeNode, id = 485060]
[WeightedTreeNode, id = 485065]
[WeightedTreeNode, id = 485067]

Shortest path distance: 15.283136830490866
Benchmark in 1281 milliseconds

Запрос критики

Как всегда, пожалуйста, расскажите мне все, что приходит на ум.

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *