Thanks to visit codestin.com
Credit goes to github.com

Skip to content

m-stclair/mpermute

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mpermute

overview

Python extension for fast multiset permutations. Basically a straight C port of https://github.com/ekg/multipermute/, which is itself a straightforward implementation of "Loopless Generation of Multiset Permutations using a Constant Number of Variables by Prefix Shifts (Williams 2009). This implementation is 3-4x faster and slightly more space-efficient than the pure Python version.

It also exposes a backend function, unique, which is useful for counting unique elements of a collection (optionally grouped by a key function).

Experimental code. May crash your computer. Not suitable for any purpose. Use at your own peril.

requirements

  • Python >= 3.12
  • setuptools

installation

Install from source with pip install ..

examples of use

>>> from mpermute import mperms, mpermute, unique

>>> mpermute("akjj")

(('k', 'j', 'j', 'a'),
('a', 'k', 'j', 'j'),
('k', 'a', 'j', 'j'),
('j', 'k', 'a', 'j'),
('a', 'j', 'k', 'j'),
('j', 'a', 'k', 'j'),
('k', 'j', 'a', 'j'),
('j', 'k', 'j', 'a'),
('j', 'j', 'k', 'a'),
('a', 'j', 'j', 'k'),
('j', 'a', 'j', 'k'),
('j', 'j', 'a', 'k'))

>>> next(mperms("akjj")

('k', 'j', 'j', 'a')

>>> lists = [1], [2, 3], [9, 1], [1, 4]
>>> mpermute(lists + (lists[0],), )

(([9, 1], [2, 3], [1, 4], [1], [1]),
 ([1], [9, 1], [2, 3], [1, 4], [1]),
 ([9, 1], [1], [2, 3], [1, 4], [1]),
 ([2, 3], [9, 1], [1], [1, 4], [1]),
...

# when passed a second argument, all high-level functions in the `mpermute` 
# library will treat it as a 'key' function that defines equivalence classes.
# Outputs are guaranteed to include only one member of each equivalence class.
# This will _usually_ be the last member of that equivalence class, but this 
# behavior is not guaranteed.

>>> mpermute(lists + (lists[0],), lambda x, y: len(x) > len(y))

(([1], [1], [2, 3], [2, 3], [2, 3]),
 ([2, 3], [1], [1], [2, 3], [2, 3]),
 ([1], [2, 3], [1], [2, 3], [2, 3]),
 ([2, 3], [1], [2, 3], [1], [2, 3]),
 ([2, 3], [2, 3], [1], [1], [2, 3]),
 ([1], [2, 3], [2, 3], [1], [2, 3]),
 ([2, 3], [1], [2, 3], [2, 3], [1]),
 ([2, 3], [2, 3], [1], [2, 3], [1]),
 ([2, 3], [2, 3], [2, 3], [1], [1]),
 ([1], [2, 3], [2, 3], [2, 3], [1]))
 

# Calling unique(seq, keyfunc=None) should produce the same result as 
# `{k: seq.count(v) for v in set(seq)}`, but with roughly 10x performance (note 
# that order of dict keys is undefined in both cases).  It will generally also 
# produce significant speedups over pure-Python techniques when passed a key 
# function, although the ratio depends on how expensive the key function is.

>>> rands = [random.randint(0, 10000) for _ in range(1000000)] 
>>> unique(rands, lambda r: r % 3)

{645: 333306, 5839: 332940, 4193: 333754}

Tips

licensing

This library bears the BSD 3-clause license, copyright Michael St. Clair. Although it contains no verbatim code from https://github.com/ekg/multipermute, it is essentially a port of that library and also bears its license.

About

fast multiset permutations

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published