Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_util clean up and ring #528

Merged
merged 3 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions automol/util/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ def partner(pair: Collection, item: Any) -> Any:

def flatten(lst: Collection) -> Iterator:
"""Flatten an arbitrarily nested list of lists (iterator).

Source: https://stackoverflow.com/a/2158532
Source: https://stackoverflow.com/a/2158532 .
:param lst: An arbitrarily nested list or tuple
:return: An iterator over the flattened list of values.
"""
for elem in lst:
if isinstance(elem, Iterable) and not isinstance(elem, str | bytes):
Expand Down Expand Up @@ -72,7 +73,7 @@ def is_odd_permutation(seq1: list, seq2: list) -> bool:
return not is_even_permutation(seq1, seq2)


def is_even_permutation(seq1: list, seq2: list, check: bool = True) -> bool:
def is_even_permutation(seq1: Sequence, seq2: Sequence, check: bool = True) -> bool:
"""Determine whether a permutation of a sequence is even.

:param seq1: The first sequence
Expand Down Expand Up @@ -189,34 +190,48 @@ def move_items_to_front(lst: Sequence, items) -> tuple:
return tuple(lst)


def breakby(lst: Collection, elem) -> tuple[tuple, tuple]:
def breakby(lst: Sequence, elem) -> tuple[tuple, tuple]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Break a list by element, dropping the element itself.

Analogous to '<char>'.split('<string>') for strings.
:param lst: The list
:param elem: The element to break the list by, gets deleted
:return:The chunks between the break points of the input list.
"""
lsts = tuple(
tuple(g) for k, g in itertools.groupby(lst, lambda x: x == elem) if not k
)
return lsts


def separate_negatives(lst: Sequence):
"""Seperate a list of numbers into negative and nonnegative (>= 0)."""
def separate_negatives(lst: Sequence) -> tuple[tuple, tuple]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Seperate a list of numbers into negative and nonnegative (>= 0).
:param lst: The list
:return: Value for negatives and for non-negatives.
"""
neg_lst = tuple(val for val in lst if val < 0)
pos_lst = tuple(val for val in lst if val >= 0)

return neg_lst, pos_lst


def value_similar_to(val: float, lst: Collection[float], thresh: float) -> bool:
"""Check if a value is close to some lst of values within some threshold."""
def value_similar_to(val: float, lst: Sequence[float], thresh: float) -> bool:
"""Check if a value is close to any one of a list of values.
:param val: A number.
:param lst: A collection of numbers to compare to.
:param thresh: The comparison threshold.
:return: 'True' if close, 'False' if not.
"""
return any(abs(val - vali) < thresh for vali in lst)


def scale_iterable(
iterable: Collection[float], scale_factor: float
) -> Collection[float]:
"""Scale some type of iterable of floats by a scale factor."""
"""Scale some type of iterable of floats by a scale factor.
:param iterable: A list of numbers.
:param scale_factor: A factor to scale by.
:return: The scaled list of numbers.
"""
if isinstance(iterable, list):
iterable = [val * scale_factor for val in iterable]
elif isinstance(iterable, tuple):
Expand All @@ -225,8 +240,13 @@ def scale_iterable(
return iterable


def remove_duplicates_with_order(lst: list):
"""Remove all duplicates of a list while not reordering the list."""
def remove_duplicates_with_order(lst: Sequence) -> Sequence:
"""Remove all duplicates of a list while not reordering the list.
:param lst: A list.
:return: A list, without duplicates.
Note: To be deprecated
and replaced with calls to more_itertools.unique_justseen.
"""
if isinstance(lst, list):
lst = [n for i, n in enumerate(lst) if n not in lst[:i]]
if isinstance(lst, tuple):
Expand Down
5 changes: 2 additions & 3 deletions automol/util/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ def string(mat: Sequence[Sequence[float]], val_format="{0:>8.3f}") -> str:
"""Write a matrix to a string.

:param mat: matrix to form string with
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
:type mat: tuple(tuple(float))
:param precision: number of integers past decimal
:type precision: int
:param val_format: A number-formatting string, such as "{:.3f}"
:return: Matrix as a string
"""
mat_str = ""
for row in mat:
Expand Down
72 changes: 22 additions & 50 deletions automol/util/ring.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
r"""Functions for dealing with a list of items encoding a ring

