From 928408b944d396030019b2d8719206fa9395d073 Mon Sep 17 00:00:00 2001 From: Madhav2310 Date: Wed, 3 Aug 2022 09:36:23 +0530 Subject: [PATCH 1/5] fmean, Median, Median_low, median_high, mean overload functions implemented --- integration_tests/test_statistics.py | 83 ++++++++- src/runtime/statistics.py | 255 +++++++++++++++++++++++++++ 2 files changed, 337 insertions(+), 1 deletion(-) diff --git a/integration_tests/test_statistics.py b/integration_tests/test_statistics.py index cb101af163..a829c0a636 100644 --- a/integration_tests/test_statistics.py +++ b/integration_tests/test_statistics.py @@ -1,4 +1,4 @@ -from statistics import (mean, geometric_mean, harmonic_mean) +from statistics import (mean, geometric_mean, harmonic_mean, fmean, median, median_low, median_high) from ltypes import i32, f64, i64 eps: f64 @@ -17,6 +17,26 @@ def test_mean(): k = mean(c) assert abs(k - 5.4) < eps + d: list[i32] + d = [1, 3, 11] + l: f64 + l = mean(d) + assert abs(l - 5) < eps + +def test_fmean(): + a: list[i32] + a = [9, 4, 10] + j: f64 + j = fmean(a) + assert abs(j - 7.666666666666667) < eps + + b: list[f64] + b = [-1.9, -13.8, -6, 4.2, 5.9, 9.1] + k: f64 + k = fmean(b) + assert abs(k + 0.41666666666666674) < eps + + def test_geometric_mean(): c: list[i32] c = [1,2,3] @@ -31,10 +51,71 @@ def test_harmonic_mean(): k = harmonic_mean(c) assert abs(k - 4.740458015267175) < eps +def test_median(): + a: list[i32] + a = [9, 4, 10] + j: f64 + j = median(a) + assert abs(j - 9) < eps + + b: list[i32] + b = [9, 4, 1, 10] + k: f64 + k = median(b) + assert abs(k - 6.5) < eps + + c: list[f64] + c = [-1.2, 3.4, 9.7, 6.0, 5.1] + l: f64 + l = median(c) + assert abs(l - 5.1) < eps + +def test_median_low(): + a: list[i32] + a = [9, 4, 10] + j: f64 + j = median_low(a) + assert abs(j - 9) < eps + + b: list[i32] + b = [9, 4, 1, 10] + k: f64 + k = median_low(b) + assert abs(k - 4) < eps + + c: list[f64] + c = [-1.2, 3.4, 6.0, 5.1] + l: f64 + l = median_low(c) + assert abs(l - 3.4) < eps + +def test_median_high(): + a: list[i32] + a = [9, 4, 10] + j: f64 + j = median_high(a) + assert abs(j - 9) < eps + + b: list[i32] + b = [9, 4, 1, 10] + k: f64 + k = median_high(b) + assert abs(k - 9) < eps + + c: list[f64] + c = [-1.2, 3.4, 6.0, 5.1] + l: f64 + l = median_high(c) + assert abs(l - 5.1) < eps + def check(): test_mean() test_geometric_mean() test_harmonic_mean() + test_fmean() + test_median() + test_median_low() + test_median_high() check() diff --git a/src/runtime/statistics.py b/src/runtime/statistics.py index daa8268b81..481fc7083e 100644 --- a/src/runtime/statistics.py +++ b/src/runtime/statistics.py @@ -1,7 +1,11 @@ from ltypes import i32, f64 + @overload def mean(x: list[i32]) -> f64: + """ + Returns the arithmetic mean of a data sequence of numbers + """ k: i32 = len(x) if k == 0: return 0.0 @@ -17,6 +21,66 @@ def mean(x: list[i32]) -> f64: @overload def mean(x: list[f64]) -> f64: + """ + Returns the arithmetic mean of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0.0 + sum: f64 + sum = 0.0 + i: i32 + for i in range(k): + sum += x[i] + ans: f64 + ans = sum/k + return ans + +@overload +def mean(x: list[i32]) -> i32: + """ + Returns the arithmetic mean of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0 + sum: i32 + sum = 0 + + i: i32 + for i in range(k): + sum += x[i] + + if sum%k == 0: + ans: i32 + ans = sum/k + return ans + + +@overload +def fmean(x: list[i32]) -> f64: + """ + Returns the floating type arithmetic mean of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0.0 + sum: f64 + sum = 0.0 + i: i32 + + for i in range(k): + sum += x[i] + ans: f64 + ans = sum/k + return ans + + +@overload +def fmean(x: list[f64]) -> f64: + """ + Returns the floating type arithmetic mean of a data sequence of numbers + """ k: i32 = len(x) if k == 0: return 0.0 @@ -29,8 +93,12 @@ def mean(x: list[f64]) -> f64: ans = sum/k return ans + @overload def geometric_mean(x: list[i32]) -> f64: + """ + Returns the geometric mean of a data sequence of numbers + """ k: i32 = len(x) if k == 0: return 0.0 @@ -47,6 +115,9 @@ def geometric_mean(x: list[i32]) -> f64: @overload def harmonic_mean(x: list[i32]) -> f64: + """ + Returns the harmonic mean of a data sequence of numbers + """ k: i32 = len(x) if k == 0: return 0.0 @@ -62,3 +133,187 @@ def harmonic_mean(x: list[i32]) -> f64: ans: f64 ans = k/sum return ans + +@overload +def median(x: list[i32]) -> f64: + """ + Returns the median of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0.0 + i: i32 + j: i32 + for i in range(k): + for j in range(i+1,k): + if x[i]>x[j]: + x[i],x[j]=x[j],x[i] + ans: f64 + if k%2==1: + medianidx: i32 + medianidx = k/2 + ans = float(x[medianidx]) + else: + lowmedidx: i32 + highmedidx: i32 + lowmedidx = (k/2)-1 + highmedidx = k/2 + ans = float((x[lowmedidx] + x[highmedidx])/2) + return ans + +@overload +def median(x: list[f64]) -> f64: + """ + Returns the median of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0.0 + i: i32 + j: i32 + for i in range(k): + for j in range(i+1,k): + if x[i]>x[j]: + x[i],x[j]=x[j],x[i] + ans: f64 + if k%2==1: + medianidx: i32 + medianidx = k/2 + ans = x[medianidx] + else: + lowmedidx: i32 + highmedidx: i32 + lowmedidx = (k/2)-1 + highmedidx = k/2 + ans = (x[lowmedidx] + x[highmedidx])/2 + return ans + +@overload +def median(x: list[i32]) -> i32: + """ + Returns the median of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0 + i: i32 + j: i32 + for i in range(k): + for j in range(i+1,k): + if x[i]>x[j]: + x[i],x[j]=x[j],x[i] + ans: i32 + if k%2==1: + medianidx: i32 + medianidx = k/2 + ans = x[medianidx] + return ans + else: + lowmedidx: i32 + highmedidx: i32 + lowmedidx = (k/2)-1 + highmedidx = k/2 + if (x[lowmedidx] + x[highmedidx])%2 ==0: + ans = (x[lowmedidx] + x[highmedidx])/2 + return ans + +@overload +def median_low(x: list[i32]) -> i32: + """ + Returns the lowmedian of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0 + i: i32 + j: i32 + for i in range(k): + for j in range(i+1,k): + if x[i]>x[j]: + x[i],x[j]=x[j],x[i] + ans: i32 + if k%2==1: + medianidx: i32 + medianidx = k/2 + ans = x[medianidx] + else: + lowmedidx: i32 + lowmedidx = (k/2)-1 + ans = x[lowmedidx] + return ans + +@overload +def median_low(x: list[f64]) -> f64: + """ + Returns the low median of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0.0 + i: i32 + j: i32 + for i in range(k): + for j in range(i+1,k): + if x[i]>x[j]: + x[i],x[j]=x[j],x[i] + ans: f64 + if k%2==1: + medianidx: i32 + medianidx = k/2 + ans = x[medianidx] + else: + lowmedidx: i32 + lowmedidx = (k/2)-1 + ans = x[lowmedidx] + return ans + + +@overload +def median_high(x: list[i32]) -> i32: + """ + Returns the high median of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0 + i: i32 + j: i32 + for i in range(k): + for j in range(i+1,k): + if x[i]>x[j]: + x[i],x[j]=x[j],x[i] + ans: i32 + if k%2==1: + medianidx: i32 + medianidx = k/2 + ans = x[medianidx] + else: + highmedidx: i32 + highmedidx = (k/2) + ans = x[highmedidx] + return ans + +@overload +def median_high(x: list[f64]) -> f64: + """ + Returns the high median of a data sequence of numbers + """ + k: i32 = len(x) + if k == 0: + return 0.0 + i: i32 + j: i32 + for i in range(k): + for j in range(i+1,k): + if x[i]>x[j]: + x[i],x[j]=x[j],x[i] + ans: f64 + if k%2==1: + medianidx: i32 + medianidx = k/2 + ans = x[medianidx] + else: + highmedidx: i32 + highmedidx = (k/2) + ans = x[highmedidx] + return ans \ No newline at end of file From a914135f73cbff46da28c1c0f8a39f9cead048c8 Mon Sep 17 00:00:00 2001 From: Smit-create Date: Mon, 8 Aug 2022 17:40:53 +0530 Subject: [PATCH 2/5] Implement list argument in LLVM --- src/libasr/codegen/asr_to_llvm.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index b6f2109db3..84c524630b 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -2195,6 +2195,20 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor type = tuple_api->get_tuple_type(type_code, llvm_el_types)->getPointerTo(); break; } + case (ASR::ttypeType::List) : { + bool is_array_type = false, is_malloc_array_type = false; + bool is_list = true; + ASR::dimension_t *m_dims = nullptr; + ASR::List_t* asr_list = ASR::down_cast(asr_type); + llvm::Type* el_llvm_type = get_type_from_ttype_t(asr_list->m_type, m_storage, + is_array_type, + is_malloc_array_type, + is_list, m_dims, n_dims, + a_kind); + std::string el_type_code = ASRUtils::get_type_code(asr_list->m_type); + type = list_api->get_list_type(el_llvm_type, el_type_code, a_kind)->getPointerTo(); + break; + } default : LFORTRAN_ASSERT(false); } From d535b291a5128dbf5160a4139bf720bb28e8df3b Mon Sep 17 00:00:00 2001 From: Smit-create Date: Mon, 8 Aug 2022 17:51:44 +0530 Subject: [PATCH 3/5] Fix list overload error --- src/libasr/asr_utils.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libasr/asr_utils.cpp b/src/libasr/asr_utils.cpp index e6907ab710..b57f100ff9 100644 --- a/src/libasr/asr_utils.cpp +++ b/src/libasr/asr_utils.cpp @@ -659,6 +659,11 @@ bool types_equal(const ASR::ttype_t &a, const ASR::ttype_t &b) { } break; } + case (ASR::ttypeType::List) : { + ASR::List_t *a2 = ASR::down_cast(&a); + ASR::List_t *b2 = ASR::down_cast(&b); + return types_equal(*a2->m_type, *b2->m_type); + } case (ASR::ttypeType::Derived) : { ASR::Derived_t *a2 = ASR::down_cast(&a); ASR::Derived_t *b2 = ASR::down_cast(&b); From 88201d5dd5d5a2a078bed816a6bfdf3d03c462d8 Mon Sep 17 00:00:00 2001 From: Smit-create Date: Mon, 8 Aug 2022 21:53:31 +0530 Subject: [PATCH 4/5] Add support for mean, fmean, geometric/harmonic mean --- src/runtime/statistics.py | 266 ++++++-------------------------------- 1 file changed, 42 insertions(+), 224 deletions(-) diff --git a/src/runtime/statistics.py b/src/runtime/statistics.py index 481fc7083e..555c72a052 100644 --- a/src/runtime/statistics.py +++ b/src/runtime/statistics.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from ltypes import i32, f64, overload @overload @@ -15,12 +15,11 @@ def mean(x: list[i32]) -> f64: for i in range(k): sum += x[i] - ans: f64 - ans = sum/k - return ans + return sum/k + @overload -def mean(x: list[f64]) -> f64: +def mean(x: list[i64]) -> f64: """ Returns the arithmetic mean of a data sequence of numbers """ @@ -30,37 +29,17 @@ def mean(x: list[f64]) -> f64: sum: f64 sum = 0.0 i: i32 - for i in range(k): - sum += x[i] - ans: f64 - ans = sum/k - return ans - -@overload -def mean(x: list[i32]) -> i32: - """ - Returns the arithmetic mean of a data sequence of numbers - """ - k: i32 = len(x) - if k == 0: - return 0 - sum: i32 - sum = 0 - i: i32 for i in range(k): sum += x[i] - if sum%k == 0: - ans: i32 - ans = sum/k - return ans + return sum/k @overload -def fmean(x: list[i32]) -> f64: +def mean(x: list[f32]) -> f64: """ - Returns the floating type arithmetic mean of a data sequence of numbers + Returns the arithmetic mean of a data sequence of numbers """ k: i32 = len(x) if k == 0: @@ -71,15 +50,13 @@ def fmean(x: list[i32]) -> f64: for i in range(k): sum += x[i] - ans: f64 - ans = sum/k - return ans + return sum/k @overload -def fmean(x: list[f64]) -> f64: +def mean(x: list[f64]) -> f64: """ - Returns the floating type arithmetic mean of a data sequence of numbers + Returns the arithmetic mean of a data sequence of numbers """ k: i32 = len(x) if k == 0: @@ -87,233 +64,74 @@ def fmean(x: list[f64]) -> f64: sum: f64 sum = 0.0 i: i32 + for i in range(k): sum += x[i] - ans: f64 - ans = sum/k - return ans + return sum/k @overload -def geometric_mean(x: list[i32]) -> f64: +def fmean(x: list[i32]) -> f64: """ - Returns the geometric mean of a data sequence of numbers + Returns the floating type arithmetic mean of a data sequence of numbers """ - k: i32 = len(x) - if k == 0: - return 0.0 - product: f64 - product = 1.0 - i: i32 - for i in range(k): - if x[i] < 1: - raise ValueError('geometric mean requires a non-empty dataset containing positive numbers') - product *= x[i] - ans: f64 - ans = product**(1/k) - return ans + return mean(x) -@overload -def harmonic_mean(x: list[i32]) -> f64: - """ - Returns the harmonic mean of a data sequence of numbers - """ - k: i32 = len(x) - if k == 0: - return 0.0 - sum: f64 - sum = 0.0 - i: i32 - for i in range(k): - if x[i] < 0: - raise ValueError('harmonic mean does not support negative values') - if x[i] ==0: - return 0.0 - sum += 1 / x[i] - ans: f64 - ans = k/sum - return ans @overload -def median(x: list[i32]) -> f64: +def fmean(x: list[i64]) -> f64: """ - Returns the median of a data sequence of numbers + Returns the floating type arithmetic mean of a data sequence of numbers """ - k: i32 = len(x) - if k == 0: - return 0.0 - i: i32 - j: i32 - for i in range(k): - for j in range(i+1,k): - if x[i]>x[j]: - x[i],x[j]=x[j],x[i] - ans: f64 - if k%2==1: - medianidx: i32 - medianidx = k/2 - ans = float(x[medianidx]) - else: - lowmedidx: i32 - highmedidx: i32 - lowmedidx = (k/2)-1 - highmedidx = k/2 - ans = float((x[lowmedidx] + x[highmedidx])/2) - return ans + return mean(x) -@overload -def median(x: list[f64]) -> f64: - """ - Returns the median of a data sequence of numbers - """ - k: i32 = len(x) - if k == 0: - return 0.0 - i: i32 - j: i32 - for i in range(k): - for j in range(i+1,k): - if x[i]>x[j]: - x[i],x[j]=x[j],x[i] - ans: f64 - if k%2==1: - medianidx: i32 - medianidx = k/2 - ans = x[medianidx] - else: - lowmedidx: i32 - highmedidx: i32 - lowmedidx = (k/2)-1 - highmedidx = k/2 - ans = (x[lowmedidx] + x[highmedidx])/2 - return ans @overload -def median(x: list[i32]) -> i32: +def fmean(x: list[f64]) -> f64: """ - Returns the median of a data sequence of numbers + Returns the floating type arithmetic mean of a data sequence of numbers """ - k: i32 = len(x) - if k == 0: - return 0 - i: i32 - j: i32 - for i in range(k): - for j in range(i+1,k): - if x[i]>x[j]: - x[i],x[j]=x[j],x[i] - ans: i32 - if k%2==1: - medianidx: i32 - medianidx = k/2 - ans = x[medianidx] - return ans - else: - lowmedidx: i32 - highmedidx: i32 - lowmedidx = (k/2)-1 - highmedidx = k/2 - if (x[lowmedidx] + x[highmedidx])%2 ==0: - ans = (x[lowmedidx] + x[highmedidx])/2 - return ans + return mean(x) + @overload -def median_low(x: list[i32]) -> i32: +def fmean(x: list[f32]) -> f64: """ - Returns the lowmedian of a data sequence of numbers + Returns the floating type arithmetic mean of a data sequence of numbers """ - k: i32 = len(x) - if k == 0: - return 0 - i: i32 - j: i32 - for i in range(k): - for j in range(i+1,k): - if x[i]>x[j]: - x[i],x[j]=x[j],x[i] - ans: i32 - if k%2==1: - medianidx: i32 - medianidx = k/2 - ans = x[medianidx] - else: - lowmedidx: i32 - lowmedidx = (k/2)-1 - ans = x[lowmedidx] - return ans + return mean(x) -@overload -def median_low(x: list[f64]) -> f64: + +def geometric_mean(x: list[i32]) -> f64: """ - Returns the low median of a data sequence of numbers + Returns the geometric mean of a data sequence of numbers """ k: i32 = len(x) if k == 0: return 0.0 + product: f64 + product = 1.0 i: i32 - j: i32 + for i in range(k): - for j in range(i+1,k): - if x[i]>x[j]: - x[i],x[j]=x[j],x[i] - ans: f64 - if k%2==1: - medianidx: i32 - medianidx = k/2 - ans = x[medianidx] - else: - lowmedidx: i32 - lowmedidx = (k/2)-1 - ans = x[lowmedidx] - return ans + product *= x[i] + return product**(1/k) -@overload -def median_high(x: list[i32]) -> i32: - """ - Returns the high median of a data sequence of numbers - """ - k: i32 = len(x) - if k == 0: - return 0 - i: i32 - j: i32 - for i in range(k): - for j in range(i+1,k): - if x[i]>x[j]: - x[i],x[j]=x[j],x[i] - ans: i32 - if k%2==1: - medianidx: i32 - medianidx = k/2 - ans = x[medianidx] - else: - highmedidx: i32 - highmedidx = (k/2) - ans = x[highmedidx] - return ans -@overload -def median_high(x: list[f64]) -> f64: +def harmonic_mean(x: list[i32]) -> f64: """ - Returns the high median of a data sequence of numbers + Returns the harmonic mean of a data sequence of numbers """ k: i32 = len(x) if k == 0: return 0.0 + sum: f64 + sum = 0.0 i: i32 - j: i32 + for i in range(k): - for j in range(i+1,k): - if x[i]>x[j]: - x[i],x[j]=x[j],x[i] - ans: f64 - if k%2==1: - medianidx: i32 - medianidx = k/2 - ans = x[medianidx] - else: - highmedidx: i32 - highmedidx = (k/2) - ans = x[highmedidx] - return ans \ No newline at end of file + if x[i] == 0: + return 0.0 + sum += 1 / x[i] + return k/sum From a3af2ab32822c5a9083dad62796fe59d4159a771 Mon Sep 17 00:00:00 2001 From: Smit-create Date: Mon, 8 Aug 2022 21:53:52 +0530 Subject: [PATCH 5/5] Add and update tests --- integration_tests/CMakeLists.txt | 4 +- integration_tests/test_statistics.py | 65 +--------------------------- 2 files changed, 3 insertions(+), 66 deletions(-) diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 028ce8614c..517555188b 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -216,6 +216,4 @@ RUN(NAME test_str_comparison LABELS cpython llvm) RUN(NAME generics_01 LABELS cpython llvm) RUN(NAME generics_array_01 LABELS llvm) - -# Just CPython -RUN(NAME test_statistics LABELS cpython) +RUN(NAME test_statistics LABELS cpython llvm) diff --git a/integration_tests/test_statistics.py b/integration_tests/test_statistics.py index a829c0a636..bd1c018fa2 100644 --- a/integration_tests/test_statistics.py +++ b/integration_tests/test_statistics.py @@ -1,4 +1,4 @@ -from statistics import (mean, geometric_mean, harmonic_mean, fmean, median, median_low, median_high) +from statistics import (mean, geometric_mean, harmonic_mean, fmean) from ltypes import i32, f64, i64 eps: f64 @@ -31,7 +31,7 @@ def test_fmean(): assert abs(j - 7.666666666666667) < eps b: list[f64] - b = [-1.9, -13.8, -6, 4.2, 5.9, 9.1] + b = [-1.9, -13.8, -6.0, 4.2, 5.9, 9.1] k: f64 k = fmean(b) assert abs(k + 0.41666666666666674) < eps @@ -51,71 +51,10 @@ def test_harmonic_mean(): k = harmonic_mean(c) assert abs(k - 4.740458015267175) < eps -def test_median(): - a: list[i32] - a = [9, 4, 10] - j: f64 - j = median(a) - assert abs(j - 9) < eps - - b: list[i32] - b = [9, 4, 1, 10] - k: f64 - k = median(b) - assert abs(k - 6.5) < eps - - c: list[f64] - c = [-1.2, 3.4, 9.7, 6.0, 5.1] - l: f64 - l = median(c) - assert abs(l - 5.1) < eps - -def test_median_low(): - a: list[i32] - a = [9, 4, 10] - j: f64 - j = median_low(a) - assert abs(j - 9) < eps - - b: list[i32] - b = [9, 4, 1, 10] - k: f64 - k = median_low(b) - assert abs(k - 4) < eps - - c: list[f64] - c = [-1.2, 3.4, 6.0, 5.1] - l: f64 - l = median_low(c) - assert abs(l - 3.4) < eps - -def test_median_high(): - a: list[i32] - a = [9, 4, 10] - j: f64 - j = median_high(a) - assert abs(j - 9) < eps - - b: list[i32] - b = [9, 4, 1, 10] - k: f64 - k = median_high(b) - assert abs(k - 9) < eps - - c: list[f64] - c = [-1.2, 3.4, 6.0, 5.1] - l: f64 - l = median_high(c) - assert abs(l - 5.1) < eps - - def check(): test_mean() test_geometric_mean() test_harmonic_mean() test_fmean() - test_median() - test_median_low() - test_median_high() check()