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

org.jenetics.internal.util.DieHarder Maven / Gradle / Ivy

There is a newer version: 3.6.0
Show newest version
/*
 * Java Genetic Algorithm Library (jenetics-3.2.0).
 * Copyright (c) 2007-2015 Franz Wilhelmstötter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *    Franz Wilhelmstötter ([email protected])
 */
package org.jenetics.internal.util;

import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static java.util.regex.Pattern.quote;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static org.jenetics.internal.util.Equality.eq;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.Random;

import org.jenetics.internal.util.DieHarder.Result.Assessment;

/**
 * Class for testing a given random engine using the
 * dieharder
 * test application.
 *
 * @author Franz Wilhelmstötter
 * @since 1.5
 * @version 3.0
 */
public final class DieHarder {

	/**
	 * Writes random numbers to an given data output stream.
	 *
	 * @author Franz Wilhelmstötter
	 * @since 1.5
	 * @version 3.0
	 */
	private static final class Randomizer implements Runnable {
		private final Random _random;
		private final CountingOutputStream _out;

		Randomizer(final Random random, final OutputStream out) {
			_random = requireNonNull(random);
			_out = new CountingOutputStream(out);
		}

		@Override
		public void run() {
			try {
				final byte[] data = new byte[4096];
				while (!Thread.currentThread().isInterrupted()) {
					_random.nextBytes(data);
					_out.write(data);
				}
			} catch (IOException ignore) {
			}
		}

		long getCount() {
			return _out.getCount();
		}
	}

	public static void main(final String[] args) throws Exception {
		if ( args.length < 1) {
			println("Usage: java org.jenetics.internal.util.DieHarder ");
			return;
		}

		final String randomName = args[0];
		Random random = null;
		try {
			random = (Random)Class.forName(randomName).newInstance();
			printt(
				"Testing: %s (%s)",
				randomName,
				new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date())
			);
		} catch (Exception e) {
			System.out.println("Can't create random class " + randomName);
			return;
		}

		final List dieharderArgs = new ArrayList<>();
		dieharderArgs.add("dieharder");
		for (int i = 1; i < args.length; ++i) {
			dieharderArgs.add(args[i]);
		}
		dieharderArgs.add("-g");
		dieharderArgs.add("200");

		printv();

		final long start = System.currentTimeMillis();
		final ProcessBuilder builder = new ProcessBuilder(dieharderArgs);
		final Process dieharder = builder.start();

		final Randomizer randomizer = new Randomizer(
			random,
			dieharder.getOutputStream()
		);
		final Thread randomizerThread = new Thread(randomizer);
		randomizerThread.start();

		// The dieharder console output.
		final BufferedReader stdout = new BufferedReader (
			new InputStreamReader(dieharder.getInputStream())
		);

		final List results = new ArrayList<>();
		for (String l = stdout.readLine(); l != null; l = stdout.readLine()) {
			Result.parse(l).ifPresent(results::add);
			System.out.println(l);
		}

		dieharder.waitFor();
		randomizerThread.interrupt();

		final long millis = System.currentTimeMillis() - start;
		final long sec = (millis)/1000;
		final double megaBytes = randomizer.getCount()/(1024.0*1024.0);

		// Calculate statistics.
		final Map grouped = results.stream()
			.collect(groupingBy(r -> r.assessment, counting()));

		final long passed = grouped.getOrDefault(Assessment.PASSED, 0L);
		final long weak = grouped.getOrDefault(Assessment.WEAK, 0L);
		final long failed = grouped.getOrDefault(Assessment.FAILED, 0L);

		final NumberFormat formatter = NumberFormat.getIntegerInstance();
		formatter.setMinimumFractionDigits(3);
		formatter.setMaximumFractionDigits(3);

