complex-range 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- complex_range-1.0.0/CHANGELOG.md +44 -0
- complex_range-1.0.0/LICENSE +21 -0
- complex_range-1.0.0/MANIFEST.in +12 -0
- complex_range-1.0.0/PKG-INFO +330 -0
- complex_range-1.0.0/README.md +287 -0
- complex_range-1.0.0/pyproject.toml +129 -0
- complex_range-1.0.0/pytest.ini +6 -0
- complex_range-1.0.0/setup.cfg +4 -0
- complex_range-1.0.0/src/complex_range/__init__.py +25 -0
- complex_range-1.0.0/src/complex_range/core.py +549 -0
- complex_range-1.0.0/src/complex_range/dev.py +41 -0
- complex_range-1.0.0/src/complex_range/farey.py +84 -0
- complex_range-1.0.0/src/complex_range/py.typed +0 -0
- complex_range-1.0.0/src/complex_range.egg-info/PKG-INFO +330 -0
- complex_range-1.0.0/src/complex_range.egg-info/SOURCES.txt +18 -0
- complex_range-1.0.0/src/complex_range.egg-info/dependency_links.txt +1 -0
- complex_range-1.0.0/src/complex_range.egg-info/requires.txt +12 -0
- complex_range-1.0.0/src/complex_range.egg-info/top_level.txt +1 -0
- complex_range-1.0.0/tests/__init__.py +1 -0
- complex_range-1.0.0/tests/test_complex_range.py +549 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2025-02-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release
|
|
13
|
+
- `complex_range()` function for generating complex number ranges
|
|
14
|
+
- Rectangular range support (2D grids in complex plane)
|
|
15
|
+
- Linear range support (diagonal sequences)
|
|
16
|
+
- Custom step sizes (complex or tuple format)
|
|
17
|
+
- Support for negative steps in descending ranges
|
|
18
|
+
- `increment_first` option to control iteration order ('im' or 're')
|
|
19
|
+
- `farey_range` option for Farey sequence subdivision
|
|
20
|
+
- `farey_sequence()` function for generating Farey sequences
|
|
21
|
+
- `ComplexRangeError` exception for error handling
|
|
22
|
+
- Comprehensive test suite
|
|
23
|
+
- Full type hints
|
|
24
|
+
- Complete documentation
|
|
25
|
+
- Development utilities module (`complex_range.dev`)
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
- **Rectangular ranges**: Generate 2D grids between two complex corners
|
|
30
|
+
- **Linear ranges**: Generate points along diagonals using list syntax
|
|
31
|
+
- **Flexible stepping**: Independent control of real and imaginary step sizes
|
|
32
|
+
- **Negative steps**: Support for descending ranges
|
|
33
|
+
- **Farey subdivision**: Create refined grids using number-theoretic sequences
|
|
34
|
+
- **Pure Python**: No external dependencies required
|
|
35
|
+
- **Python 3.8+**: Compatible with Python 3.8 and later
|
|
36
|
+
|
|
37
|
+
## [Unreleased]
|
|
38
|
+
|
|
39
|
+
### Planned
|
|
40
|
+
|
|
41
|
+
- NumPy array output option
|
|
42
|
+
- Iterator/generator versions for memory efficiency
|
|
43
|
+
- Polar coordinate range support
|
|
44
|
+
- Additional subdivision methods
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Daniele Gregori
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
include pytest.ini
|
|
6
|
+
|
|
7
|
+
recursive-include src/complex_range *.py *.pyi py.typed
|
|
8
|
+
recursive-include tests *.py
|
|
9
|
+
|
|
10
|
+
global-exclude __pycache__
|
|
11
|
+
global-exclude *.py[cod]
|
|
12
|
+
global-exclude .DS_Store
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: complex-range
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Generate ranges of complex numbers - rectangular grids and linear sequences in the complex plane
|
|
5
|
+
Author-email: Daniele Gregori <dangregori@gmail.com>
|
|
6
|
+
Maintainer-email: Daniele Gregori <dangregori@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://pypi.org/project/complex-range
|
|
9
|
+
Project-URL: Documentation, https://resources.wolframcloud.com/FunctionRepository/resources/ComplexRange/
|
|
10
|
+
Project-URL: Repository, https://github.com/Daniele-Gregori/PyPI-packages
|
|
11
|
+
Project-URL: Issues, https://github.com/Daniele-Gregori/PyPI-packages/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/Daniele-Gregori/PyPI-packages/blob/main/CHANGELOG.md
|
|
13
|
+
Keywords: complex,numbers,range,grid,mathematics,farey,sequence,complex-plane
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Intended Audience :: Education
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
27
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.8
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
35
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
36
|
+
Requires-Dist: isort>=5.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
38
|
+
Requires-Dist: flake8>=6.0; extra == "dev"
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: sphinx>=6.0; extra == "docs"
|
|
41
|
+
Requires-Dist: sphinx-rtd-theme>=1.0; extra == "docs"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# complex-range
|
|
45
|
+
|
|
46
|
+
[](https://badge.fury.io/py/complex-range)
|
|
47
|
+
[](https://pypi.org/project/complex-range/)
|
|
48
|
+
[](https://opensource.org/licenses/MIT)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
Generate ranges of complex numbers in Python - rectangular grids and linear sequences in the complex plane.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install complex-range
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from complex_range import complex_range
|
|
64
|
+
|
|
65
|
+
# Rectangular grid from origin to 2+2j
|
|
66
|
+
grid = complex_range(0, 2+2j)
|
|
67
|
+
# [0j, 1j, 2j, (1+0j), (1+1j), (1+2j), (2+0j), (2+1j), (2+2j)]
|
|
68
|
+
|
|
69
|
+
# Linear range along a diagonal
|
|
70
|
+
line = complex_range([0, 3+3j])
|
|
71
|
+
# [0j, (1+1j), (2+2j), (3+3j)]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
- **Rectangular ranges**: Generate 2D grids of complex numbers
|
|
77
|
+
- **Linear ranges**: Generate points along a line in the complex plane
|
|
78
|
+
- **Flexible step sizes**: Control spacing independently for real and imaginary axes
|
|
79
|
+
- **Negative steps**: Support for descending ranges with negative step values
|
|
80
|
+
- **Farey sequence subdivision**: Create refined grids using number-theoretic sequences
|
|
81
|
+
- **Iteration order control**: Choose whether to iterate real or imaginary component first
|
|
82
|
+
- **Pure Python**: No dependencies required
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
### Rectangular Ranges
|
|
87
|
+
|
|
88
|
+
Generate a grid of complex numbers between two corners:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from complex_range import complex_range
|
|
92
|
+
|
|
93
|
+
# Basic rectangular range
|
|
94
|
+
complex_range(0, 2+2j)
|
|
95
|
+
# Returns: [0j, 1j, 2j, (1+0j), (1+1j), (1+2j), (2+0j), (2+1j), (2+2j)]
|
|
96
|
+
|
|
97
|
+
# Single argument: range from 0 to z
|
|
98
|
+
complex_range(2+3j)
|
|
99
|
+
# Returns grid from 0 to 2+3j (3×4 = 12 points)
|
|
100
|
+
|
|
101
|
+
# With custom step size (complex number)
|
|
102
|
+
complex_range(0, 2+2j, 0.5+0.5j)
|
|
103
|
+
# Real step = 0.5, Imaginary step = 0.5
|
|
104
|
+
|
|
105
|
+
# With separate real and imaginary steps
|
|
106
|
+
complex_range(0, 4+6j, [2, 3])
|
|
107
|
+
# Real step = 2, Imaginary step = 3
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Linear Ranges
|
|
111
|
+
|
|
112
|
+
Generate points along a line (diagonal) in the complex plane:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# Linear from 0 to endpoint
|
|
116
|
+
complex_range([3+3j])
|
|
117
|
+
# Returns: [0j, (1+1j), (2+2j), (3+3j)]
|
|
118
|
+
|
|
119
|
+
# Linear between two points
|
|
120
|
+
complex_range([-1-1j, 2+2j])
|
|
121
|
+
# Returns: [(-1-1j), 0j, (1+1j), (2+2j)]
|
|
122
|
+
|
|
123
|
+
# Linear with custom step
|
|
124
|
+
complex_range([0, 4+4j], [2, 2])
|
|
125
|
+
# Returns: [0j, (2+2j), (4+4j)]
|
|
126
|
+
|
|
127
|
+
# Linear with complex step
|
|
128
|
+
complex_range([0, 4+4j], 2+2j)
|
|
129
|
+
# Returns: [0j, (2+2j), (4+4j)]
|
|
130
|
+
|
|
131
|
+
# Descending linear range with negative step
|
|
132
|
+
complex_range([2+2j, 0], -1-1j)
|
|
133
|
+
# Returns: [(2+2j), (1+1j), 0j]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Options
|
|
137
|
+
|
|
138
|
+
#### `increment_first`
|
|
139
|
+
|
|
140
|
+
Control the iteration order for rectangular ranges:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
# Default: increment imaginary first
|
|
144
|
+
complex_range(0, 2+2j, 1+1j, increment_first='im')
|
|
145
|
+
# [0j, 1j, 2j, (1+0j), (1+1j), (1+2j), (2+0j), (2+1j), (2+2j)]
|
|
146
|
+
|
|
147
|
+
# Increment real first
|
|
148
|
+
complex_range(0, 2+2j, 1+1j, increment_first='re')
|
|
149
|
+
# [0j, (1+0j), (2+0j), 1j, (1+1j), (2+1j), 2j, (1+2j), (2+2j)]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### `farey_range`
|
|
153
|
+
|
|
154
|
+
Use Farey sequence to create a finer subdivision of the grid:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# Regular grid
|
|
158
|
+
regular = complex_range(0, 4+4j, 2+2j)
|
|
159
|
+
# Returns 9 points
|
|
160
|
+
|
|
161
|
+
# Farey subdivision (step must be integer)
|
|
162
|
+
farey = complex_range(0, 4+4j, 2+2j, farey_range=True)
|
|
163
|
+
# Returns 81 points using Farey sequence F_2
|
|
164
|
+
|
|
165
|
+
# Farey sequence of order n creates fractions 0, 1/n, ..., 1
|
|
166
|
+
from complex_range import farey_sequence
|
|
167
|
+
farey_sequence(3)
|
|
168
|
+
# [Fraction(0,1), Fraction(1,3), Fraction(1,2), Fraction(2,3), Fraction(1,1)]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## API Reference
|
|
172
|
+
|
|
173
|
+
### `complex_range(z1, z2=None, step=None, *, increment_first='im', farey_range=False)`
|
|
174
|
+
|
|
175
|
+
Generate a range of complex numbers.
|
|
176
|
+
|
|
177
|
+
**Parameters:**
|
|
178
|
+
|
|
179
|
+
| Parameter | Type | Description |
|
|
180
|
+
|-----------|------|-------------|
|
|
181
|
+
| `z1` | `complex`, `list`, or `tuple` | First corner (rectangular) or endpoint specification (linear) |
|
|
182
|
+
| `z2` | `complex`, optional | Second corner for rectangular range |
|
|
183
|
+
| `step` | `complex`, `list`, or `tuple`, optional | Step size(s). Default: `1+1j` |
|
|
184
|
+
| `increment_first` | `'im'` or `'re'` | Which component to iterate first. Default: `'im'` |
|
|
185
|
+
| `farey_range` | `bool` | Use Farey sequence subdivision. Default: `False` |
|
|
186
|
+
|
|
187
|
+
**Returns:** `List[complex]` - List of complex numbers
|
|
188
|
+
|
|
189
|
+
**Raises:** `ComplexRangeError` - If `farey_range=True` with non-integer step
|
|
190
|
+
|
|
191
|
+
### `farey_sequence(n)`
|
|
192
|
+
|
|
193
|
+
Generate the Farey sequence of order n.
|
|
194
|
+
|
|
195
|
+
**Parameters:**
|
|
196
|
+
|
|
197
|
+
| Parameter | Type | Description |
|
|
198
|
+
|-----------|------|-------------|
|
|
199
|
+
| `n` | `int` | Order of the Farey sequence (must be positive) |
|
|
200
|
+
|
|
201
|
+
**Returns:** `List[Fraction]` - Sorted list of fractions in [0, 1]
|
|
202
|
+
|
|
203
|
+
## Understanding the Ranges
|
|
204
|
+
|
|
205
|
+
### Rectangular Range
|
|
206
|
+
|
|
207
|
+
A rectangular range generates all points on a 2D grid:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
Im ↑
|
|
211
|
+
3 │ · · ·
|
|
212
|
+
2 │ · · ·
|
|
213
|
+
1 │ · · ·
|
|
214
|
+
0 │ · · ·
|
|
215
|
+
└──────────→ Re
|
|
216
|
+
0 1 2
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
With `increment_first='im'` (default), points are generated column by column:
|
|
220
|
+
`(0,0), (0,1), (0,2), (0,3), (1,0), (1,1), ...`
|
|
221
|
+
|
|
222
|
+
### Linear Range
|
|
223
|
+
|
|
224
|
+
A linear range generates points along a diagonal:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
Im ↑
|
|
228
|
+
3 │ ·
|
|
229
|
+
2 │ ·
|
|
230
|
+
1 │ ·
|
|
231
|
+
0 │·
|
|
232
|
+
└──────────→ Re
|
|
233
|
+
0 1 2 3
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Points increment along both axes simultaneously.
|
|
237
|
+
|
|
238
|
+
## Examples
|
|
239
|
+
|
|
240
|
+
### Visualizing a Rectangular Grid
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
import matplotlib.pyplot as plt
|
|
244
|
+
from complex_range import complex_range
|
|
245
|
+
|
|
246
|
+
points = complex_range(0, 3+3j)
|
|
247
|
+
x = [p.real for p in points]
|
|
248
|
+
y = [p.imag for p in points]
|
|
249
|
+
|
|
250
|
+
plt.scatter(x, y)
|
|
251
|
+
plt.xlabel('Real')
|
|
252
|
+
plt.ylabel('Imaginary')
|
|
253
|
+
plt.title('Rectangular Complex Range')
|
|
254
|
+
plt.grid(True)
|
|
255
|
+
plt.show()
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Creating a Refined Grid with Farey Sequence
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from complex_range import complex_range
|
|
262
|
+
|
|
263
|
+
# Coarse grid: 3×3 = 9 points
|
|
264
|
+
coarse = complex_range(0, 2+2j, 1+1j)
|
|
265
|
+
|
|
266
|
+
# Refined grid using Farey sequence
|
|
267
|
+
refined = complex_range(0, 2+2j, 2+2j, farey_range=True)
|
|
268
|
+
print(f"Coarse: {len(coarse)} points, Refined: {len(refined)} points")
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Iterating Over Complex Regions
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from complex_range import complex_range
|
|
275
|
+
|
|
276
|
+
# Evaluate a function over a region of the complex plane
|
|
277
|
+
def mandelbrot_escape(c, max_iter=100):
|
|
278
|
+
z = 0
|
|
279
|
+
for i in range(max_iter):
|
|
280
|
+
z = z*z + c
|
|
281
|
+
if abs(z) > 2:
|
|
282
|
+
return i
|
|
283
|
+
return max_iter
|
|
284
|
+
|
|
285
|
+
# Create a grid and evaluate
|
|
286
|
+
grid = complex_range(-2-1.5j, 1+1.5j, [0.1, 0.1])
|
|
287
|
+
escapes = [mandelbrot_escape(c) for c in grid]
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Author
|
|
291
|
+
|
|
292
|
+
**Daniele Gregori**
|
|
293
|
+
|
|
294
|
+
- Original [Wolfram Language ComplexRange](https://resources.wolframcloud.com/FunctionRepository/resources/ComplexRange/) function
|
|
295
|
+
- Python implementation
|
|
296
|
+
|
|
297
|
+
## Contributing
|
|
298
|
+
|
|
299
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
# Clone the repository
|
|
303
|
+
git clone https://github.com/Daniele-Gregori/PyPI-packages.git
|
|
304
|
+
cd PyPI-packages/packages/complex-range
|
|
305
|
+
|
|
306
|
+
# Install development dependencies
|
|
307
|
+
pip install -e ".[dev]"
|
|
308
|
+
|
|
309
|
+
# Run tests
|
|
310
|
+
pytest
|
|
311
|
+
|
|
312
|
+
# Run type checking
|
|
313
|
+
mypy src/complex_range
|
|
314
|
+
|
|
315
|
+
# Format code
|
|
316
|
+
black src tests
|
|
317
|
+
isort src tests
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## License
|
|
321
|
+
|
|
322
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
323
|
+
|
|
324
|
+
## Acknowledgments
|
|
325
|
+
|
|
326
|
+
Original [Wolfram Language ComplexRange](https://resources.wolframcloud.com/FunctionRepository/resources/ComplexRange/) resource function contributed by Daniele Gregori and reviewed by the Wolfram Review Team.
|
|
327
|
+
|
|
328
|
+
## Changelog
|
|
329
|
+
|
|
330
|
+
See [CHANGELOG.md](CHANGELOG.md) for a list of changes.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# complex-range
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/complex-range)
|
|
4
|
+
[](https://pypi.org/project/complex-range/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Generate ranges of complex numbers in Python - rectangular grids and linear sequences in the complex plane.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install complex-range
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from complex_range import complex_range
|
|
21
|
+
|
|
22
|
+
# Rectangular grid from origin to 2+2j
|
|
23
|
+
grid = complex_range(0, 2+2j)
|
|
24
|
+
# [0j, 1j, 2j, (1+0j), (1+1j), (1+2j), (2+0j), (2+1j), (2+2j)]
|
|
25
|
+
|
|
26
|
+
# Linear range along a diagonal
|
|
27
|
+
line = complex_range([0, 3+3j])
|
|
28
|
+
# [0j, (1+1j), (2+2j), (3+3j)]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **Rectangular ranges**: Generate 2D grids of complex numbers
|
|
34
|
+
- **Linear ranges**: Generate points along a line in the complex plane
|
|
35
|
+
- **Flexible step sizes**: Control spacing independently for real and imaginary axes
|
|
36
|
+
- **Negative steps**: Support for descending ranges with negative step values
|
|
37
|
+
- **Farey sequence subdivision**: Create refined grids using number-theoretic sequences
|
|
38
|
+
- **Iteration order control**: Choose whether to iterate real or imaginary component first
|
|
39
|
+
- **Pure Python**: No dependencies required
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Rectangular Ranges
|
|
44
|
+
|
|
45
|
+
Generate a grid of complex numbers between two corners:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from complex_range import complex_range
|
|
49
|
+
|
|
50
|
+
# Basic rectangular range
|
|
51
|
+
complex_range(0, 2+2j)
|
|
52
|
+
# Returns: [0j, 1j, 2j, (1+0j), (1+1j), (1+2j), (2+0j), (2+1j), (2+2j)]
|
|
53
|
+
|
|
54
|
+
# Single argument: range from 0 to z
|
|
55
|
+
complex_range(2+3j)
|
|
56
|
+
# Returns grid from 0 to 2+3j (3×4 = 12 points)
|
|
57
|
+
|
|
58
|
+
# With custom step size (complex number)
|
|
59
|
+
complex_range(0, 2+2j, 0.5+0.5j)
|
|
60
|
+
# Real step = 0.5, Imaginary step = 0.5
|
|
61
|
+
|
|
62
|
+
# With separate real and imaginary steps
|
|
63
|
+
complex_range(0, 4+6j, [2, 3])
|
|
64
|
+
# Real step = 2, Imaginary step = 3
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Linear Ranges
|
|
68
|
+
|
|
69
|
+
Generate points along a line (diagonal) in the complex plane:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
# Linear from 0 to endpoint
|
|
73
|
+
complex_range([3+3j])
|
|
74
|
+
# Returns: [0j, (1+1j), (2+2j), (3+3j)]
|
|
75
|
+
|
|
76
|
+
# Linear between two points
|
|
77
|
+
complex_range([-1-1j, 2+2j])
|
|
78
|
+
# Returns: [(-1-1j), 0j, (1+1j), (2+2j)]
|
|
79
|
+
|
|
80
|
+
# Linear with custom step
|
|
81
|
+
complex_range([0, 4+4j], [2, 2])
|
|
82
|
+
# Returns: [0j, (2+2j), (4+4j)]
|
|
83
|
+
|
|
84
|
+
# Linear with complex step
|
|
85
|
+
complex_range([0, 4+4j], 2+2j)
|
|
86
|
+
# Returns: [0j, (2+2j), (4+4j)]
|
|
87
|
+
|
|
88
|
+
# Descending linear range with negative step
|
|
89
|
+
complex_range([2+2j, 0], -1-1j)
|
|
90
|
+
# Returns: [(2+2j), (1+1j), 0j]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Options
|
|
94
|
+
|
|
95
|
+
#### `increment_first`
|
|
96
|
+
|
|
97
|
+
Control the iteration order for rectangular ranges:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
# Default: increment imaginary first
|
|
101
|
+
complex_range(0, 2+2j, 1+1j, increment_first='im')
|
|
102
|
+
# [0j, 1j, 2j, (1+0j), (1+1j), (1+2j), (2+0j), (2+1j), (2+2j)]
|
|
103
|
+
|
|
104
|
+
# Increment real first
|
|
105
|
+
complex_range(0, 2+2j, 1+1j, increment_first='re')
|
|
106
|
+
# [0j, (1+0j), (2+0j), 1j, (1+1j), (2+1j), 2j, (1+2j), (2+2j)]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### `farey_range`
|
|
110
|
+
|
|
111
|
+
Use Farey sequence to create a finer subdivision of the grid:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
# Regular grid
|
|
115
|
+
regular = complex_range(0, 4+4j, 2+2j)
|
|
116
|
+
# Returns 9 points
|
|
117
|
+
|
|
118
|
+
# Farey subdivision (step must be integer)
|
|
119
|
+
farey = complex_range(0, 4+4j, 2+2j, farey_range=True)
|
|
120
|
+
# Returns 81 points using Farey sequence F_2
|
|
121
|
+
|
|
122
|
+
# Farey sequence of order n creates fractions 0, 1/n, ..., 1
|
|
123
|
+
from complex_range import farey_sequence
|
|
124
|
+
farey_sequence(3)
|
|
125
|
+
# [Fraction(0,1), Fraction(1,3), Fraction(1,2), Fraction(2,3), Fraction(1,1)]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## API Reference
|
|
129
|
+
|
|
130
|
+
### `complex_range(z1, z2=None, step=None, *, increment_first='im', farey_range=False)`
|
|
131
|
+
|
|
132
|
+
Generate a range of complex numbers.
|
|
133
|
+
|
|
134
|
+
**Parameters:**
|
|
135
|
+
|
|
136
|
+
| Parameter | Type | Description |
|
|
137
|
+
|-----------|------|-------------|
|
|
138
|
+
| `z1` | `complex`, `list`, or `tuple` | First corner (rectangular) or endpoint specification (linear) |
|
|
139
|
+
| `z2` | `complex`, optional | Second corner for rectangular range |
|
|
140
|
+
| `step` | `complex`, `list`, or `tuple`, optional | Step size(s). Default: `1+1j` |
|
|
141
|
+
| `increment_first` | `'im'` or `'re'` | Which component to iterate first. Default: `'im'` |
|
|
142
|
+
| `farey_range` | `bool` | Use Farey sequence subdivision. Default: `False` |
|
|
143
|
+
|
|
144
|
+
**Returns:** `List[complex]` - List of complex numbers
|
|
145
|
+
|
|
146
|
+
**Raises:** `ComplexRangeError` - If `farey_range=True` with non-integer step
|
|
147
|
+
|
|
148
|
+
### `farey_sequence(n)`
|
|
149
|
+
|
|
150
|
+
Generate the Farey sequence of order n.
|
|
151
|
+
|
|
152
|
+
**Parameters:**
|
|
153
|
+
|
|
154
|
+
| Parameter | Type | Description |
|
|
155
|
+
|-----------|------|-------------|
|
|
156
|
+
| `n` | `int` | Order of the Farey sequence (must be positive) |
|
|
157
|
+
|
|
158
|
+
**Returns:** `List[Fraction]` - Sorted list of fractions in [0, 1]
|
|
159
|
+
|
|
160
|
+
## Understanding the Ranges
|
|
161
|
+
|
|
162
|
+
### Rectangular Range
|
|
163
|
+
|
|
164
|
+
A rectangular range generates all points on a 2D grid:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
Im ↑
|
|
168
|
+
3 │ · · ·
|
|
169
|
+
2 │ · · ·
|
|
170
|
+
1 │ · · ·
|
|
171
|
+
0 │ · · ·
|
|
172
|
+
└──────────→ Re
|
|
173
|
+
0 1 2
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
With `increment_first='im'` (default), points are generated column by column:
|
|
177
|
+
`(0,0), (0,1), (0,2), (0,3), (1,0), (1,1), ...`
|
|
178
|
+
|
|
179
|
+
### Linear Range
|
|
180
|
+
|
|
181
|
+
A linear range generates points along a diagonal:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
Im ↑
|
|
185
|
+
3 │ ·
|
|
186
|
+
2 │ ·
|
|
187
|
+
1 │ ·
|
|
188
|
+
0 │·
|
|
189
|
+
└──────────→ Re
|
|
190
|
+
0 1 2 3
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Points increment along both axes simultaneously.
|
|
194
|
+
|
|
195
|
+
## Examples
|
|
196
|
+
|
|
197
|
+
### Visualizing a Rectangular Grid
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
import matplotlib.pyplot as plt
|
|
201
|
+
from complex_range import complex_range
|
|
202
|
+
|
|
203
|
+
points = complex_range(0, 3+3j)
|
|
204
|
+
x = [p.real for p in points]
|
|
205
|
+
y = [p.imag for p in points]
|
|
206
|
+
|
|
207
|
+
plt.scatter(x, y)
|
|
208
|
+
plt.xlabel('Real')
|
|
209
|
+
plt.ylabel('Imaginary')
|
|
210
|
+
plt.title('Rectangular Complex Range')
|
|
211
|
+
plt.grid(True)
|
|
212
|
+
plt.show()
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Creating a Refined Grid with Farey Sequence
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
from complex_range import complex_range
|
|
219
|
+
|
|
220
|
+
# Coarse grid: 3×3 = 9 points
|
|
221
|
+
coarse = complex_range(0, 2+2j, 1+1j)
|
|
222
|
+
|
|
223
|
+
# Refined grid using Farey sequence
|
|
224
|
+
refined = complex_range(0, 2+2j, 2+2j, farey_range=True)
|
|
225
|
+
print(f"Coarse: {len(coarse)} points, Refined: {len(refined)} points")
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Iterating Over Complex Regions
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
from complex_range import complex_range
|
|
232
|
+
|
|
233
|
+
# Evaluate a function over a region of the complex plane
|
|
234
|
+
def mandelbrot_escape(c, max_iter=100):
|
|
235
|
+
z = 0
|
|
236
|
+
for i in range(max_iter):
|
|
237
|
+
z = z*z + c
|
|
238
|
+
if abs(z) > 2:
|
|
239
|
+
return i
|
|
240
|
+
return max_iter
|
|
241
|
+
|
|
242
|
+
# Create a grid and evaluate
|
|
243
|
+
grid = complex_range(-2-1.5j, 1+1.5j, [0.1, 0.1])
|
|
244
|
+
escapes = [mandelbrot_escape(c) for c in grid]
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Author
|
|
248
|
+
|
|
249
|
+
**Daniele Gregori**
|
|
250
|
+
|
|
251
|
+
- Original [Wolfram Language ComplexRange](https://resources.wolframcloud.com/FunctionRepository/resources/ComplexRange/) function
|
|
252
|
+
- Python implementation
|
|
253
|
+
|
|
254
|
+
## Contributing
|
|
255
|
+
|
|
256
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Clone the repository
|
|
260
|
+
git clone https://github.com/Daniele-Gregori/PyPI-packages.git
|
|
261
|
+
cd PyPI-packages/packages/complex-range
|
|
262
|
+
|
|
263
|
+
# Install development dependencies
|
|
264
|
+
pip install -e ".[dev]"
|
|
265
|
+
|
|
266
|
+
# Run tests
|
|
267
|
+
pytest
|
|
268
|
+
|
|
269
|
+
# Run type checking
|
|
270
|
+
mypy src/complex_range
|
|
271
|
+
|
|
272
|
+
# Format code
|
|
273
|
+
black src tests
|
|
274
|
+
isort src tests
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
280
|
+
|
|
281
|
+
## Acknowledgments
|
|
282
|
+
|
|
283
|
+
Original [Wolfram Language ComplexRange](https://resources.wolframcloud.com/FunctionRepository/resources/ComplexRange/) resource function contributed by Daniele Gregori and reviewed by the Wolfram Review Team.
|
|
284
|
+
|
|
285
|
+
## Changelog
|
|
286
|
+
|
|
287
|
+
See [CHANGELOG.md](CHANGELOG.md) for a list of changes.
|