@@ -208,25 +208,26 @@ def cov(
208208 correction : int or float, optional
209209 Degrees of freedom correction: normalization divides by
210210 ``N - correction`` (for unweighted input). Default: ``1``, which
211- gives the unbiased estimate (matches `` numpy.cov` ` default of
211+ gives the unbiased estimate (matches :func:` numpy.cov` default of
212212 ``bias=False``). Set to ``0`` for the biased estimate (``N``
213- normalization). Corresponds to ``ddof`` in ``numpy.cov`` and to
214- ``correction`` in ``numpy.var``/``std`` and ``torch.cov``.
213+ normalization). Corresponds to ``ddof`` in :func:`numpy.cov` and to
214+ ``correction`` in :func:`numpy.var`/:func:`numpy.std` and
215+ :func:`torch.cov`.
215216 Non-integer values are allowed for advanced use cases: the
216217 unbiased correction for weighted observations depends on the
217218 sum and dispersion of the weights and is generally not an
218219 integer, and autocorrelated data may also require a fractional
219220 correction. Non-integer ``correction`` routes through the
220- generic implementation because `` numpy.cov` `'s ``ddof`` and
221- `` torch.cov` `'s ``correction`` both require integers.
221+ generic implementation because :func:` numpy.cov`'s ``ddof`` and
222+ :func:` torch.cov`'s ``correction`` both require integers.
222223 fweights : array, optional
223224 1-D array of integer frequency weights: the number of times each
224225 observation is repeated. Same as ``fweights`` in
225- `` numpy.cov``/`` torch.cov` `.
226+ :func:` numpy.cov`/:func:` torch.cov`.
226227 aweights : array, optional
227228 1-D array of observation-vector weights (analytic weights). Larger
228229 values mark more important observations. Same as ``aweights`` in
229- `` numpy.cov``/`` torch.cov` `.
230+ :func:` numpy.cov`/:func:` torch.cov`.
230231 xp : array_namespace, optional
231232 The standard-compatible namespace for `m`. Default: infer.
232233
@@ -238,7 +239,7 @@ def cov(
238239
239240 Notes
240241 -----
241- Mapping from `` numpy.cov` ` to this function::
242+ Mapping from :func:` numpy.cov` to this function::
242243
243244 numpy.cov(m, rowvar=True) -> cov(m, axis=-1) # default
244245 numpy.cov(m, rowvar=False) -> cov(m, axis=-2)
@@ -300,6 +301,30 @@ def cov(
300301 [ -4.286 , 2.14413333]],
301302 [[ 46.84 , -17.144 ],
302303 [-17.144 , 8.57653333]]], dtype=array_api_strict.float64)
304+
305+ The normalization can be adjusted with `correction`, and observations
306+ can be weighted with integer frequencies `fweights` or importance
307+ weights `aweights`:
308+
309+ >>> x = xp.asarray([0., 1., 2., 3., 4.])
310+ >>> xpx.cov(x, xp=xp) # unbiased variance: divide by N - 1
311+ Array(2.5, dtype=array_api_strict.float64)
312+ >>> xpx.cov(x, correction=0, xp=xp) # biased variance: divide by N
313+ Array(2., dtype=array_api_strict.float64)
314+
315+ Giving the two extreme observations frequency 2 via `fweights` is
316+ equivalent to repeating them in `x`:
317+
318+ >>> xpx.cov(x, fweights=xp.asarray([2, 1, 1, 1, 2]), xp=xp)
319+ Array(3., dtype=array_api_strict.float64)
320+ >>> xpx.cov(xp.asarray([0., 0., 1., 2., 3., 4., 4.]), xp=xp)
321+ Array(3., dtype=array_api_strict.float64)
322+
323+ `aweights` instead adjusts the relative importance of observations,
324+ here down-weighting the two extremes:
325+
326+ >>> xpx.cov(x, aweights=xp.asarray([0.5, 1., 1., 1., 0.5]), xp=xp)
327+ Array(1.92, dtype=array_api_strict.float64)
303328 """
304329
305330 if xp is None :
@@ -319,14 +344,17 @@ def cov(
319344 # `numpy.cov` (and cupy/dask/jax) require integer `ddof`; `torch.cov`
320345 # requires integer `correction`. For non-integer-valued `correction`,
321346 # fall through to the generic implementation.
322- integer_correction = isinstance (correction , int ) or correction .is_integer ()
347+ integer_correction = float (correction ) .is_integer ()
323348 has_weights = fweights is not None or aweights is not None
324349
325350 if m .ndim <= 2 and integer_correction :
351+ # Not just for static typing: `correction` may be an integer-valued
352+ # float such as 1.0, which `torch.cov` rejects at runtime.
353+ int_correction = int (correction )
326354 if is_torch_namespace (xp ):
327355 fw = None if fweights is None else xp .asarray (fweights )
328356 aw = None if aweights is None else xp .asarray (aweights )
329- return xp .cov (m , correction = int ( correction ) , fweights = fw , aweights = aw )
357+ return xp .cov (m , correction = int_correction , fweights = fw , aweights = aw )
330358 # `dask.array.cov` forces `.compute()` whenever weights are given:
331359 # its internal `if fact <= 0` check on a lazy 0-D scalar triggers
332360 # materialization. Route to the generic impl, which is fully lazy
@@ -339,7 +367,7 @@ def cov(
339367 ):
340368 return xp .cov (
341369 m ,
342- ddof = int ( correction ) ,
370+ ddof = int_correction ,
343371 fweights = fweights ,
344372 aweights = aweights ,
345373 )
0 commit comments