
    Ti                     J    d Z ddlZddlmZmZmZmZmZ ddl	m
Z
mZ d Zd ZdS )a   
This module provides some Powell-style linear algebra procedures.

Translated from Zaikun Zhang's modern-Fortran reference implementation in PRIMA.

Dedicated to late Professor M. J. D. Powell FRS (1936--2015).

Python translation by Nickolai Belakovski.
    N   )isminorplanerotmatprodinprodhypot)	DEBUGGINGEPSc                    |j         d         }|}t          | |          }t          t          |           t          |                    }t          j        d t          ||          D                       }t          |dz
  |dz
  d          D ]}t          ||dz                      dk    rat          |||dz                      }	t          |dd||dz   gf         |	j                  |dd||dz   gf<   t          |||dz             ||<   ||k     rBt          ||                   t          dz  k    r!t          ||         ||                   s|dz  }|dz
  dk    r|dz
  |k     r||dz
           ||dz
  <   t          rO||cxk    rt          |dz   |          k    sn J |t          |          cxk    r|k    sn J |j         ||fk    sJ |||fS )a  
    This function updates the QR factorization of an MxN matrix A of full column rank, attempting to
    add a new column C to this matrix as the LAST column while maintaining the full-rankness.
    Case 1. If C is not in range(A) (theoretically, it implies N < M), then the new matrix is np.hstack([A, C])
    Case 2. If C is in range(A), then the new matrix is np.hstack([A[:, :n-1], C])
    N.B.:
    0. Instead of R, this subroutine updates Rdiag, which is np.diag(R), with a size at most M and at
    least min(m, n+1). The number is min(m, n+1) rather than min(m, n) as n may be augmented by 1 in
    the function.
    1. With the two cases specified as above, this function does not need A as an input.
    2. The function changes only Q[:, nsave:m] (nsave is the original value of n) and
    R[:, n-1] (n takes the updated value)
    3. Indeed, when C is in range(A), Powell wrote in comments that "set iOUT to the index of the
    constraint (here, column of A --- Zaikun) to be deleted, but branch if no suitable index can be
    found". The idea is to replace a column of A by C so that the new matrix still has full rank
    (such a column must exist unless C = 0). But his code essentially sets iout=n always. Maybe he
    found this worked well enough in practice. Meanwhile, Powell's code includes a snippet that can
    never be reached, which was probably intended to deal with the case that IOUT != n
    r   c                 <    g | ]\  }}t          ||          rd n|S )r   )r   ).0cqicqais      x/var/www/development/aibuddy-work/election-extract/venv/lib/python3.11/site-packages/scipy/_lib/pyprima/common/powalg.py
<listcomp>zqradd_Rdiag.<locals>.<listcomp>-   s/    RRR	TT**311RRR       r   N)shaper   absnparrayzipranger   Tr   r
   r   r	   minlen)
cQRdiagnmnsavecqcqakGs
             r   qradd_Rdiagr(      s   ( 	

AE 
AB
#a&&#a&&
!
!C 
RRSS\\RRR	S	SB
 1Q3!R   & &r!A#w<<! AacE##A$Qqqq1ac({^QS99Aaaa!QqSkN2a!e9%BqE 	1uur!u::Qwr!uc!f'='=FA 	1uzza!eaii!a%ya!e !....SA........CJJ####!######w1a&    eQ;r   c                      j         \  }}|dk    r||k    sJ |dk    r||k     sJ t          |          |k    sJ j         d         |k    r"j         d         |k    rj         d         |k    sJ |dk     s||k    r|fS t          ||dz
            D ]q}t          ||dz            t	          dd|f          dd|dz   f                   g          }t          dd|dz   |gf         |j                  dd||dz   gf<   r fdt          ||dz
            D             |||dz
  <   t	          dd|dz
  f          dd|f                   ||dz
  <   |fS )a[  
    This function updates the QR factorization for an MxN matrix A=Q@R so that the updated Q and
    R form a QR factorization of [A_0, ..., A_{I-1}, A_{I+1}, ..., A_{N-1}, A_I] which is the matrix
    obtained by rearranging columns [I, I+1, ... N-1] of A to [I+1, ..., N-1, I]. Here A is ASSUMED TO
    BE OF FULL COLUMN RANK, Q is a matrix whose columns are orthogonal, and R, which is not present,
    is an upper triangular matrix whose diagonal entries are nonzero. Q and R need not be square.
    N.B.:
    0. Instead of R, this function updates Rdiag, which is np.diag(R), the size being n.
    1. With L = Q.shape[1] = R.shape[0], we have M >= L >= N. Most often L = M or N.
    2. This function changes only Q[:, i:] and Rdiag[i:]
    3. (NDB 20230919) In Python, i is either icon or nact - 2, whereas in FORTRAN it is either icon or nact - 1.
    r   r   Nc           	      ^    g | ])}t          d d |f         d d |dz   f                   *S )Nr   )r   )r   r&   Ar   s     r   r   zqrexc_Rdiag.<locals>.<listcomp>   s?    FFF1F1QQQT7Aaaa1fI..FFFr   )r   r   r   r   r   r   r   )r+   r   r    ir"   r!   r&   r'   s   ``      r   qrexc_Rdiagr-   L   s    7DAq 66a1ffff66a!eeeeu::????71:??qwqzQ171:????
 	1uuQ%x 1ac]] 8 8eAaCj&111a4!AAAqsF)"<"<=>> 111qsAh;!#77!!!a1X+ GFFFFa1FFFE!AaC%L!!!QqS&	1QQQT7++E!A#Je8Or   )__doc__numpyr   linalgr   r   r   r   r   constsr	   r
   r(   r-    r   r   <module>r3      s         = = = = = = = = = = = = = = " " " " " " " "9 9 9x7 7 7 7 7r   