From d1e12a66e3f26510ccd295beb3e024380890db9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 21 Jan 2022 13:36:15 +0100 Subject: [PATCH] Improve each performance ~6x, add error handling to at --- .../Base/0.2.32-SNAPSHOT/src/Data/Vector.enso | 12 ++-- test/Benchmarks/src/Vector.enso | 54 ++------------- test/Benchmarks/src/Vector_Sort.enso | 68 +++++++++++++++++++ test/Table_Tests/src/Matching_Spec.enso | 2 +- test/Tests/src/Data/Vector_Spec.enso | 10 +++ 5 files changed, 90 insertions(+), 56 deletions(-) create mode 100644 test/Benchmarks/src/Vector_Sort.enso diff --git a/distribution/lib/Standard/Base/0.2.32-SNAPSHOT/src/Data/Vector.enso b/distribution/lib/Standard/Base/0.2.32-SNAPSHOT/src/Data/Vector.enso index 0d62c6bfe6852..493976ce1ee57 100644 --- a/distribution/lib/Standard/Base/0.2.32-SNAPSHOT/src/Data/Vector.enso +++ b/distribution/lib/Standard/Base/0.2.32-SNAPSHOT/src/Data/Vector.enso @@ -140,11 +140,11 @@ type Vector Get the last element of a vector. [1, 2, 3].at -1 == 3 - at : Number -> Any + at : Number -> Any ! Index_Out_Of_Bounds_Error at index = - # TODO we may want to ad.ad an unsafe_at without this check and then wrap the Java panics from to_array.at to some prettier Enso types - if index < 0 then this.to_array.at (this.length + index) else - this.to_array.at index + actual_index = if index < 0 then this.length + index else index + if actual_index>=0 && actual_index Any) -> Nothing each f = - this.map f - Nothing + 0.up_to this.length . each ix-> + f (this.unsafe_at ix) ## Reverses the vector, returning a vector with the same elements, but in the opposite order. diff --git a/test/Benchmarks/src/Vector.enso b/test/Benchmarks/src/Vector.enso index 4fd5388c6b121..1138d781a0165 100644 --- a/test/Benchmarks/src/Vector.enso +++ b/test/Benchmarks/src/Vector.enso @@ -6,69 +6,25 @@ polyglot java import java.util.Random polyglot java import org.enso.base.Time_Utils - ## Bench Utilities ============================================================ vector_size = 1000000 iter_size = 100 num_iterations = 10 -make_sorted_ascending_vec : Integer -> Base.Vector.Vector -make_sorted_ascending_vec n = 0.up_to n+1 . to_vector - -make_partially_sorted_vec : Integer -> Base.Vector.Vector -make_partially_sorted_vec n = - random_gen = Random.new n - direction = Ref.new Sort_Order.Ascending - last_num = Ref.new 0 - run_length = Ref.new 0 - Base.Vector.fill n <| - case (Ref.get run_length) == 0 of - True -> - new_direction = if random_gen.nextDouble > 0 then Sort_Order.Ascending else - Sort_Order.Descending - Ref.put direction new_direction - Ref.put run_length ((random_gen.nextLong % (n / 10).floor) - 1) - num = random_gen.nextInt - Ref.put last_num num - num - False -> - change = random_gen.nextInt.abs % n - num = case Ref.get direction of - Sort_Order.Ascending -> - num = (Ref.get last_num) + change - Ref.put last_num num - num - Sort_Order.Descending -> - num = (Ref.get last_num) - change - Ref.put last_num num - num - Ref.put run_length ((Ref.get run_length) - 1) - num - make_random_vec : Integer -> Base.Vector.Vector make_random_vec n = random_gen = Random.new n Base.Vector.fill n random_gen.nextLong - - # The Benchmarks ============================================================== main = - sorted_vec = here.make_sorted_ascending_vec here.vector_size - partially_sorted_vec = here.make_partially_sorted_vec here.vector_size random_vec = here.make_random_vec here.vector_size - projection = x -> x % 10 - comparator = l -> r -> r.compare_to l - - Bench.measure (sorted_vec.sort) "Already Sorted" here.iter_size here.num_iterations - Bench.measure (sorted_vec.sort order=Sort_Order.Descending) "Sorted in Opposite Order" here.iter_size here.num_iterations - Bench.measure (partially_sorted_vec.sort) "Sorted Runs Ascending" here.iter_size here.num_iterations - Bench.measure (partially_sorted_vec.sort order=Sort_Order.Descending) "Sorted Runs Descending" here.iter_size here.num_iterations - Bench.measure (random_vec.sort) "Random Elements Ascending" here.iter_size here.num_iterations - Bench.measure (random_vec.sort order=Sort_Order.Descending) "Random Elements Descending" here.iter_size here.num_iterations - Bench.measure (random_vec.sort on=projection) "Sorting with a Custom Projection" here.iter_size here.num_iterations - Bench.measure (random_vec.sort by=comparator) "Sorting with a Custom Comparison" here.iter_size here.num_iterations Bench.measure (random_vec.filter (x -> x % 3 == 1)) "Filter" here.iter_size here.num_iterations + + stateful_fun x = + s = State.get Number + State.put s+x + Bench.measure (State.run Number 0 <| random_vec.each stateful_fun) "Each" here.iter_size here.num_iterations diff --git a/test/Benchmarks/src/Vector_Sort.enso b/test/Benchmarks/src/Vector_Sort.enso new file mode 100644 index 0000000000000..7b69c34b1dd87 --- /dev/null +++ b/test/Benchmarks/src/Vector_Sort.enso @@ -0,0 +1,68 @@ +from Standard.Base import all + +import Standard.Test.Bench + +import project.Vector as Vector_Utils + +polyglot java import java.util.Random +polyglot java import org.enso.base.Time_Utils + + + +## Bench Utilities ============================================================ + +vector_size = 1000000 +iter_size = 100 +num_iterations = 10 + +make_sorted_ascending_vec : Integer -> Base.Vector.Vector +make_sorted_ascending_vec n = 0.up_to n+1 . to_vector + +make_partially_sorted_vec : Integer -> Base.Vector.Vector +make_partially_sorted_vec n = + random_gen = Random.new n + direction = Ref.new Sort_Order.Ascending + last_num = Ref.new 0 + run_length = Ref.new 0 + Base.Vector.fill n <| + case (Ref.get run_length) == 0 of + True -> + new_direction = if random_gen.nextDouble > 0 then Sort_Order.Ascending else + Sort_Order.Descending + Ref.put direction new_direction + Ref.put run_length ((random_gen.nextLong % (n / 10).floor) - 1) + num = random_gen.nextInt + Ref.put last_num num + num + False -> + change = random_gen.nextInt.abs % n + num = case Ref.get direction of + Sort_Order.Ascending -> + num = (Ref.get last_num) + change + Ref.put last_num num + num + Sort_Order.Descending -> + num = (Ref.get last_num) - change + Ref.put last_num num + num + Ref.put run_length ((Ref.get run_length) - 1) + num + + +# The Benchmarks ============================================================== + +main = + sorted_vec = here.make_sorted_ascending_vec here.vector_size + partially_sorted_vec = here.make_partially_sorted_vec here.vector_size + random_vec = Vector_Utils.make_random_vec here.vector_size + projection = x -> x % 10 + comparator = l -> r -> r.compare_to l + + Bench.measure (sorted_vec.sort) "Already Sorted" here.iter_size here.num_iterations + Bench.measure (sorted_vec.sort order=Sort_Order.Descending) "Sorted in Opposite Order" here.iter_size here.num_iterations + Bench.measure (partially_sorted_vec.sort) "Sorted Runs Ascending" here.iter_size here.num_iterations + Bench.measure (partially_sorted_vec.sort order=Sort_Order.Descending) "Sorted Runs Descending" here.iter_size here.num_iterations + Bench.measure (random_vec.sort) "Random Elements Ascending" here.iter_size here.num_iterations + Bench.measure (random_vec.sort order=Sort_Order.Descending) "Random Elements Descending" here.iter_size here.num_iterations + Bench.measure (random_vec.sort on=projection) "Sorting with a Custom Projection" here.iter_size here.num_iterations + Bench.measure (random_vec.sort by=comparator) "Sorting with a Custom Comparison" here.iter_size here.num_iterations diff --git a/test/Table_Tests/src/Matching_Spec.enso b/test/Table_Tests/src/Matching_Spec.enso index 776f8bc437bbd..eb2f0a792f543 100644 --- a/test/Table_Tests/src/Matching_Spec.enso +++ b/test/Table_Tests/src/Matching_Spec.enso @@ -79,7 +79,7 @@ spec = Test.group 'Matching Helper' <| Matching.match_criteria (Error.throw Foo_Error) [] . should_fail_with Foo_Error Matching.match_criteria [] (Error.throw Foo_Error) . should_fail_with Foo_Error Matching.match_criteria [] [] (Error.throw Foo_Error) . should_fail_with Foo_Error - Matching.match_criteria ["a"] ["a"] name_mapper=(_-> Error.throw Foo_Error) . should_fail_with Foo_Error + Matching.match_criteria [1, 2, 3] ["2"] name_mapper=(x-> if x == 3 then Error.throw Foo_Error else x.to_text) . should_fail_with Foo_Error Matching.match_criteria ["a"] ["a"] name_mapper=_.nonexistent_function . should_fail_with No_Such_Method_Error main = Test.Suite.run_main here.spec diff --git a/test/Tests/src/Data/Vector_Spec.enso b/test/Tests/src/Data/Vector_Spec.enso index a890b336d29d1..c724f70de221f 100644 --- a/test/Tests/src/Data/Vector_Spec.enso +++ b/test/Tests/src/Data/Vector_Spec.enso @@ -26,8 +26,18 @@ spec = Test.group "Vectors" <| built . should_equal [1, 2, 3, 4, 5] Test.specify "should allow accessing elements" <| + [1,2,3].at 0 . should_equal 1 [1,2,3].at 2 . should_equal 3 + Test.specify "should allow accessing elements with negative indices" <| + [1,2,3].at -1 . should_equal 3 + [1,2,3].at -2 . should_equal 2 + [1,2,3].at -3 . should_equal 1 + + Test.specify "should return a dataflow error when accessing elements out of bounds" <| + [1,2,3].at -4 . should_fail_with Vector.Index_Out_Of_Bounds_Error + [1,2,3].at 3 . should_fail_with Vector.Index_Out_Of_Bounds_Error + Test.specify "should have a well-defined length" <| [1,2,3].length . should_equal 3