// Copyright © 2024 Mikhail Hogrefe // // This file is part of Malachite. // // Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU // Lesser General Public License (LGPL) as published by the Free Software Foundation; either version // 3 of the License, or (at your option) any later version. See . use malachite_base::num::arithmetic::traits::{CheckedRoot, CheckedSqrt, Pow, Reciprocal}; use malachite_base::num::basic::traits::{NegativeOne, One, Zero}; use malachite_base::num::conversion::traits::ExactFrom; use malachite_nz::test_util::generators::integer_unsigned_pair_gen_var_3; use malachite_q::test_util::generators::{ rational_gen, rational_gen_var_1, rational_gen_var_3, rational_signed_pair_gen_var_4, rational_unsigned_pair_gen_var_4, }; use malachite_q::Rational; use std::panic::catch_unwind; use std::str::FromStr; fn test_helper(s: &str, exp: T, out: Option<&str>) where Rational: CheckedRoot, for<'a> &'a Rational: CheckedRoot, { let n = Rational::from_str(s).unwrap(); let out = out.map(ToString::to_string); assert_eq!(n.clone().checked_root(exp).map(|x| x.to_string()), out); assert_eq!((&n).checked_root(exp).map(|x| x.to_string()), out); } #[test] fn test_checked_root() { let test = |s, exp, out: Option<&str>| { test_helper::(s, exp, out); test_helper::(s, i64::exact_from(exp), out); }; test("0", 1, Some("0")); test("1", 1, Some("1")); test("2", 1, Some("2")); test("22/7", 1, Some("22/7")); test("0", 2, Some("0")); test("1", 2, Some("1")); test("2", 2, None); test("3", 2, None); test("4", 2, Some("2")); test("5", 2, None); test("22/7", 2, None); test("4/9", 2, Some("2/3")); test("-1", 1, Some("-1")); test("-2", 1, Some("-2")); test("-100", 1, Some("-100")); test("-1", 3, Some("-1")); test("-2", 3, None); test("-7", 3, None); test("-8", 3, Some("-2")); test("-9", 3, None); test("-27/8", 3, Some("-3/2")); test("27/8", 3, Some("3/2")); let test_i = |s, exp: i64, out: Option<&str>| { test_helper::(s, exp, out); }; test_i("1", -1, Some("1")); test_i("2", -1, Some("1/2")); test_i("22/7", -1, Some("7/22")); test_i("1", -2, Some("1")); test_i("2", -2, None); test_i("3", -2, None); test_i("4", -2, Some("1/2")); test_i("5", -2, None); test_i("22/7", -2, None); test_i("4/9", -2, Some("3/2")); test_i("-1", -1, Some("-1")); test_i("-2", -1, Some("-1/2")); test_i("-100", -1, Some("-1/100")); test_i("-1", -3, Some("-1")); test_i("-2", -3, None); test_i("-7", -3, None); test_i("-8", -3, Some("-1/2")); test_i("-9", -3, None); test_i("-27/8", -3, Some("-2/3")); test_i("27/8", -3, Some("2/3")); } #[test] fn checked_root_fail() { assert_panic!(Rational::ONE.checked_root(0u64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(0u64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(2u64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(4u64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(100u64)); assert_panic!(Rational::ZERO.checked_root(-2i64)); assert_panic!(Rational::ONE.checked_root(0i64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(0i64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(2i64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(4i64)); assert_panic!(Rational::NEGATIVE_ONE.checked_root(100i64)); } #[test] fn checked_root_ref_fail() { assert_panic!((&Rational::ONE).checked_root(0u64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(0u64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(2u64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(4u64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(100u64)); assert_panic!((&Rational::ZERO).checked_root(-2i64)); assert_panic!((&Rational::ONE).checked_root(0i64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(0i64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(2i64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(4i64)); assert_panic!((&Rational::NEGATIVE_ONE).checked_root(100i64)); } #[test] fn checked_root_properties() { rational_unsigned_pair_gen_var_4::().test_properties(|(n, exp)| { let root = n.clone().checked_root(exp); assert!(root.as_ref().map_or(true, Rational::is_valid)); let root_alt = (&n).checked_root(exp); assert!(root_alt.as_ref().map_or(true, Rational::is_valid)); assert_eq!(root_alt, root); assert_eq!((&n).checked_root(u64::exact_from(exp)), root); if n != 0 { assert_eq!( (&n).reciprocal().checked_root(exp), root.as_ref().map(Reciprocal::reciprocal) ); } if let Some(root) = root { assert_eq!((&root).pow(exp), n); } }); rational_signed_pair_gen_var_4::().test_properties(|(n, exp)| { let root = n.clone().checked_root(exp); assert!(root.as_ref().map_or(true, Rational::is_valid)); let root_alt = (&n).checked_root(exp); assert!(root_alt.as_ref().map_or(true, Rational::is_valid)); assert_eq!(root_alt, root); assert_eq!((&n).checked_root(exp), root); if n != 0u32 { assert_eq!( (&n).checked_root(-exp), root.as_ref().map(Reciprocal::reciprocal) ); assert_eq!( (&n).reciprocal().checked_root(exp), root.as_ref().map(Reciprocal::reciprocal) ); } if let Some(root) = root { assert_eq!((&root).pow(exp), n); } }); rational_gen().test_properties(|n| { assert_eq!((&n).checked_root(1u64).unwrap(), n); assert_eq!((&n).checked_root(1i64).unwrap(), n); }); rational_gen_var_3().test_properties(|n| { assert_eq!((&n).checked_root(2u64), (&n).checked_sqrt()); assert_eq!((&n).checked_root(2i64), n.checked_sqrt()); }); rational_gen_var_1().test_properties(|n| { assert_eq!((&n).checked_root(-1i64), Some(n.reciprocal())); }); integer_unsigned_pair_gen_var_3().test_properties(|(n, exp)| { assert_eq!( (&n).checked_root(exp).map(Rational::from), Rational::from(n).checked_root(exp) ); }); }