Coverage for src/fast_minimum_variance/__init__.py: 100%

5 statements  

« prev     ^ index     » next       coverage.py v7.15.0, created at 2026-07-04 15:49 +0000

1"""fast_minimum_variance — fast solvers for the minimum-variance portfolio.""" 

2 

3import numpy as np 

4 

5from .minvar_problem import _MinVarProblem 

6 

7 

8def Problem( # noqa: N802 

9 X: np.ndarray, # noqa: N803 

10 target: np.ndarray | None = None, 

11 B: np.ndarray | None = None, # noqa: N803 

12 c: np.ndarray | None = None, 

13 alpha: float = 0.0, 

14 rho: float = 0.0, 

15 mu: np.ndarray | None = None, 

16 target_lr: tuple[float, np.ndarray, np.ndarray] | None = None, 

17 pcg_lr: tuple[float, np.ndarray, np.ndarray] | None = None, 

18) -> _MinVarProblem: 

19 """Create a long-only minimum-variance portfolio optimisation problem. 

20 

21 Returns a :class:`_MinVarProblem` (shrinking active-set) for the long-only 

22 minimum-variance problem, optionally with a balance system ``(B, c)`` in 

23 place of the default budget constraint. 

24 

25 Args: 

26 X: Returns matrix of shape ``(T, N)``. 

27 target: Optional ``(N, N)`` regularisation matrix; when supplied the 

28 shrinkage term ``alpha * ||target @ w||^2`` is added to the 

29 objective. ``None`` disables shrinkage entirely. 

30 B: Balance system ``(p, N)`` for the fast shrinking active-set 

31 path: ``B w = c`` replaces the budget ``1^T w = 1``. ``B`` 

32 must have full row rank on every active set the loop visits. 

33 c: Balance RHS ``(p,)``; required together with ``B``. 

34 alpha: Shrinkage intensity; only active when ``target`` is provided. 

35 rho: Return tilt strength (Markowitz mean-variance). 

36 mu: Expected returns vector ``(N,)``; required when ``rho != 0``. 

37 target_lr: Low-rank factored target ``(bar_lam, U_k, delta_k)`` for 

38 RMT eigenvalue-cleaning; replaces ``target`` in the CG matvec. 

39 pcg_lr: RMT preconditioner ``(bar_lam, U_k, delta_k)`` for 

40 ``solve_pcg``; ignored unless PCG is invoked. 

41 

42 Returns: 

43 A solver instance with ``solve_kkt()``, ``solve_minres()``, 

44 ``solve_cg()``, and ``solve_cvxpy()`` methods, each returning 

45 ``(w, n_iters)``. 

46 

47 Examples: 

48 >>> import numpy as np 

49 >>> X = np.random.default_rng(42).standard_normal((500, 20)) 

50 >>> w, _ = Problem(X).solve_kkt() 

51 >>> float(round(w.sum(), 8)) 

52 1.0 

53 >>> bool((w >= 0).all()) 

54 True 

55 

56 A two-sleeve balance system — each half of the universe holds half 

57 of the budget: 

58 

59 >>> B = np.zeros((2, 20)); B[0, :10] = 1.0; B[1, 10:] = 1.0 

60 >>> w, _ = Problem(X, B=B, c=np.array([0.5, 0.5])).solve_kkt() 

61 >>> [float(round(s, 8)) for s in B @ w] 

62 [0.5, 0.5] 

63 >>> bool((w >= -1e-6).all()) 

64 True 

65 """ 

66 return _MinVarProblem(X, target=target, alpha=alpha, rho=rho, mu=mu, target_lr=target_lr, pcg_lr=pcg_lr, B=B, c=c) 

67 

68 

69__all__ = ["Problem"]