All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cicirello.examples.jpt.RandomIndexerTimes Maven / Gradle / Ivy

Go to download

This package contains several example programs of the usage of the JavaPermutationTools (JPT) library. JPT is a Java library that enables representing and generating permutations and sequences, as well as performing computation on permutations and sequences. It includes implementations of a variety of permutation distance metrics as well as distance metrics on sequences (i.e., Strings, arrays, and other ordered data types). In addition to programs demonstrating the usage of the JPT library, the jpt-examples package also contains programs for replicating the experiments from a few published papers that utilized the library or implementations on which the library is based. JPT's source code is maintained on GitHub, and the prebuilt jars of the library can be imported from Maven Central using maven or other build tools. The purpose of the package jpt-examples is to demonstrate usage of the major functionality of the JPT library. You can find out more about the JPT library itself from its website: https://jpt.cicirello.org/.

The newest version!
/*
 * Example programs for JavaPermutationTools library.
 * Copyright (C) 2019-2023 Vincent A. Cicirello
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package org.cicirello.examples.jpt;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom;
import org.cicirello.math.rand.RandomIndexer;
import org.cicirello.math.stats.Statistics;

/**
 * Simple program comparing CPU time of RandomIndexer.nextInt vs ThreadLocalRandom.nextInt to check
 * whether there is a time advantage to using it for small bounds, as is commonly encountered as
 * array indexes; and whether there is a time disadvantage for larger bounds. There is an optional
 * command line argument, which is used to do the timing with multiple threads to test whether
 * threading affects runtime. To use that command line argument, simply pass an integer value for
 * the number of threads via the command line.
 *
 * @author Vincent A. Cicirello, https://www.cicirello.org/
 */
public class RandomIndexerTimes {

  private static final int N = 1000000;
  private static final int TRIALS = 100;

  /**
   * Runs the example program.
   *
   * @param args The command line argument is optional. If specified, uses multiple threads where
   *     the command line parameter is the number of threads.
   */
  public static void main(String[] args) {
    ExamplesShared.printCopyrightAndLicense();

    final int NUM_THREADS = args.length > 0 ? Integer.parseInt(args[0]) : 0;
    if (NUM_THREADS > 0) {
      timeWithThreads(NUM_THREADS);
      System.exit(0);
    }

    ThreadMXBean bean = ManagementFactory.getThreadMXBean();

    // Attempt to "warm-up" Java's JIT compiler.
    for (int bound = 2; bound <= 512; bound *= 2) {
      for (int j = 0; j < 100000; j++) {
        RandomIndexer.nextInt(bound - 1);
        RandomIndexer.nextInt(bound);
        RandomIndexer.nextInt(bound + 1);
        ThreadLocalRandom.current().nextInt(bound - 1);
        ThreadLocalRandom.current().nextInt(bound);
        ThreadLocalRandom.current().nextInt(bound + 1);
      }
    }

    @SuppressWarnings("unchecked")
    ArrayList[] msLowBound = new ArrayList[2];
    msLowBound[0] = new ArrayList();
    msLowBound[1] = new ArrayList();
    @SuppressWarnings("unchecked")
    ArrayList[] msHighBound = new ArrayList[2];
    msHighBound[0] = new ArrayList();
    msHighBound[1] = new ArrayList();
    @SuppressWarnings("unchecked")
    ArrayList[] msPow2Bound = new ArrayList[2];
    msPow2Bound[0] = new ArrayList();
    msPow2Bound[1] = new ArrayList();
    System.out.printf("%6s\t%10s\t%10s\t%10s\t%10s%n", "Bound", "TLR", "RI", "t", "dof");
    for (int bound = 1; bound <= 512; bound++) {
      double[][] ms = new double[2][TRIALS];
      for (int j = 0; j < TRIALS; j++) {
        long start = bean.getCurrentThreadCpuTime();
        for (int i = 0; i < N; i++) {
          ThreadLocalRandom.current().nextInt(bound);
        }
        long middle = bean.getCurrentThreadCpuTime();
        for (int i = 0; i < N; i++) {
          RandomIndexer.nextInt(bound);
        }
        long end = bean.getCurrentThreadCpuTime();
        ms[0][j] = (middle - start) / 1000000.0;
        ms[1][j] = (end - middle) / 1000000.0;
      }
      if ((bound & (bound - 1)) != 0) {
        if (bound <= 256) {
          msLowBound[0].add(ms[0]);
          msLowBound[1].add(ms[1]);
        } else {
          msHighBound[0].add(ms[0]);
          msHighBound[1].add(ms[1]);
        }
      } else {
        msPow2Bound[0].add(ms[0]);
        msPow2Bound[1].add(ms[1]);
      }
      Number[] tTest = Statistics.tTestWelch(ms[0], ms[1]);
      double t = tTest[0].doubleValue();
      int dof = tTest[1].intValue();
      // times are converted to seconds during output
      System.out.printf(
          "%6d\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
          bound, Statistics.mean(ms[0]) / 1000, Statistics.mean(ms[1]) / 1000, t, dof);
    }
    double[] a0 = toArray(msLowBound[0]);
    double[] a1 = toArray(msLowBound[1]);
    Number[] tTest = Statistics.tTestWelch(a0, a1);
    double t = tTest[0].doubleValue();
    int dof = tTest[1].intValue();
    // times are converted to seconds during output
    System.out.printf(
        "%6s\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
        "LOW", Statistics.mean(a0) / 1000, Statistics.mean(a1) / 1000, t, dof);
    a0 = toArray(msHighBound[0]);
    a1 = toArray(msHighBound[1]);
    tTest = Statistics.tTestWelch(a0, a1);
    t = tTest[0].doubleValue();
    dof = tTest[1].intValue();
    // times are converted to seconds during output
    System.out.printf(
        "%6s\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
        "HIGH", Statistics.mean(a0) / 1000, Statistics.mean(a1) / 1000, t, dof);
    a0 = toArray(msPow2Bound[0]);
    a1 = toArray(msPow2Bound[1]);
    tTest = Statistics.tTestWelch(a0, a1);
    t = tTest[0].doubleValue();
    dof = tTest[1].intValue();
    // times are converted to seconds during output
    System.out.printf(
        "%6s\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
        "POW2", Statistics.mean(a0) / 1000, Statistics.mean(a1) / 1000, t, dof);
  }

