maths icon indicating copy to clipboard operation
maths copied to clipboard

Make functions in the combinatoric/sequences modules iterator-based instead of list-based

Open NicklasXYZ opened this issue 5 months ago • 0 comments

The functions in the combinatorics and sequences modules could be improved by making them return an iterator instead of a list, which will be prohibitively expensive to do for larger inputs. See related comments and info by DanielSherlock:

No worries, I'm not in any rush (and I hope you aren't too)!

Actually, I thought after posting this pull request: Oh before I start writing tests and docs I should go and look at the standard (or standard-ish) libraries of other languages to see how they handle this case. Then I got distracted. And now it is now.

As far as I can tell, it's like this:

Language Behaviour A Behaviour B Iterator
Javascript (Deno) permutations
Ruby permutation
Scala permutations
Swift permutations uniquePermutations ✅ (Sequence)
Julia permutations multiset_permutations
Rust permutations
Nim nextPermutation ✅ (mutating)
C++ next_permutation ✅ (mutating)
Haskell permutations ✅ (everything is lazy)
Python permutations
Clojure permutations ✅ (lazy-seq)

(I had hoped to find a list-permuting function in the standard (or standard-ish) libraries of Erlang or Elixir, and prioritise similarity to that. But no luck, not even Elixir's Math library has this. Other languages that seem to have nothing (semi-)official include Java, Elm, and Lobster. Though perhaps I wasn't looking hard enough.)

Personally, I like the way Swift handles it. Plus, their documentation is clear (with examples) and also has some hints for possible efficient implementations. The Clojure implementation seem nice and clean too, and might be easy to port. Not all other documentation was similarly clear...

Another thing to note: Almost all of the languages I surveyed returned an iterator (or equivalent thing in that language), even when given a list/array/etc. If we are going to be worried about performance, we might consider doing the same. This after all exactly the sort of function where iterators make a lot of sense:

  • It does not take a particularly large input list for the output list to be very very large indeed.
  • The state needed to generate the next permutation is small.

Originally posted by @DanielSherlock in https://github.com/gleam-community/maths/issues/9#issuecomment-1811371118

NicklasXYZ avatar Jan 23 '24 13:01 NicklasXYZ