1---2
/ \
[1, 2, 3, 4, 5, 6] <=> 6 3
\ /
5---4
"""
"""Functions for dealing with a list of items encoding a ring."""

import itertools
from typing import List, Tuple

import more_itertools as mit


def normalize(items: List[object]) -> List[object]:
def normalize(items: list[object]) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Normalize the ordering of items in a ring.

:param items: The ring items
Expand All @@ -28,7 +20,7 @@ def normalize(items: List[object]) -> List[object]:
return cycle(items, count=items.index(start_item))


def cycle(items: List[object], count: int = 1) -> List[object]:
def cycle(items: list[object], count: int = 1) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Cycle ring items once.

Example: (1, 2, 3, 4) -> (2, 3, 4, 1)
Expand All @@ -42,7 +34,7 @@ def cycle(items: List[object], count: int = 1) -> List[object]:
return tuple(itertools.islice(cycler, nitems))


def edges(items: List[object]) -> List[object]:
def edges(items: list[object]) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Get the edge pairs of a ring.

Example: (1, 2, 3, 4) -> ((1, 2), (2, 3), (3, 4), (4, 1))
Expand All @@ -54,23 +46,18 @@ def edges(items: List[object]) -> List[object]:


def distance(
items: List[object], item1: object, item2: object, longest: bool = False
items: list[object], item1: object, item2: object, longest: bool = False
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
) -> int:
"""Find the distance between two items in a ring
"""Find the distance between two items in a ring.

By default, finds the shortest distance. Setting `longest=True` results in the
longest distance.

:param items: The ring items
:type items: List[object]
:param item1: The item to start measuring distance from
:type item1: object
:param item2: The item to measure distance to
:type item2: object
:param longest: Return the longest distance?, defaults to False
:type longest: bool, optional
:return: The number of ring items between these two
:rtype: int
"""
assert (
item1 in items and item2 in items
Expand All @@ -95,21 +82,17 @@ def distance(


def cycle_item_to_front(
items: List[object], item: object, end_item: object = None
) -> List[object]:
"""Cycle ring items until one is in front
items: list[object], item: object, end_item: object = None
) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Cycle ring items until one is in front.

Optionally, request one adjacent item to be at the end, reversing the ring order if
necessary.

:param items: The ring items
:type items: List[object]
:parm item: The item to cycle to the font
:type item: object
:param end_item: optionally, ensure that this is the last item in the ring
:type end_item: object
:returns: The ring items with `item` cycled to the front and `end_item` to the end
:rtype: List[int]
"""
items = cycle_items_to_front(items, [item])

Expand All @@ -124,16 +107,13 @@ def cycle_item_to_front(


def cycle_items_to_front(
items: List[object], front_items: List[object]
) -> List[object]:
"""Cycle ring items until a group of adjacent items is at the front of the list
items: list[object], front_items: list[object]
) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Cycle ring items until a group of adjacent items is at the front of the list.

:param items: The ring items
:type items: List[object]
:parm front_items: The item to cycle to the font
:type front_items: List[object]
:returns: The ring items with `item` cycled to the front and `end_item` to the end
:rtype: List[int]
"""
nitems = len(items)

Expand All @@ -149,15 +129,12 @@ def cycle_items_to_front(
return tuple(itertools.islice(cycler, nitems))


def cycle_items_to_back(items: List[object], back_items: List[object]) -> List[object]:
"""Cycle ring items until a group of adjacent items is at the end of the list
def cycle_items_to_back(items: list[object], back_items: list[object]) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Cycle ring items until a group of adjacent items is at the end of the list.

:param items: The ring items
:type items: List[object]
:parm back_items: The item to cycle to the end
:type back_items: List[object]
:returns: The ring items `back_items` cycled to the end
:rtype: List[int]
"""
nitems = len(items)

Expand All @@ -174,16 +151,15 @@ def cycle_items_to_back(items: List[object], back_items: List[object]) -> List[o


def cycle_to_split(
items: List[object], split_pair: Tuple[object, object]
) -> List[object]:
"""Cycle to split a pair of adjacent items, putting one on each end of the list
items: list[object], split_pair: tuple[object, object]
) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Cycle to split a pair of adjacent items, putting one on each end of the list.

:param items: The ring items
:type items: List[object]
:param split_pair: The pair of items to split
:type split_pair: Tuple[object, object]
:return: The ring items with one item in the pair at the start and one at the end
:rtype: List[object]
"""
nitems = len(items)
split_pair = set(split_pair)
Expand Down Expand Up @@ -211,21 +187,17 @@ def cycle_to_split(


def cycle_to_optimal_split(
items: List[object],
split_pairs: List[Tuple[object, object]],
back_items: List[object],
) -> List[object]:
items: list[object],
split_pairs: list[tuple[object, object]],
back_items: list[object],
) -> list[object]:
Rosalbam1 marked this conversation as resolved.
Show resolved Hide resolved
"""Cycle to find an "optimum split" that puts a subset of items as close as possible
to the end of the list
to the end of the list.

:param items: The ring items
:type items: List[object]
:param split_pairs: Pairs where the cycle can be split
:type split_pairs: List[Tuple[object, object]]
:param back_items: Adjacent items that should be as close to the end as possible
:type back_items: List[object]
:return: The cycle with the optimal split
:rtype: List[object]
"""
orig_items = items
split_pairs = list(split_pairs)
Expand Down
4 changes: 0 additions & 4 deletions docs/source/automol/heuristic.md

This file was deleted.

5 changes: 0 additions & 5 deletions docs/source/automol/matrix.md

This file was deleted.

14 changes: 14 additions & 0 deletions docs/source/automol/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,18 @@
some words
```{eval-rst}
.. automodule:: automol.util
```
## automol.util.heuristic
```{eval-rst}
.. automodule:: automol.util.heuristic
```
## automol.util.matrix
some words
```{eval-rst}
.. automodule:: automol.util.matrix
```
## automol.ring
some words
```{eval-rst}
.. automodule:: automol.util.ring
```
2 changes: 0 additions & 2 deletions docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@ Welcome to my documentation website...
:hidden:
automol/inchi_key.md
automol/util.md
automol/heuristic.md
automol/matrix.md
```
1 change: 1 addition & 0 deletions lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ FILES=(
"automol/util/__init__.py"
"automol/util/heuristic.py"
"automol/util/matrix.py"
"automol/util/ring.py"
)

(
Expand Down