
    #
3j                     $    S SK r       SS jrg)    Nc	           	      F  ^ Tc  S n	O[        T5      (       a  Tn	OU4S jn	Uc  [        R                  " U5      OUR                  5       n
[        R                  R                  U5      n[        U 5      (       a  X" U
5      -
  nOXR                  U
5      -
  n[        R                  R                  U5      nX:  d  XU-  :  a  U
$ U	" U5      nUR                  5       n[        R                  " X5      n[        U5       GH  nUR                  5       n[        U 5      (       a	  U " U5      nOU R                  U5      nU[        R                  " UU5      -  nU
UU-  -  n
UUU-  -  n[        R                  R                  U5      nUb
  U" X
XX5        X:  d  XU-  :  a  U
s  $ U	" U5      nU(       a4  [        R                  " UU-
  U5      U-  n[        R                  " X5      nO SU-  n[        R                  " X5      nUU-  nUU-  nX-  nGM     [        SU-  5      e)a$  Solves a system of linear equations :math:`Ax=b` using conjugate gradient descent :cite:`hestenes1952methods`

Parameters
----------
A: scipy.sparse.csr_matrix
   Square matrix
b: numpy.ndarray
   Vector describing the right-hand side of the system
x0: numpy.ndarray
   Initialization, if `None` then :code:`x=np.zeros_like(b)`
atol: float
   Absolute tolerance. The loop terminates if the :math:`||r||` is smaller than `atol`, where :math:`r` denotes the residual of the current iterate.
rtol: float
   Relative tolerance. The loop terminates if :math:`{||r||}/{||b||}` is smaller than `rtol`, where :math:`r` denotes the residual of the current iterate.
callback: function
   Function :code:`callback(A, x, b, norm_b, r, norm_r)` called after each iteration, defaults to `None`
M: function or scipy.sparse.csr_matrix
   Function that applies the preconditioner to a vector. Alternatively, `M` can be a matrix describing the precondioner.
reorthogonalize: boolean
    Whether to apply reorthogonalization of the residuals after each update, defaults to `False`


Returns
-------
x: numpy.ndarray
    Solution of the system

Example
-------
>>> from pymatting import *
>>> import numpy as np
>>> A = np.array([[3.0, 1.0], [1.0, 2.0]])
>>> M = jacobi(A)
>>> b = np.array([4.0, 3.0])
>>> cg(A, b, M=M)
array([1., 1.])
c                     U $ N )xs    M/home/wildlama/miniconda3/lib/python3.13/site-packages/pymatting/solver/cg.pypreconditioncg.<locals>.precondition6   s    H    c                 &   > TR                  U 5      $ r   )dot)r   Ms    r   r	   r
   =   s    558Or   g      ?z@Conjugate gradient descent did not converge within %d iterations)
callablenp
zeros_likecopylinalgnormr   innerrange
ValueError)Abx0atolrtolmaxitercallbackr   reorthogonalizer	   r   norm_brnorm_rzprz	iterationr_oldApalphabetas          `              r   cgr+      s   ` 	y	 
!	 JaBGGIAYY^^AF{{!HaLYY^^AF}.QA	A	!B7^	A;;1BqBRXXa_$	UQY	URZ"Q1a0=FF]2HO88AIq)B.D!B8D!BBJD	T		? $B JWT r   )Ng        gHz>i'  NNF)numpyr   r+   r   r   r   <module>r-      s%     		
qr   