@@ -200,25 +200,10 @@ Springer Science & Business Media, **2013**.
200
200
"""
201
201
struct LexOrder <: AbstractMonomialOrdering end
202
202
203
- function compare (
204
- exp1:: AbstractVector{T} ,
205
- exp2:: AbstractVector{T} ,
206
- :: Type{LexOrder} ,
207
- ) where {T}
208
- if eachindex (exp1) != eachindex (exp2)
209
- throw (
210
- ArgumentError (
211
- " Cannot compare exponent vectors `$exp1 ` and `$exp2 ` of different indices." ,
212
- ),
213
- )
214
- end
215
- @inbounds for i in eachindex (exp1)
216
- Δ = exp1[i] - exp2[i]
217
- if ! iszero (Δ)
218
- return Δ
219
- end
220
- end
221
- return zero (T)
203
+ const _TupleOrVector = Union{Tuple,AbstractVector}
204
+
205
+ function compare (exp1:: _TupleOrVector , exp2:: _TupleOrVector , :: Type{LexOrder} )
206
+ return Base. cmp (exp1, exp2)
222
207
end
223
208
224
209
"""
@@ -239,25 +224,16 @@ SIAM Journal on Matrix Analysis and Applications, 34(1), 102-125, *2013*.
239
224
"""
240
225
struct InverseLexOrder <: AbstractMonomialOrdering end
241
226
227
+ # We can't use `Iterators.Reverse` because it's not an `AbstractVector`
228
+ # so not `cmp` methods is defined for it.
229
+ _rev (v:: AbstractVector ) = view (v, lastindex (v): - 1 : firstindex (v))
230
+ _rev (t:: Tuple ) = reverse (t)
242
231
function compare (
243
- exp1:: AbstractVector{T} ,
244
- exp2:: AbstractVector{T} ,
232
+ exp1:: _TupleOrVector ,
233
+ exp2:: _TupleOrVector ,
245
234
:: Type{InverseLexOrder} ,
246
- ) where {T}
247
- if eachindex (exp1) != eachindex (exp2)
248
- throw (
249
- ArgumentError (
250
- " Cannot compare exponent vectors `$exp1 ` and `$exp2 ` of different indices." ,
251
- ),
252
- )
253
- end
254
- @inbounds for i in Iterators. Reverse (eachindex (exp1))
255
- Δ = exp1[i] - exp2[i]
256
- if ! iszero (Δ)
257
- return Δ
258
- end
259
- end
260
- return zero (T)
235
+ )
236
+ return compare (_rev (exp1), _rev (exp2), LexOrder)
261
237
end
262
238
263
239
"""
@@ -316,3 +292,199 @@ compare(a, b, ::Type{Reverse{O}}) where {O} = compare(b, a, O)
316
292
Returns the [`AbstractMonomialOrdering`](@ref) used for the monomials of `p`.
317
293
"""
318
294
function ordering end
295
+
296
+ _last_lex_index (n, :: Type{LexOrder} ) = n
297
+ _prev_lex_index (i, :: Type{LexOrder} ) = i - 1
298
+ _not_first_indices (n, :: Type{LexOrder} ) = n: - 1 : 2
299
+ _last_lex_index (_, :: Type{InverseLexOrder} ) = 1
300
+ _prev_lex_index (i, :: Type{InverseLexOrder} ) = i + 1
301
+ _not_first_indices (n, :: Type{InverseLexOrder} ) = 1 : (n- 1 )
302
+ _last_lex_index (n, :: Type{Graded{M}} ) where {M} = _last_lex_index (n, M)
303
+ _prev_lex_index (i, :: Type{Graded{M}} ) where {M} = _prev_lex_index (i, M)
304
+ _not_first_indices (n, :: Type{Graded{M}} ) where {M} = _not_first_indices (n, M)
305
+
306
+ """
307
+ struct ExponentsIterator{M}(
308
+ object;
309
+ mindegree::Int = 0,
310
+ maxdegree::Union{Nothing,Int} = nothing,
311
+ inline::Bool = false,
312
+ )
313
+
314
+ An iterator for generating monomial exponents for monomial
315
+ ordering `M`. The type of the vector of exponents is the type of
316
+ `object` and is length (i.e., the number of variables) is `length(object)`.
317
+
318
+ Note that `object` does not have to be zero, it just needs to implement
319
+ `copy` and `setindex!` methods (except for `Tuple` which we handle with a
320
+ special case).
321
+
322
+ See also [`monomials`](@ref).
323
+
324
+ ### Examples
325
+
326
+ The following example shows how to generate all exponents of
327
+ monomials of 2 variables up to degree 2.
328
+ ```jldoctest
329
+ julia> collect(ExponentsIterator{Graded{LexOrder}}((0, 0), maxdegree = 2))
330
+ 6-element Vector{Tuple{Int64, Int64}}:
331
+ (0, 0)
332
+ (0, 1)
333
+ (1, 0)
334
+ (0, 2)
335
+ (1, 1)
336
+ (2, 0)
337
+ ```
338
+ Note that you can easily generate the tuple of exponents
339
+ of arbitrary length using `ntuple` as follows:
340
+ ```jldoctest
341
+ julia> collect(ExponentsIterator{Graded{LexOrder}}(ntuple(zero, 3), mindegree = 2, maxdegree = 2))
342
+ 6-element Vector{Tuple{Int64, Int64, Int64}}:
343
+ (0, 0, 2)
344
+ (0, 1, 1)
345
+ (0, 2, 0)
346
+ (1, 0, 1)
347
+ (1, 1, 0)
348
+ (2, 0, 0)
349
+ ```
350
+ You can also change the monomial ordering and use `Vector` instead of `Tuple` as follows:
351
+ ```jldoctest
352
+ julia> collect(ExponentsIterator{LexOrder}(zeros(Int, 2), mindegree = 2, maxdegree = 3))
353
+ 7-element Vector{Vector{Int64}}:
354
+ [0, 2]
355
+ [0, 3]
356
+ [1, 1]
357
+ [1, 2]
358
+ [2, 0]
359
+ [2, 1]
360
+ [3, 0]
361
+ ```
362
+ """
363
+ struct ExponentsIterator{M,D<: Union{Nothing,Int} ,O}
364
+ object:: O # Used to get number of variables and get new zero elements
365
+ mindegree:: Int
366
+ maxdegree:: D
367
+ inline:: Bool
368
+ end
369
+
370
+ function ExponentsIterator {M} (
371
+ object;
372
+ mindegree:: Int = 0 ,
373
+ maxdegree:: Union{Nothing,Int} = nothing ,
374
+ inline:: Bool = false ,
375
+ ) where {M}
376
+ if length (object) == 0 && isnothing (maxdegree)
377
+ # Otherwise, it will incorrectly think that the iterator is infinite
378
+ # while it actually has zero elements
379
+ maxdegree = mindegree
380
+ end
381
+ return ExponentsIterator {M,typeof(maxdegree),typeof(object)} (
382
+ object,
383
+ mindegree,
384
+ maxdegree,
385
+ inline,
386
+ )
387
+ end
388
+
389
+ Base. eltype (:: Type{ExponentsIterator{M,D,O}} ) where {M,D,O} = O
390
+ function Base. IteratorSize (:: Type{<:ExponentsIterator{M,Nothing}} ) where {M}
391
+ return Base. IsInfinite ()
392
+ end
393
+ function Base. IteratorSize (:: Type{<:ExponentsIterator{M,Int}} ) where {M}
394
+ return Base. HasLength ()
395
+ end
396
+
397
+ function Base. length (it:: ExponentsIterator{M,Int} ) where {M}
398
+ len = binomial (nvariables (it) + it. maxdegree, nvariables (it))
399
+ if it. mindegree > 0
400
+ if it. maxdegree < it. mindegree
401
+ return 0
402
+ end
403
+ len -= binomial (nvariables (it) + it. mindegree - 1 , nvariables (it))
404
+ end
405
+ return len
406
+ end
407
+
408
+ nvariables (it:: ExponentsIterator ) = length (it. object)
409
+
410
+ _increase_degree (it:: ExponentsIterator{<:Graded,Nothing} , _) = false
411
+ _increase_degree (it:: ExponentsIterator{<:Graded,Int} , _) = false
412
+ _increase_degree (it:: ExponentsIterator{M,Nothing} , _) where {M} = true
413
+ function _increase_degree (it:: ExponentsIterator{M,Int} , deg) where {M}
414
+ return deg < it. maxdegree
415
+ end
416
+
417
+ # We just changed the degree by removing `Δ`,
418
+ # In graded ordering, we just add `Δ` to maintain the same degree
419
+ _adjust_degree (:: ExponentsIterator{<:Graded} , _, Δ) = Δ
420
+ # Otherwise, we just need the degree to stay above `it.mindegree`,
421
+ # so we need to add `it.mindegree - deg`
422
+ _adjust_degree (it:: ExponentsIterator , deg, _) = max (0 , it. mindegree - deg)
423
+
424
+ _setindex! (x, v, i) = Base. setindex! (x, v, i)
425
+ _setindex! (x:: Tuple , v, i) = Base. setindex (x, v, i)
426
+ _increment! (x, i) = _setindex! (x, x[i] + 1 , i)
427
+
428
+ _zero (x) = zero (x)
429
+ _zero (x:: Tuple ) = zero .(x)
430
+
431
+ _zero! (x) = fill! (x, 0 )
432
+ _zero! (x:: Tuple ) = _zero (x)
433
+
434
+ _copy (x) = copy (x)
435
+ _copy (x:: Tuple ) = x
436
+
437
+ function _iterate! (it:: ExponentsIterator{M} , z, deg) where {M}
438
+ if _increase_degree (it, deg)
439
+ z = _increment! (z, _last_lex_index (nvariables (it), M))
440
+ return z, deg + 1
441
+ end
442
+ I = _not_first_indices (nvariables (it), M)
443
+ i = findfirst (i -> ! iszero (z[i]), I)
444
+ if isnothing (i)
445
+ if ! isnothing (it. maxdegree) && deg == it. maxdegree
446
+ return
447
+ end
448
+ z = _zero! (z)
449
+ z = _setindex! (z, deg + 1 , _last_lex_index (nvariables (it), M))
450
+ return z, deg + 1
451
+ end
452
+ j = I[i]
453
+ Δ = z[j] - 1
454
+ z = _setindex! (z, 0 , j)
455
+ j = I[i]
456
+ deg -= Δ
457
+ Δ = _adjust_degree (it, deg, Δ)
458
+ deg += Δ
459
+ z = _setindex! (z, Δ, _last_lex_index (nvariables (it), M))
460
+ j = I[i]
461
+ z = _increment! (z, _prev_lex_index (j, M))
462
+ return z, deg
463
+ end
464
+
465
+ function Base. iterate (it:: ExponentsIterator{M} ) where {M}
466
+ z = _zero (it. object)
467
+ if it. mindegree > 0
468
+ if nvariables (it) == 0 ||
469
+ (! isnothing (it. maxdegree) && it. maxdegree < it. mindegree)
470
+ return
471
+ end
472
+ z = _setindex! (z, it. mindegree, _last_lex_index (nvariables (it), M))
473
+ end
474
+ return z, (z, it. mindegree)
475
+ end
476
+
477
+ function Base. iterate (it:: ExponentsIterator , state)
478
+ if nvariables (it) == 0
479
+ return # There cannot be more than 1 element
480
+ end
481
+ z, deg = state
482
+ if ! it. inline
483
+ z = _copy (z)
484
+ end
485
+ state = _iterate! (it, z, deg)
486
+ if isnothing (state)
487
+ return
488
+ end
489
+ return state[1 ], state
490
+ end
0 commit comments