a-conjecture-of-mine

An exercise on polyglossy: the same problem solved on multiple languages

commit 20e70ab22a0de1ec9713cc6aeb61235ac9c64d16
parent 91bcaf293d5cfee408f6cdc4cde0515ed19e1d8b
Author: Gark Garcia <37553739+GarkGarcia@users.noreply.github.com>
Date:   Wed, 27 Feb 2019 10:52:36 -0300

Optimized calculations by switching from signed to unsigned integers whenever possible.

Diffstat:
MCargo.lock | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
MCargo.toml | 2+-
Msrc/main.rs | 96++++++++++++++++++++++++++++++-------------------------------------------------
3 files changed, 121 insertions(+), 64 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -15,22 +15,96 @@ dependencies = [
 name = "conjecture_tester"
 version = "0.1.0"
 dependencies = [
- "crossterm 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "crossterm"
-version = "0.4.3"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
+ "crossterm_cursor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_input 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_screen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_style 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_terminal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossterm_cursor"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossterm_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_winapi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossterm_input"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossterm_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_winapi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossterm_screen"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossterm_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_winapi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossterm_style"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossterm_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_winapi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossterm_terminal"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossterm_cursor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossterm_winapi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossterm_utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossterm_winapi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
  "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "crossterm_winapi"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "fuchsia-zircon"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -173,7 +247,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 [metadata]
 "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
-"checksum crossterm 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c9d2256dbdfabccaf577d59b1a4058bd4a7cd28823e8bc31a74a5781df12d30e"
+"checksum crossterm 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91f04a703cb52c7ea4f800cda4e6839fb61c33955703dea2a8252d81d87178b3"
+"checksum crossterm_cursor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e91c25e521708bd85fbdbdc34a854d1582793ab36e9aff2cee58fc79d7728e82"
+"checksum crossterm_input 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "937c314942c75a7893303e3fa1857cfbafdd8a7d8ee369389c79b55cc268c7a7"
+"checksum crossterm_screen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48eb1d3e7c5fea9b5a15c8667cb18b8c8fdfb28e38cd8faa048b9b7490cd9f69"
+"checksum crossterm_style 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2e4b4a13093fd9c0c16167b14a69ceb8166e079ccda904d41bbfc8ba2714b1b"
+"checksum crossterm_terminal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1b61af4ef3ed3624994e8af7ac87b6a483c2936e63eebe38d9a2810cd4a6d44"
+"checksum crossterm_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d26f24386ea91f9c55a85531dd3ee3673e4c82729e64567928665aca3a47c741"
+"checksum crossterm_winapi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f63b02344710452064687251b49cb0c275df10ea70dcd6038b1eec11665efc0a"
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
diff --git a/Cargo.toml b/Cargo.toml
@@ -4,6 +4,6 @@ version = "0.1.0"
 authors = ["Gark Garcia <37553739+GarkGarcia@users.noreply.github.com>"]
 
 [dependencies]
-crossterm = "0.4.3"
+crossterm = "0.6"
 num_cpus = "1.0"
 rand = "0.6.1" 
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
@@ -7,49 +7,41 @@ extern crate crossterm;
 extern crate num_cpus;
 extern crate rand;
 
-use std::io::{stdin, stdout, prelude::*};
-use std::sync::mpsc::{Sender, Receiver};
-use std::sync::mpsc;
-use std::thread;
-use std::env;
-use std::process::Command;
-use std::time::Instant;
-use crossterm::terminal::{terminal,ClearType};
-use crossterm::Screen;
+use std::{env, thread, time::Instant, sync::mpsc, sync::mpsc::{Sender, Receiver}};
+use crossterm::{terminal, input, ClearType};
 use rand::prelude::*;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
-    let screen = Screen::default();
-    let prompt = terminal(&screen);
+    let prompt = terminal();
 
     // Assign the correct number of threads to run the application with
     // The default is the number of cores in the machine
-    let n_cores = num_cpus::get_physical() as i64;
+    let n_cores = num_cpus::get_physical();
     let n_threads = if args.len() == 0 { n_cores } else {
-        match args[0].trim().parse::<i64>() {
-            Ok(n) => std::cmp::min(n.abs(), n_cores),
+        match args[0].trim().parse::<usize>() {
+            Ok(n_arg) => std::cmp::min(n_arg, n_cores),
             Err(_) => n_cores
         }
     };
 
-    println!("This program is a simple test for the following conjecture:
-    
-Let S: N -> N be the sum of the digits of a positive integer.
-For all A and B in N, S(A + B) = S(A) + S(B) - 9k, where k is an integer.");
+    println!("This program is a simple test for the following conjecture:\n");
+    println!("Let S: N -> N be the sum of the digits of a positive integer.");
+    println!("For all A and B in N, S(A + B) = S(A) + S(B) - 9k, where k is an integer.");
 
     // Listen for user input
-    let user_input = ask("\nWhat value would you like to test the conjecture for?");
+    let _ = prompt.write("\nWhat value would you like to test the conjecture for? ");
+    let user_input = input().read_line().unwrap_or(String::new());
 
-    match user_input.trim().parse::<i64>() {
+    match user_input.trim().parse::<usize>() {
         Ok(max) => {
             let start_time = Instant::now();
             println!("\nLOADING. . .");
-            let counterexpls = get_all_countrexpls(max.abs(), n_threads);
+            let counterexpls = get_all_countrexpls(max, n_threads);
             let duration = start_time.elapsed();
 
             // Print the results
-            prompt.clear(ClearType::All);
+            if let Err(err) = prompt.clear(ClearType::All) { panic!(err); }
             println!("LOADED. . . 100% in {}s [{} threads]\n", duration.as_secs(), n_threads);
             if counterexpls.len() == 0 {
                 println!("The conjecture is proved for all natural numbers smaller or equals to {}!", max);
@@ -66,25 +58,24 @@ For all A and B in N, S(A + B) = S(A) + S(B) - 9k, where k is an integer.");
                 println!("{}\n", counterexpls_str);
             }
 
-            pause_prompt();
+            if let Err(err) = prompt.write("Press any key to continue. . . ") { panic!(err); }
+            let _ = input().read_char();
         }, 
-        Err(_) => println!("'{}' is not an integer!", user_input.trim())
+        Err(_) => println!("'{}' is not a natural number!", user_input.trim())
     }
 }
 
-fn get_all_countrexpls(max: i64, n_threads: i64) -> Vec<[i64; 2]> {
-    if n_threads < 1 { panic!("The number {} is not a valid number of threads.", n_threads) }
-
+fn get_all_countrexpls(max: usize, n_threads: usize) -> Vec<[usize; 2]> {
     if max / n_threads > 0 && n_threads > 1 {
 
         // Thread related variables
-        let (coutexpl_sender, coutexpl_reciever): (Sender<Vec<[i64; 2]>>, Receiver<Vec<[i64; 2]>>) = mpsc::channel();
+        let (coutexpl_sender, coutexpl_reciever): (Sender<Vec<[usize; 2]>>, Receiver<Vec<[usize; 2]>>) = mpsc::channel();
         let mut child_threads = Vec::new();
-        let range_lenght = ((max as f64) / n_threads as f64).ceil() as i64;
-        let mut range: Vec<i64> = (0..max).collect();
+        let range_lenght = max / n_threads;
+        let mut range: Vec<usize> = (0..max).collect();
 
         // Conjecture related variables
-        let mut counterexpls: Vec<[i64; 2]> = Vec::new();
+        let mut counterexpls: Vec<[usize; 2]> = Vec::new();
 
         // Shuffle the values in the range to get an even distribution of calculations across all threads
         range.shuffle(&mut thread_rng());
@@ -92,13 +83,14 @@ fn get_all_countrexpls(max: i64, n_threads: i64) -> Vec<[i64; 2]> {
         for i in 1..n_threads {
             let thread_countr_sd = coutexpl_sender.clone();
 
+            // Separate a specific slice of the range and assign it to the thread
             let start = (i - 1) * range_lenght;
             let end = start + range_lenght - 1;
             let thread_range = range[(start as usize)..(end as usize)].to_vec();
 
             let child = thread::spawn(move || {
                 thread_countr_sd.send(get_range_countrexpls(thread_range, max))
-                    .expect(&*format!("Thread n°{} was unable to sent a message trought the channel", i));
+                    .expect(&format!("Thread n°{} was unable to sent a message trought the channel", i));
             });
             child_threads.push(child);
         }
@@ -111,19 +103,18 @@ fn get_all_countrexpls(max: i64, n_threads: i64) -> Vec<[i64; 2]> {
             child.join().expect("Child thread panicked");
         }
 
-        return counterexpls;
-
+        counterexpls
     } else {
-        return get_range_countrexpls((0..max).collect(), max);
+        get_range_countrexpls((0..max).collect(), max)
     }
 }
 
-fn get_range_countrexpls(range: Vec<i64>, max: i64) -> Vec<[i64; 2]> {
+fn get_range_countrexpls(range: Vec<usize>, max: usize) -> Vec<[usize; 2]> {
     let mut counterexpls = Vec::new();
 
     for a in range {
         for b in a..max {
-            let difference: i64 = sum_digits(a + b) - sum_digits(a) - sum_digits(b);
+            let difference = sum_digits(a + b) - sum_digits(a) - sum_digits(b);
 
             if !is_multiple_of_nine(difference) {
                 counterexpls.push([a, b]);
@@ -131,41 +122,26 @@ fn get_range_countrexpls(range: Vec<i64>, max: i64) -> Vec<[i64; 2]> {
         }
     }
 
-    return counterexpls;
+    counterexpls
 }
 
-fn is_multiple_of_nine(n: i64) -> bool {
+fn is_multiple_of_nine(n: isize) -> bool {
     let floor = n / 9;
     let neerest_mult = floor * 9;
 
-    return n == neerest_mult;
+    n == neerest_mult
 }
 
-fn get_digits(n: i64) -> Vec<i64> {
-    return n.to_string().chars().map(|d| d.to_digit(10).unwrap() as i64).collect();
+fn get_digits(n: usize) -> Vec<u32> {
+    n.to_string().chars().map(|d| d.to_digit(10).unwrap()).collect()
 }
 
-fn sum_digits(n: i64) -> i64 {
+fn sum_digits(n: usize) -> isize {
     let mut sum = 0;
 
     for d in get_digits(n) {
-        sum += d;
+        sum += d as isize;
     }
 
-    return sum;
-}
-
-fn ask(message: &str) -> String {
-    // Print the question
-    write!(stdout(), "{} ", message).unwrap();
-    stdout().flush().unwrap();
-
-    // Return the responce
-    let mut response = String::new();
-    stdin().read_line(&mut response).unwrap();
-    return response;
-}
-
-fn pause_prompt() {
-    let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();
+    sum
 } 
\ No newline at end of file