  private static void timeWithThreads(final int NUM_THREADS) {
    // Attempt to "warm-up" Java's JIT compiler.
    for (int bound = 2; bound <= 512; bound *= 2) {
      int j = 100000;
      Thread t1 = new RandomIndexerTimeThread(bound - 1, j / NUM_THREADS);
      t1.start();
      Thread t2 = new RandomIndexerTimeThread(bound, j / NUM_THREADS);
      t2.start();
      Thread t3 = new RandomIndexerTimeThread(bound + 1, j / NUM_THREADS);
      t3.start();
      try {
        t1.join();
        t2.join();
        t3.join();
      } catch (InterruptedException e) {
        System.out.println(e);
        System.exit(0);
      }
      t1 = new ThreadLocalRandomTimeThread(bound - 1, j / NUM_THREADS);
      t1.start();
      t2 = new ThreadLocalRandomTimeThread(bound, j / NUM_THREADS);
      t2.start();
      t3 = new ThreadLocalRandomTimeThread(bound + 1, j / NUM_THREADS);
      t3.start();
      try {
        t1.join();
        t2.join();
        t3.join();
      } catch (InterruptedException e) {
        System.out.println(e);
        System.exit(0);
      }
    }

    @SuppressWarnings("unchecked")
    ArrayList[] msLowBound = new ArrayList[2];
    msLowBound[0] = new ArrayList();
    msLowBound[1] = new ArrayList();
    @SuppressWarnings("unchecked")
    ArrayList[] msHighBound = new ArrayList[2];
    msHighBound[0] = new ArrayList();
    msHighBound[1] = new ArrayList();
    @SuppressWarnings("unchecked")
    ArrayList[] msPow2Bound = new ArrayList[2];
    msPow2Bound[0] = new ArrayList();
    msPow2Bound[1] = new ArrayList();
    System.out.printf("%6s\t%10s\t%10s\t%10s\t%10s%n", "Bound", "TLR", "RI", "t", "dof");
    System.out.flush();
    for (int bound = 1; bound <= 512; bound++) {
      double[][] ms = new double[2][TRIALS];
      for (int j = 0; j < TRIALS; j++) {
        Thread[] t1 = new Thread[NUM_THREADS];
        Thread[] t2 = new Thread[NUM_THREADS];
        for (int x = 0; x < NUM_THREADS; x++) {
          t1[x] = new ThreadLocalRandomTimeThread(bound, N / NUM_THREADS);
          t2[x] = new RandomIndexerTimeThread(bound, N / NUM_THREADS);
        }
        long start = System.nanoTime();
        for (Thread s : t1) {
          s.start();
        }
        try {
          for (Thread s : t1) {
            s.join();
          }
        } catch (InterruptedException e) {
          System.out.println(e);
          System.exit(0);
        }
        long middle = System.nanoTime();
        for (Thread s : t2) {
          s.start();
        }
        try {
          for (Thread s : t2) {
            s.join();
          }
        } catch (InterruptedException e) {
          System.out.println(e);
          System.exit(0);
        }
        long end = System.nanoTime();
        ms[0][j] = (middle - start) / 1000000.0;
        ms[1][j] = (end - middle) / 1000000.0;
      }
      if ((bound & (bound - 1)) != 0) {
        if (bound <= 256) {
          msLowBound[0].add(ms[0]);
          msLowBound[1].add(ms[1]);
        } else {
          msHighBound[0].add(ms[0]);
          msHighBound[1].add(ms[1]);
        }
      } else {
        msPow2Bound[0].add(ms[0]);
        msPow2Bound[1].add(ms[1]);
      }
      Number[] tTest = Statistics.tTestWelch(ms[0], ms[1]);
      double t = tTest[0].doubleValue();
      int dof = tTest[1].intValue();
      // times are converted to seconds during output
      System.out.printf(
          "%6d\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
          bound, Statistics.mean(ms[0]) / 1000, Statistics.mean(ms[1]) / 1000, t, dof);
      System.out.flush();
    }
    double[] a0 = toArray(msLowBound[0]);
    double[] a1 = toArray(msLowBound[1]);
    Number[] tTest = Statistics.tTestWelch(a0, a1);
    double t = tTest[0].doubleValue();
    int dof = tTest[1].intValue();
    // times are converted to seconds during output
    System.out.printf(
        "%6s\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
        "LOW", Statistics.mean(a0) / 1000, Statistics.mean(a1) / 1000, t, dof);
    a0 = toArray(msHighBound[0]);
    a1 = toArray(msHighBound[1]);
    tTest = Statistics.tTestWelch(a0, a1);
    t = tTest[0].doubleValue();
    dof = tTest[1].intValue();
    // times are converted to seconds during output
    System.out.printf(
        "%6s\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
        "HIGH", Statistics.mean(a0) / 1000, Statistics.mean(a1) / 1000, t, dof);
    a0 = toArray(msPow2Bound[0]);
    a1 = toArray(msPow2Bound[1]);
    tTest = Statistics.tTestWelch(a0, a1);
    t = tTest[0].doubleValue();
    dof = tTest[1].intValue();
    // times are converted to seconds during output
    System.out.printf(
        "%6s\t%10.7f\t%10.7f\t%10.4f\t%10d%n",
        "POW2", Statistics.mean(a0) / 1000, Statistics.mean(a1) / 1000, t, dof);
  }

  private static final class RandomIndexerTimeThread extends Thread {
    private final int bound;
    private final int samples;

    public RandomIndexerTimeThread(int bound, int samples) {
      this.bound = bound;
      this.samples = samples;
    }

    public void run() {
      for (int i = 0; i < samples; i++) {
        RandomIndexer.nextInt(bound);
      }
    }
  }

  private static final class ThreadLocalRandomTimeThread extends Thread {
    private final int bound;
    private final int samples;

    public ThreadLocalRandomTimeThread(int bound, int samples) {
      this.bound = bound;
      this.samples = samples;
    }

    public void run() {
      for (int i = 0; i < samples; i++) {
        ThreadLocalRandom.current().nextInt(bound);
      }
    }
  }

  private static double[] toArray(ArrayList from) {
    int n = 0;
    for (double[] e : from) n += e.length;
    double[] a = new double[n];
    int i = 0;
    for (double[] e : from) {
      for (int j = 0; j < e.length; j++) {
        a[i] = e[j];
        i++;
      }
    }
    return a;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy