1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

from __future__ import division, print_function, absolute_import 

 

import numpy as np 

from scipy.linalg import svd 

 

 

__all__ = ['polar'] 

 

 

def polar(a, side="right"): 

""" 

Compute the polar decomposition. 

 

Returns the factors of the polar decomposition [1]_ `u` and `p` such 

that ``a = up`` (if `side` is "right") or ``a = pu`` (if `side` is 

"left"), where `p` is positive semidefinite. Depending on the shape 

of `a`, either the rows or columns of `u` are orthonormal. When `a` 

is a square array, `u` is a square unitary array. When `a` is not 

square, the "canonical polar decomposition" [2]_ is computed. 

 

Parameters 

---------- 

a : (m, n) array_like 

The array to be factored. 

side : {'left', 'right'}, optional 

Determines whether a right or left polar decomposition is computed. 

If `side` is "right", then ``a = up``. If `side` is "left", then 

``a = pu``. The default is "right". 

 

Returns 

------- 

u : (m, n) ndarray 

If `a` is square, then `u` is unitary. If m > n, then the columns 

of `a` are orthonormal, and if m < n, then the rows of `u` are 

orthonormal. 

p : ndarray 

`p` is Hermitian positive semidefinite. If `a` is nonsingular, `p` 

is positive definite. The shape of `p` is (n, n) or (m, m), depending 

on whether `side` is "right" or "left", respectively. 

 

References 

---------- 

.. [1] R. A. Horn and C. R. Johnson, "Matrix Analysis", Cambridge 

University Press, 1985. 

.. [2] N. J. Higham, "Functions of Matrices: Theory and Computation", 

SIAM, 2008. 

 

Examples 

-------- 

>>> from scipy.linalg import polar 

>>> a = np.array([[1, -1], [2, 4]]) 

>>> u, p = polar(a) 

>>> u 

array([[ 0.85749293, -0.51449576], 

[ 0.51449576, 0.85749293]]) 

>>> p 

array([[ 1.88648444, 1.2004901 ], 

[ 1.2004901 , 3.94446746]]) 

 

A non-square example, with m < n: 

 

>>> b = np.array([[0.5, 1, 2], [1.5, 3, 4]]) 

>>> u, p = polar(b) 

>>> u 

array([[-0.21196618, -0.42393237, 0.88054056], 

[ 0.39378971, 0.78757942, 0.4739708 ]]) 

>>> p 

array([[ 0.48470147, 0.96940295, 1.15122648], 

[ 0.96940295, 1.9388059 , 2.30245295], 

[ 1.15122648, 2.30245295, 3.65696431]]) 

>>> u.dot(p) # Verify the decomposition. 

array([[ 0.5, 1. , 2. ], 

[ 1.5, 3. , 4. ]]) 

>>> u.dot(u.T) # The rows of u are orthonormal. 

array([[ 1.00000000e+00, -2.07353665e-17], 

[ -2.07353665e-17, 1.00000000e+00]]) 

 

Another non-square example, with m > n: 

 

>>> c = b.T 

>>> u, p = polar(c) 

>>> u 

array([[-0.21196618, 0.39378971], 

[-0.42393237, 0.78757942], 

[ 0.88054056, 0.4739708 ]]) 

>>> p 

array([[ 1.23116567, 1.93241587], 

[ 1.93241587, 4.84930602]]) 

>>> u.dot(p) # Verify the decomposition. 

array([[ 0.5, 1.5], 

[ 1. , 3. ], 

[ 2. , 4. ]]) 

>>> u.T.dot(u) # The columns of u are orthonormal. 

array([[ 1.00000000e+00, -1.26363763e-16], 

[ -1.26363763e-16, 1.00000000e+00]]) 

 

""" 

if side not in ['right', 'left']: 

raise ValueError("`side` must be either 'right' or 'left'") 

a = np.asarray(a) 

if a.ndim != 2: 

raise ValueError("`a` must be a 2-D array.") 

 

w, s, vh = svd(a, full_matrices=False) 

u = w.dot(vh) 

if side == 'right': 

# a = up 

p = (vh.T.conj() * s).dot(vh) 

else: 

# a = pu 

p = (w * s).dot(w.T.conj()) 

return u, p