• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37728

26 Mar 2024 03:46AM UTC coverage: 80.612% (-0.8%) from 81.423%
#37728

push

local

web-flow
Update zlib to 1.3.1 (#53841)

Released January 22, 2024

69920 of 86737 relevant lines covered (80.61%)

14456248.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.92
/base/combinatorics.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# Factorials
4

5
const _fact_table64 = Vector{Int64}(undef, 20)
6
_fact_table64[1] = 1
7
for n in 2:20
8
    _fact_table64[n] = _fact_table64[n-1] * n
9
end
10

11
const _fact_table128 = Vector{UInt128}(undef, 34)
12
_fact_table128[1] = 1
13
for n in 2:34
14
    _fact_table128[n] = _fact_table128[n-1] * n
15
end
16

17
function factorial_lookup(n::Integer, table, lim)
18
    n < 0 && throw(DomainError(n, "`n` must not be negative."))
15✔
19
    n > lim && throw(OverflowError(string(n, " is too large to look up in the table; consider using `factorial(big(", n, "))` instead")))
13✔
20
    n == 0 && return one(n)
13✔
21
    @inbounds f = table[n]
13✔
22
    return oftype(n, f)
13✔
23
end
24

25
factorial(n::Int128) = factorial_lookup(n, _fact_table128, 33)
×
26
factorial(n::UInt128) = factorial_lookup(n, _fact_table128, 34)
×
27
factorial(n::Union{Int64,UInt64}) = factorial_lookup(n, _fact_table64, 20)
24✔
28

29
if Int === Int32
30
    factorial(n::Union{Int8,UInt8,Int16,UInt16}) = factorial(Int32(n))
×
31
    factorial(n::Union{Int32,UInt32}) = factorial_lookup(n, _fact_table64, 12)
×
32
else
33
    factorial(n::Union{Int8,UInt8,Int16,UInt16,Int32,UInt32}) = factorial(Int64(n))
2✔
34
end
35

36

37
# Basic functions for working with permutations
38

39
@inline function _foldoneto(op, acc, ::Val{N}) where N
2,330✔
40
    @assert N::Integer > 0
2,037✔
41
    if @generated
42
        quote
260✔
43
            acc_0 = acc
2,037✔
44
            Base.Cartesian.@nexprs $N i -> acc_{i} = op(acc_{i-1}, i)
2,330✔
45
            return $(Symbol(:acc_, N))
2,037✔
46
        end
47
    else
48
        for i in 1:N
49
            acc = op(acc, i)
50
        end
51
        return acc
52
    end
53
end
54

55
"""
56
    isperm(v) -> Bool
57

58
Return `true` if `v` is a valid permutation.
59

60
# Examples
61
```jldoctest
62
julia> isperm([1; 2])
63
true
64

65
julia> isperm([1; 3])
66
false
67
```
68
"""
69
isperm(A) = _isperm(A)
507✔
70

71
function _isperm(A)
507✔
72
    n = length(A)
507✔
73
    used = falses(n)
507✔
74
    for a in A
507✔
75
        (0 < a <= n) && (used[a] ⊻= true) || return false
50,680✔
76
    end
50,680✔
77
    true
78
end
79

80
isperm(p::Tuple{}) = true
×
81
isperm(p::Tuple{Int}) = p[1] == 1
×
82
isperm(p::Tuple{Int,Int}) = ((p[1] == 1) & (p[2] == 2)) | ((p[1] == 2) & (p[2] == 1))
433✔
83

84
function isperm(P::Tuple)
85
    valn = Val(length(P))
393✔
86
    _foldoneto(true, valn) do b,i
463✔
87
        s = _foldoneto(false, valn) do s, j
1,366✔
88
            s || P[j]==i
3,062✔
89
        end
90
        b&s
1,230✔
91
    end
92
end
93

94
isperm(P::Any32) = _isperm(P)
×
95

96
# swap columns i and j of a, in-place
97
function swapcols!(a::AbstractMatrix, i, j)
6,057✔
98
    i == j && return
6,057✔
99
    cols = axes(a,2)
6,057✔
100
    @boundscheck i in cols || throw(BoundsError(a, (:,i)))
6,057✔
101
    @boundscheck j in cols || throw(BoundsError(a, (:,j)))
6,057✔
102
    for k in axes(a,1)
6,057✔
103
        @inbounds a[k,i],a[k,j] = a[k,j],a[k,i]
56,510✔
104
    end
56,510✔
105
end
106

107
# swap rows i and j of a, in-place
108
function swaprows!(a::AbstractMatrix, i, j)
262,505✔
109
    i == j && return
262,505✔
110
    rows = axes(a,1)
32,229✔
111
    @boundscheck i in rows || throw(BoundsError(a, (:,i)))
32,229✔
112
    @boundscheck j in rows || throw(BoundsError(a, (:,j)))
32,229✔
113
    for k in axes(a,2)
32,229✔
114
        @inbounds a[i,k],a[j,k] = a[j,k],a[i,k]
127,712✔
115
    end
127,712✔
116
end
117

118
# like permute!! applied to each row of a, in-place in a (overwriting p).
119
function permutecols!!(a::AbstractMatrix, p::AbstractVector{<:Integer})
150✔
120
    require_one_based_indexing(a, p)
150✔
121
    count = 0
150✔
122
    start = 0
150✔
123
    while count < length(p)
487✔
124
        ptr = start = findnext(!iszero, p, start+1)::Int
869✔
125
        next = p[start]
337✔
126
        count += 1
337✔
127
        while next != start
1,242✔
128
            swapcols!(a, ptr, next)
905✔
129
            p[ptr] = 0
905✔
130
            ptr = next
905✔
131
            next = p[next]
905✔
132
            count += 1
905✔
133
        end
905✔
134
        p[ptr] = 0
337✔
135
    end
337✔
136
    a
150✔
137
end
138

139
# Row and column permutations for AbstractMatrix
140
permutecols!(a::AbstractMatrix, p::AbstractVector{<:Integer}) =
8✔
141
    _permute!(a, p, Base.swapcols!)
142
permuterows!(a::AbstractMatrix, p::AbstractVector{<:Integer}) =
16✔
143
    _permute!(a, p, Base.swaprows!)
144
@inline function _permute!(a::AbstractMatrix, p::AbstractVector{<:Integer}, swapfun!::F) where {F}
145
    require_one_based_indexing(a, p)
24✔
146
    p .= .-p
24✔
147
    for i in 1:length(p)
24✔
148
        p[i] > 0 && continue
240✔
149
        j = i
136✔
150
        in = p[j] = -p[j]
136✔
151
        while p[in] < 0
240✔
152
            swapfun!(a, in, j)
104✔
153
            j = in
104✔
154
            in = p[in] = -p[in]
104✔
155
        end
104✔
156
    end
456✔
157
    a
24✔
158
end
159
invpermutecols!(a::AbstractMatrix, p::AbstractVector{<:Integer}) =
×
160
    _invpermute!(a, p, Base.swapcols!)
161
invpermuterows!(a::AbstractMatrix, p::AbstractVector{<:Integer}) =
4✔
162
    _invpermute!(a, p, Base.swaprows!)
163
@inline function _invpermute!(a::AbstractMatrix, p::AbstractVector{<:Integer}, swapfun!::F) where {F}
164
    require_one_based_indexing(a, p)
4✔
165
    p .= .-p
4✔
166
    for i in 1:length(p)
4✔
167
        p[i] > 0 && continue
40✔
168
        j = p[i] = -p[i]
29✔
169
        while j != i
40✔
170
           swapfun!(a, j, i)
11✔
171
           j = p[j] = -p[j]
11✔
172
        end
11✔
173
     end
76✔
174
    a
4✔
175
end
176

177
"""
178
    permute!(v, p)
179

180
Permute vector `v` in-place, according to permutation `p`. No checking is done
181
to verify that `p` is a permutation.
182

183
To return a new permutation, use `v[p]`. This is generally faster than `permute!(v, p)`;
184
it is even faster to write into a pre-allocated output array with `u .= @view v[p]`.
185
(Even though `permute!` overwrites `v` in-place, it internally requires some allocation
186
to keep track of which elements have been moved.)
187

188
$(_DOCS_ALIASING_WARNING)
189

190
See also [`invpermute!`](@ref).
191

192
# Examples
193
```jldoctest
194
julia> A = [1, 1, 3, 4];
195

196
julia> perm = [2, 4, 3, 1];
197

198
julia> permute!(A, perm);
199

200
julia> A
201
4-element Vector{Int64}:
202
 1
203
 4
204
 3
205
 1
206
```
207
"""
208
permute!(v, p::AbstractVector) = (v .= v[p])
1,272✔
209

210
"""
211
    invpermute!(v, p)
212

213
Like [`permute!`](@ref), but the inverse of the given permutation is applied.
214

215
Note that if you have a pre-allocated output array (e.g. `u = similar(v)`),
216
it is quicker to instead employ `u[p] = v`.  (`invpermute!` internally
217
allocates a copy of the data.)
218

219
$(_DOCS_ALIASING_WARNING)
220

221
# Examples
222
```jldoctest
223
julia> A = [1, 1, 3, 4];
224

225
julia> perm = [2, 4, 3, 1];
226

227
julia> invpermute!(A, perm);
228

229
julia> A
230
4-element Vector{Int64}:
231
 4
232
 1
233
 3
234
 1
235
```
236
"""
237
invpermute!(v, p::AbstractVector) = (v[p] = v; v)
949✔
238

239
"""
240
    invperm(v)
241

242
Return the inverse permutation of `v`.
243
If `B = A[v]`, then `A == B[invperm(v)]`.
244

245
See also [`sortperm`](@ref), [`invpermute!`](@ref), [`isperm`](@ref), [`permutedims`](@ref).
246

247
# Examples
248
```jldoctest
249
julia> p = (2, 3, 1);
250

251
julia> invperm(p)
252
(3, 1, 2)
253

254
julia> v = [2; 4; 3; 1];
255

256
julia> invperm(v)
257
4-element Vector{Int64}:
258
 4
259
 1
260
 3
261
 2
262

263
julia> A = ['a','b','c','d'];
264

265
julia> B = A[v]
266
4-element Vector{Char}:
267
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
268
 'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
269
 'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
270
 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
271

272
julia> B[invperm(v)]
273
4-element Vector{Char}:
274
 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
275
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
276
 'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
277
 'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
278
```
279
"""
280
function invperm(a::AbstractVector)
1,033✔
281
    require_one_based_indexing(a)
1,033✔
282
    b = fill!(similar(a), zero(eltype(a))) # mutable vector of zeros
10,187✔
283
    n = length(a)
1,033✔
284
    @inbounds for (i, j) in enumerate(a)
1,061✔
285
        ((1 <= j <= n) && b[j] == 0) ||
10,184✔
286
            throw(ArgumentError("argument is not a permutation"))
287
        b[j] = i
10,184✔
288
    end
19,338✔
289
    b
1,033✔
290
end
291

292
function invperm(p::Union{Tuple{},Tuple{Int},Tuple{Int,Int}})
9✔
293
    isperm(p) || throw(ArgumentError("argument is not a permutation"))
164✔
294
    p  # in dimensions 0-2, every permutation is its own inverse
164✔
295
end
296

297
function invperm(P::Tuple)
4✔
298
    valn = Val(length(P))
128✔
299
    ntuple(valn) do i
209✔
300
        s = _foldoneto(nothing, valn) do s, j
465✔
301
            s !== nothing && return s
1,146✔
302
            P[j]==i && return j
764✔
303
            nothing
304
        end
305
        s === nothing && throw(ArgumentError("argument is not a permutation"))
382✔
306
        s
380✔
307
    end
308
end
309

310
invperm(P::Any32) = Tuple(invperm(collect(P)))
×
311

312
#XXX This function should be moved to Combinatorics.jl but is currently used by Base.DSP.
313
"""
314
    nextprod(factors::Union{Tuple,AbstractVector}, n)
315

316
Next integer greater than or equal to `n` that can be written as ``\\prod k_i^{p_i}`` for integers
317
``p_1``, ``p_2``, etcetera, for factors ``k_i`` in `factors`.
318

319
# Examples
320
```jldoctest
321
julia> nextprod((2, 3), 105)
322
108
323

324
julia> 2^2 * 3^3
325
108
326
```
327

328
!!! compat "Julia 1.6"
329
    The method that accepts a tuple requires Julia 1.6 or later.
330
"""
331
function nextprod(a::Union{Tuple{Vararg{Integer}},AbstractVector{<:Integer}}, x::Real)
6✔
332
    if x > typemax(Int)
6✔
333
        throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
1✔
334
    end
335
    k = length(a)
5✔
336
    v = fill(1, k)                    # current value of each counter
13✔
337
    mx = map(a -> nextpow(a,x), a)   # maximum value of each counter
18✔
338
    v[1] = mx[1]                      # start at first case that is >= x
5✔
339
    p::widen(Int) = mx[1]             # initial value of product in this case
5✔
340
    best = p
5✔
341
    icarry = 1
5✔
342

343
    while v[end] < mx[end]
63✔
344
        if p >= x
58✔
345
            best = p < best ? p : best  # keep the best found yet
36✔
346
            carrytest = true
36✔
347
            while carrytest
72✔
348
                p = div(p, v[icarry])
36✔
349
                v[icarry] = 1
36✔
350
                icarry += 1
36✔
351
                p *= a[icarry]
36✔
352
                v[icarry] *= a[icarry]
36✔
353
                carrytest = v[icarry] > mx[icarry] && icarry < k
36✔
354
            end
36✔
355
            if p < x
36✔
356
                icarry = 1
22✔
357
            end
358
        else
359
            while p < x
65✔
360
                p *= a[1]
43✔
361
                v[1] *= a[1]
43✔
362
            end
43✔
363
        end
364
    end
58✔
365
    # might overflow, but want predictable return type
366
    return mx[end] < best ? Int(mx[end]) : Int(best)
5✔
367
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc