//ProjectEulerTS/Benchmark.ts //Matthew Ellison // Created: 10-18-20 //Modified: 03-29-21 //This runs the benchmark functions for the Java version of the ProjectEuler project //readline-sync is used to get input from the user in a procedural maner and can be installed with "npm install -g readline-sync" /* Copyright (C) 2021 Matthew Ellison This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ const readlineSync = require("readline-sync"); import { Problem } from "./Problems/Problem"; import { Stopwatch } from "../../Typescript/typescriptClasses/Stopwatch"; import { ProblemSelection } from "./ProblemSelection"; enum BenchmarkOptions{runSpecific = 1, runAllShort, runAll, exit, size}; export class Benchmark{ private static tooLong: number[] = [14, 15, 23, 24, 25]; //The driver function for the benchmark selection public static benchmarkMenu(): void{ let selection: BenchmarkOptions = BenchmarkOptions.size; Benchmark.printMenu(); selection = Benchmark.getMenuSelection(); switch(selection){ case BenchmarkOptions.runSpecific: Benchmark.runSpecific(); break; case BenchmarkOptions.runAllShort: Benchmark.runAllShort(); break; case BenchmarkOptions.runAll: Benchmark.runAll(); break; case BenchmarkOptions.exit: break; case BenchmarkOptions.size: break; } } //Print the benchmark menu private static printMenu(): void{ console.log("1. Run a specific problem"); console.log("2. Run all problems that have a reasonably short run time"); console.log("3. Run all problems"); console.log("4. Exit the menu"); console.log(); } //Returns a valid menu option private static getMenuSelection(): BenchmarkOptions{ let selection: number; let sel: string = readlineSync.question(""); while(!Benchmark.isValidMenu(sel)){ console.log("That is an invalid option!\n"); Benchmark.printMenu(); selection = Benchmark.getMenuSelection(); } selection = parseInt(sel); return selection; } //Determines if a value is a valid menu option. Helper for getBenchmarkMenuSelection private static isValidMenu(sel: string): boolean{ let selection: number; try{ selection = parseInt(sel); } catch(error){ selection = -1; } if((selection > 0) && (selection < BenchmarkOptions.size)){ return true; } else{ return false; } } //Determines which problem user wants to run and runs it private static runSpecific(): void{ //Ask which problem the user wants to run let problemNumber: number = ProblemSelection.getProblemNumber(); //Ask how many times to run the problem let timesToRun: number = Benchmark.getNumberOfTimesToRun(); //Get the problem and print its description let problem: Problem = ProblemSelection.getProblem(problemNumber); console.log("\n" + problemNumber + ". " + problem.getDescription()); //Run the problem the specific number of times let totalTime: number = Benchmark.runProblem(problem, timesToRun); //Print the results console.log(Benchmark.getBenchmarkResults(problem, totalTime, timesToRun)); } //Runs all problems except a few that are specific because of run length private static runAllShort(): void{ //Ask how many times to run the problems let timesToRun: number = Benchmark.getNumberOfTimesToRun(); //Run through all valid problem numbers, skipping a few that are in the tooLong list for(let cnt: number = 1;cnt < ProblemSelection.PROBLEM_NUMBERS.length;++cnt){ let problemNumber: number = ProblemSelection.PROBLEM_NUMBERS[cnt]; //If the problem number is contained in the list of problems that take too long skip it if(Benchmark.tooLong.includes(problemNumber)){ continue; } //Get the problem and print its description let problem: Problem = ProblemSelection.getProblem(problemNumber); console.log(problemNumber + ". " + problem.getDescription()); //Run each problem the specified number of times let totalTime: number = Benchmark.runProblem(problem, timesToRun); //Print the results console.log(Benchmark.getBenchmarkResults(problem, totalTime, timesToRun)); } } //Runs all problems private static runAll(): void{ //Ask how many times to run the problem let timesToRun: number = Benchmark.getNumberOfTimesToRun(); //Run through all valid problem number, skipping a few that are in the tooLong list for(let cnt: number = 1;cnt < ProblemSelection.PROBLEM_NUMBERS.length;++cnt){ let problemNumber: number = ProblemSelection.PROBLEM_NUMBERS[cnt]; //Get the problem let problem: Problem = ProblemSelection.getProblem(problemNumber); //Run each problem the specified number of times console.log(problemNumber + ". " + problem.getDescription()); let totalTime: number = Benchmark.runProblem(problem, timesToRun); //Print the results console.log(Benchmark.getBenchmarkResults(problem, totalTime, timesToRun)); } } //Asks how many times a problem is ksupposed to run and returns the value private static getNumberOfTimesToRun(): number{ let numberOfTimesToRun: number = 1; let num: string = readlineSync.question("How many times do you want to run this problem? "); try{ numberOfTimesToRun = parseInt(num); } catch(error){ console.log("That is an invalid number!"); numberOfTimesToRun = Benchmark.getNumberOfTimesToRun(); } return numberOfTimesToRun; } //Runs the problem the given number of times private static runProblem(problem: Problem, timesToRun: number): number{ let totalTime: number = 0; process.stdout.write("Solving"); for(let cnt: number = 0;cnt < timesToRun;++cnt){ process.stdout.write('.'); //Reset the data so you are actually counting the run time an additional time problem.reset(); //Solve the problem problem.solve(); //Get the time dat totalTime += problem.getTimer().getNano(); } return totalTime; } //Prints the benchmark results of a problem private static getBenchmarkResults(problem: Problem, totalTime: number, timesRun: number): string{ //Calculate the average run time of the problem totalTime /= timesRun; let timeResults: string = Stopwatch.getStr(totalTime); //Tally the results let results: string = "\n\n" + problem.getResult() + "\nIt took an average of " + timeResults + " to run this problem through " + timesRun + " iterations\n\n"; return results; } }