		println("#=============================================================================#");
		println(
			"# %-76s#",
			format("Summary: PASSED=%d, WEAK=%d, FAILED=%d", passed, weak, failed)
		);
		println(
			"# %-76s#",
			format("         %s MB of random data created with %s MB/sec",
				formatter.format(megaBytes),
				formatter.format(megaBytes/(millis/1000.0))
			)
		);
		println("#=============================================================================#");
		printt("Runtime: %d:%02d:%02d", sec/3600, (sec%3600)/60, (sec%60));

	}

	private static void printt(final String title, final Object... args) {
		println("#=============================================================================#");
		println("# %-76s#", format(title, args));
		println("#=============================================================================#");
	}

	private static void printv() {
		println("#=============================================================================#");
		println(
			"# %-76s#",
			format("%s %s (%s) ", p("os.name"), p("os.version"), p("os.arch"))
		);
		println(
			"# %-76s#",
			format("java version \"%s\"", p("java.version"))
		);
		println(
			"# %-76s#",
			format("%s (build %s)", p("java.runtime.name"), p("java.runtime.version"))
		);
		println(
			"# %-76s#",
			format("%s (build %s)", p("java.vm.name"), p("java.vm.version"))
		);
		println("#=============================================================================#");
	}

	private static String p(final String name) {
		return System.getProperty(name);
	}

	private static void println(final String pattern, final Object... args) {
		System.out.println(format(pattern, args));
	}



	/**
	 * Represents one DieHarder test result.
	 *
	 * @author Franz Wilhelmstötter
	 * @since 3.0
	 * @version 3.0
	 */
	static final class Result {

		static enum Assessment {
			PASSED,
			FAILED,
			WEAK;

			static Optional of(final String assessment) {
				switch (assessment) {
					case "PASSED": return Optional.of(PASSED);
					case "FAILED": return Optional.of(FAILED);
					case "WEAK": return Optional.of(WEAK);
					default: return Optional.empty();
				}
			}
		}

		final String testName;
		final int ntup;
		final int tsamples;
		final int psamples;
		final double pvalue;
		final Assessment assessment;

		private Result(
			final String testName,
			final int ntup,
			final int tsamples,
			final int psamples,
			final double pvalue,
			final Assessment assessment
		) {
			this.testName = testName;
			this.ntup = ntup;
			this.tsamples = tsamples;
			this.psamples = psamples;
			this.pvalue = pvalue;
			this.assessment = assessment;
		}

		static Optional parse(final String line) {
			final String[] parts = line.split(quote("|"));

			if (parts.length == 6) {
				final String name = parts[0].trim();
				final OptionalInt ntup = toOptionalInt(parts[1].trim());
				final OptionalInt tsamples = toOptionalInt(parts[2].trim());
				final OptionalInt psamples = toOptionalInt(parts[3].trim());
				final OptionalDouble pvalue = toOptionalDouble(parts[4].trim());
				final Optional assessment = Assessment.of(parts[5].trim());

				if (ntup.isPresent() &&
					tsamples.isPresent() &&
					psamples.isPresent() &&
					pvalue.isPresent() &&
					assessment.isPresent())
				{
					return Optional.of(new Result(
						name,
						ntup.getAsInt(),
						tsamples.getAsInt(),
						psamples.getAsInt(),
						pvalue.getAsDouble(),
						assessment.get()
					));
				}
			}

			return Optional.empty();
		}

		private static OptionalInt toOptionalInt(final String value) {
			try {
				return OptionalInt.of(Integer.parseInt(value));
			} catch (NumberFormatException e) {
				return OptionalInt.empty();
			}
		}

		private static OptionalDouble toOptionalDouble(final String value) {
			try {
				return OptionalDouble.of(Double.parseDouble(value));
			} catch (NumberFormatException e) {
				return OptionalDouble.empty();
			}
		}

		@Override
		public int hashCode() {
			return Hash.of(getClass())
				.and(testName)
				.and(ntup)
				.and(tsamples)
				.and(psamples)
				.and(pvalue)
				.and(assessment).value();
		}

		@Override
		public boolean equals(final Object obj) {
			return Equality.of(this, obj).test(result ->
				eq(testName, result.testName) &&
				eq(ntup, result.ntup) &&
				eq(tsamples, result.tsamples) &&
				eq(psamples, result.psamples) &&
				eq(pvalue, result.psamples) &&
				eq(assessment, result.assessment)
			);
		}

		@Override
		public String toString() {
			return format(
				"%s[ntup=%d, tsamples=%d, psamples=%d, pvalue=%f, assessment=%s]",
				testName, ntup, tsamples, psamples, pvalue, assessment
			);
		}
	}

	/**
	 * Counts the written bytes.
	 *
	 * @author Franz Wilhelmstötter
	 * @since 3.0
	 * @version 3.0
	 */
	private static final class CountingOutputStream extends OutputStream {
		private final OutputStream _delegate;
		private long _count;

		CountingOutputStream(final OutputStream delegate) {
			_delegate = requireNonNull(delegate);
		}

		@Override
		public void write(final byte[] b) throws IOException {
			_delegate.write(b);
			_count += b.length;
		}

		@Override
		public void write(final byte[] b, final int offset, final int length)
			throws IOException
		{
			_delegate.write(b, offset, length);
			_count += length;
		}

		@Override
		public void write(final int b) throws IOException {
			_delegate.write(b);
			_count += 1;
		}

		long getCount() {
			return _count;
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy