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

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

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

69.46
/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)
15✔
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)
25✔
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,352✔
40
    @assert N::Integer > 0
2,054✔
41
    if @generated
×
42
        quote
253✔
43
            acc_0 = acc
2,054✔
44
            Base.Cartesian.@nexprs $N i -> acc_{i} = op(acc_{i-1}, i)
2,352✔
45
            return $(Symbol(:acc_, N))
2,054✔
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)
498✔
70

71
function _isperm(A)
498✔
72
    n = length(A)
498✔
73
    used = falses(n)
498✔
74
    for a in A
518✔
75
        (0 < a <= n) && (used[a] ⊻= true) || return false
50,232✔
76
    end
50,710✔
77
    true
498✔
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))
528✔
83

84
function isperm(P::Tuple)
398✔
85
    valn = Val(length(P))
398✔
86
    _foldoneto(true, valn) do b,i
472✔
87
        s = _foldoneto(false, valn) do s, j
1,460✔
88
            s || P[j]==i
4,568✔
89
        end
90
        b&s
1,242✔
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)
839✔
98
    i == j && return
839✔
99
    cols = axes(a,2)
839✔
100
    @boundscheck i in cols || throw(BoundsError(a, (:,i)))
839✔
101
    @boundscheck j in cols || throw(BoundsError(a, (:,j)))
839✔
102
    for k in axes(a,1)
1,678✔
103
        @inbounds a[k,i],a[k,j] = a[k,j],a[k,i]
44,615✔
104
    end
44,615✔
105
end
106

107
# swap rows i and j of a, in-place
108
function swaprows!(a::AbstractMatrix, i, j)
3✔
109
    i == j && return
3✔
110
    rows = axes(a,1)
3✔
111
    @boundscheck i in rows || throw(BoundsError(a, (:,i)))
3✔
112
    @boundscheck j in rows || throw(BoundsError(a, (:,j)))
3✔
113
    for k in axes(a,2)
6✔
114
        @inbounds a[i,k],a[j,k] = a[j,k],a[i,k]
18✔
115
    end
18✔
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})
138✔
120
    require_one_based_indexing(a, p)
138✔
121
    count = 0
138✔
122
    start = 0
138✔
123
    while count < length(p)
451✔
124
        ptr = start = findnext(!iszero, p, start+1)::Int
830✔
125
        next = p[start]
313✔
126
        count += 1
313✔
127
        while next != start
1,148✔
128
            swapcols!(a, ptr, next)
835✔
129
            p[ptr] = 0
835✔
130
            ptr = next
835✔
131
            next = p[next]
835✔
132
            count += 1
835✔
133
        end
835✔
134
        p[ptr] = 0
313✔
135
    end
313✔
136
    a
138✔
137
end
138

139
function permute!!(a, p::AbstractVector{<:Integer})
×
140
    require_one_based_indexing(a, p)
×
141
    count = 0
×
142
    start = 0
×
143
    while count < length(a)
×
144
        ptr = start = findnext(!iszero, p, start+1)::Int
×
145
        temp = a[start]
×
146
        next = p[start]
×
147
        count += 1
×
148
        while next != start
×
149
            a[ptr] = a[next]
×
150
            p[ptr] = 0
×
151
            ptr = next
×
152
            next = p[next]
×
153
            count += 1
×
154
        end
×
155
        a[ptr] = temp
×
156
        p[ptr] = 0
×
157
    end
×
158
    a
×
159
end
160

161
"""
162
    permute!(v, p)
163

164
Permute vector `v` in-place, according to permutation `p`. No checking is done
165
to verify that `p` is a permutation.
166

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

172
See also [`invpermute!`](@ref).
173

174
# Examples
175
```jldoctest
176
julia> A = [1, 1, 3, 4];
177

178
julia> perm = [2, 4, 3, 1];
179

180
julia> permute!(A, perm);
181

182
julia> A
183
4-element Vector{Int64}:
184
 1
185
 4
186
 3
187
 1
188
```
189
"""
190
permute!(v, p::AbstractVector) = (v .= v[p])
1,177✔
191

192
function invpermute!!(a, p::AbstractVector{<:Integer})
×
193
    require_one_based_indexing(a, p)
×
194
    count = 0
×
195
    start = 0
×
196
    while count < length(a)
×
197
        start = findnext(!iszero, p, start+1)::Int
×
198
        temp = a[start]
×
199
        next = p[start]
×
200
        count += 1
×
201
        while next != start
×
202
            temp_next = a[next]
×
203
            a[next] = temp
×
204
            temp = temp_next
×
205
            ptr = p[next]
×
206
            p[next] = 0
×
207
            next = ptr
×
208
            count += 1
×
209
        end
×
210
        a[next] = temp
×
211
        p[next] = 0
×
212
    end
×
213
    a
×
214
end
215

216
"""
217
    invpermute!(v, p)
218

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

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

225
# Examples
226
```jldoctest
227
julia> A = [1, 1, 3, 4];
228

229
julia> perm = [2, 4, 3, 1];
230

231
julia> invpermute!(A, perm);
232

233
julia> A
234
4-element Vector{Int64}:
235
 4
236
 1
237
 3
238
 1
239
```
240
"""
241
invpermute!(v, p::AbstractVector) = (v[p] = v; v)
2,293✔
242

243
"""
244
    invperm(v)
245

246
Return the inverse permutation of `v`.
247
If `B = A[v]`, then `A == B[invperm(v)]`.
248

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

251
# Examples
252
```jldoctest
253
julia> p = (2, 3, 1);
254

255
julia> invperm(p)
256
(3, 1, 2)
257

258
julia> v = [2; 4; 3; 1];
259

260
julia> invperm(v)
261
4-element Vector{Int64}:
262
 4
263
 1
264
 3
265
 2
266

267
julia> A = ['a','b','c','d'];
268

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

276
julia> B[invperm(v)]
277
4-element Vector{Char}:
278
 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
279
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
280
 'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
281
 'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
282
```
283
"""
284
function invperm(a::AbstractVector)
743✔
285
    require_one_based_indexing(a)
743✔
286
    b = zero(a) # similar vector of zeros
5,807✔
287
    n = length(a)
743✔
288
    @inbounds for (i, j) in enumerate(a)
1,483✔
289
        ((1 <= j <= n) && b[j] == 0) ||
5,804✔
290
            throw(ArgumentError("argument is not a permutation"))
291
        b[j] = i
5,804✔
292
    end
10,868✔
293
    b
743✔
294
end
295

296
function invperm(p::Union{Tuple{},Tuple{Int},Tuple{Int,Int}})
183✔
297
    isperm(p) || throw(ArgumentError("argument is not a permutation"))
183✔
298
    p  # in dimensions 0-2, every permutation is its own inverse
183✔
299
end
300

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

314
invperm(P::Any32) = Tuple(invperm(collect(P)))
×
315

316
#XXX This function should be moved to Combinatorics.jl but is currently used by Base.DSP.
317
"""
318
    nextprod(factors::Union{Tuple,AbstractVector}, n)
319

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

323
# Examples
324
```jldoctest
325
julia> nextprod((2, 3), 105)
326
108
327

328
julia> 2^2 * 3^3
329
108
330
```
331

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

347
    while v[end] < mx[end]
63✔
348
        if p >= x
58✔
349
            best = p < best ? p : best  # keep the best found yet
36✔
350
            carrytest = true
36✔
351
            while carrytest
72✔
352
                p = div(p, v[icarry])
36✔
353
                v[icarry] = 1
36✔
354
                icarry += 1
36✔
355
                p *= a[icarry]
36✔
356
                v[icarry] *= a[icarry]
36✔
357
                carrytest = v[icarry] > mx[icarry] && icarry < k
36✔
358
            end
36✔
359
            if p < x
36✔
360
                icarry = 1
22✔
361
            end
362
        else
363
            while p < x
65✔
364
                p *= a[1]
43✔
365
                v[1] *= a[1]
43✔
366
            end
43✔
367
        end
368
    end
58✔
369
    # might overflow, but want predictable return type
370
    return mx[end] < best ? Int(mx[end]) : Int(best)
5✔
371
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