एसवीडी के लिए मजबूत एल्गोरिथ्म


26

_ मेट्रिसेस के SVD की गणना के लिए एक सरल एल्गोरिथ्म क्या है ?2×2

आदर्श रूप में, मैं एक संख्यात्मक रूप से मजबूत एल्गोरिथम पसंद करूंगा, लेकिन मैं सरल और समान-सरल दोनों कार्यान्वयन देखना चाहूंगा। C कोड स्वीकार किया गया।

कागजात या कोड का कोई संदर्भ?


5
विकिपीडिया एक 2x2 बंद फॉर्म समाधान को सूचीबद्ध करता है, लेकिन मुझे इसके संख्यात्मक गुणों का कोई पता नहीं है।
डेमियन

संदर्भ के रूप में, "न्यूमेरिकल व्यंजनों", प्रेस एट अल।, कैम्ब्रिज प्रेस। महंगी किताब लेकिन हर प्रतिशत के लायक। एसवीडी समाधानों के अलावा आपको बहुत सारे अन्य उपयोगी एल्गोरिदम मिलेंगे।
जन हैकबर्ग

जवाबों:


19

देखें /math/861674/decompose-a-2d-arbitrary-transform-into-only-scaling-and-rotation (क्षमा करें, मैं डाल दिया है कि एक टिप्पणी में, लेकिन मैं पंजीकृत कर लिया है बस इसे पोस्ट करने के लिए इसलिए मैं अभी तक टिप्पणी पोस्ट नहीं कर सकता)।

लेकिन जब से मैं इसे उत्तर के रूप में लिख रहा हूं, मैं विधि भी लिखूंगा:

E=m00+m112;F=m00m112;G=m10+m012;H=m10m012Q=E2+H2;R=F2+G2sx=Q+R;sy=QRa1=atan2(G,F);a2=atan2(H,E)θ=a2a12;ϕ=a2+a12

मैट्रिक्स को निम्नानुसार विघटित करता है:

M=(m00m01m10m11)=(cosϕsinϕsinϕcosϕ)(sx00sy)(cosθsinθsinθcosθ)

इस विधि के साथ रक्षा करने के लिए केवल एक चीज है कि atan2 के लिए या ।G=F=0H=E=0मुझे संदेह है कि यह इससे ज्यादा मजबूत हो सकता है( अपडेट: एलेक्स एफ़्टीमाईड्स का जवाब देखें!)।

संदर्भ है: http://dx.doi.org/10.1109/38.486688 (राहुल द्वारा दिया गया) जो इस ब्लॉग पोस्ट के नीचे से आता है: http://metamerist.blogspot.com/2006/10/linear-alnbra -किसी-ग्राफिक्स-गीक्स-svd.html

अपडेट: जैसा कि @VictorLiu ने एक टिप्पणी में कहा है, नकारात्मक हो सकता है। ऐसा तब होता है जब और केवल तभी इनपुट मैट्रिक्स का निर्धारक ऋणात्मक होता है। अगर ऐसा है और आप सकारात्मक एकवचन मूल्यों को चाहते हैं, तो बस का पूर्ण मूल्य ।sysy


1
ऐसा लगता है कि होने पर नकारात्मक हो सकता है । यह संभव नहीं होना चाहिए। Q < RsyQ<R
विक्टर लियू

@VictorLiu यदि इनपुट मैट्रिक्स फ़्लिप हो जाता है, तो केवल उसी स्थान को प्रतिबिंबित किया जा सकता है जो स्केलिंग मैट्रिक्स में होता है, क्योंकि रोटेशन मैट्रिसेस संभवतः फ्लिप नहीं कर सकते हैं। बस यह नहीं है कि इनपुट matrices फ्लिप कि फ़ीड। मैंने अभी तक गणित नहीं किया है, लेकिन मैं शर्त लगाता हूं कि इनपुट मैट्रिक्स के निर्धारक का संकेत निर्धारित करेगा कि या अधिक है या नहीं । आरQR
पेड्रो जिमेनो

@VictorLiu मैंने अब गणित किया है और पुष्टि की है कि वास्तव में, अर्थात इनपुट मैट्रिक्स के निर्धारक का सरलीकरण करता है। मीटर 00 मीटर 11 - एम 01 मीटर 10Q2R2m00m11m01m10
पेड्रो जिमेनो

9

@Pedro Gimeno

"मुझे संदेह है कि यह उससे कहीं अधिक मजबूत हो सकता है।"

चुनौती स्वीकार की गई।

मैंने देखा कि सामान्य दृष्टिकोण atan2 जैसे ट्रिगर कार्यों का उपयोग करना है। सहज रूप से, ट्रिगर कार्यों का उपयोग करने की आवश्यकता नहीं होनी चाहिए। वास्तव में, सभी परिणाम आर्कन के साइन और कोजाइन के रूप में समाप्त होते हैं - जिन्हें बीजीय कार्यों के लिए सरल बनाया जा सकता है। इसमें काफी समय लगा, लेकिन मैंने केवल बीजीय कार्यों का उपयोग करने के लिए पेड्रो के एल्गोरिथ्म को सरल बनाने में कामयाबी हासिल की।

निम्नलिखित अजगर कोड चाल करता है।

सुन्न आयात asarray, diag से

def svd2 (m):

y1, x1 = (m[1, 0] + m[0, 1]), (m[0, 0] - m[1, 1]) y2, x2 = (m[1, 0] - m[0, 1]), (m[0, 0] + m[1, 1]) h1 = hypot(y1, x1) h2 = hypot(y2, x2) t1 = x1 / h1 t2 = x2 / h2 cc = sqrt((1 + t1) * (1 + t2)) ss = sqrt((1 - t1) * (1 - t2)) cs = sqrt((1 + t1) * (1 - t2)) sc = sqrt((1 - t1) * (1 + t2)) c1, s1 = (cc - ss) / 2, (sc + cs) / 2, u1 = asarray([[c1, -s1], [s1, c1]]) d = asarray([(h1 + h2) / 2, (h1 - h2) / 2]) sigma = diag(d) if h1 != h2: u2 = diag(1 / d).dot(u1.T).dot(m) else: u2 = diag([1 / d[0], 0]).dot(u1.T).dot(m) return u1, sigma, u2


1
कोड गलत लगता है। 2x2 पहचान मैट्रिक्स पर विचार करें। फिर y1= 0, x1= 0, h1= 0, और t1= 0/0 = NaN
ह्यूजेस

8

GSL एक 2-दर-2 SVD के लिए मुख्य SVD एल्गोरिथ्म के QR अपघटन हिस्सा अंतर्निहित solver है gsl_linalg_SV_decompsvdstep.cफ़ाइल देखें और svd2फ़ंक्शन देखें। समारोह में कुछ विशेष मामले हैं, बिल्कुल तुच्छ नहीं है, और संख्यात्मक रूप से सावधान रहने के लिए कई काम कर रहे हैं (जैसे, hypotओवरफ्लो से बचने के लिए उपयोग करना)।


1
क्या इस फ़ंक्शन का कोई दस्तावेज है? मैं जानना चाहूंगा कि इसके इनपुट पैरामीटर क्या हैं।
विक्टर लियू

@VictorLiu: अफसोस की बात यह है कि मैंने फाइल में केवल कमेंट्स के अलावा कुछ नहीं देखा। ChangeLogयदि आप जीएसएल डाउनलोड करते हैं तो फ़ाइल में थोड़ा सा है । और आप svd.cसमग्र एल्गोरिथ्म के विवरण के लिए देख सकते हैं । उच्च स्तर के उपयोगकर्ता-कॉल करने योग्य कार्यों, जैसे, के लिए एकमात्र सही दस्तावेज लगता है gsl_linalg_SV_decomp
भयावह

7

जब हम कहते हैं "संख्यात्मक रूप से मजबूत" हम आम तौर पर एक एल्गोरिथ्म का मतलब है जिसमें हम त्रुटि प्रसार से बचने के लिए धुरी जैसी चीजें करते हैं। हालांकि, 2x2 मैट्रिक्स के लिए, आप परिणाम को स्पष्ट फॉर्मूलों के संदर्भ में लिख सकते हैं - यानी, SVD तत्वों के लिए फॉर्मूले लिखें, जो परिणाम को केवल इनपुट के संदर्भ में बताते हैं , बजाय पहले से गणना किए गए मध्यवर्ती मूल्यों के संदर्भ में । इसका मतलब है कि आपके पास रद्दीकरण हो सकता है लेकिन कोई त्रुटि नहीं है।

बस बात यह है कि 2x2 प्रणालियों के लिए, मजबूती के बारे में चिंता करना आवश्यक नहीं है।


यह मैट्रिक्स पर निर्भर कर सकता है। मैंने एक विधि देखी है जो बाएँ और दाएँ कोणों को अलग-अलग ढूँढती है (प्रत्येक के माध्यम से arctan2 (y, x)) जो आम तौर पर ठीक काम करता है। लेकिन जब एकवचन मान एक साथ करीब होते हैं, तो इनमें से प्रत्येक आर्कन 0/0 पर टिक जाता है, इसलिए इसका परिणाम गलत हो सकता है। पेड्रो गिमेनो द्वारा दी गई विधि में a2 की गणना इस मामले में अच्छी तरह से परिभाषित की जाएगी, जबकि a1 अ-परिभाषित है; आपके पास अभी भी एक अच्छा परिणाम है क्योंकि अपघटन की वैधता केवल थीटा + phi के प्रति संवेदनशील है जब s.vals एक साथ करीब होते हैं, थीटा-phi के पास नहीं।
ग्रैग्गो

5

यह कोड ब्लिन के पेपर , एलिस पेपर , एसवीडी व्याख्यान , और अतिरिक्त गणनाओं पर आधारित है। एक एल्गोरिथ्म नियमित और एकवचन वास्तविक मैट्रिक्स के लिए उपयुक्त है। पिछले सभी संस्करण 100% के साथ-साथ इस एक पर काम करते हैं।

#include <stdio.h>
#include <math.h>

void svd22(const double a[4], double u[4], double s[2], double v[4]) {
    s[0] = (sqrt(pow(a[0] - a[3], 2) + pow(a[1] + a[2], 2)) + sqrt(pow(a[0] + a[3], 2) + pow(a[1] - a[2], 2))) / 2;
    s[1] = fabs(s[0] - sqrt(pow(a[0] - a[3], 2) + pow(a[1] + a[2], 2)));
    v[2] = (s[0] > s[1]) ? sin((atan2(2 * (a[0] * a[1] + a[2] * a[3]), a[0] * a[0] - a[1] * a[1] + a[2] * a[2] - a[3] * a[3])) / 2) : 0;
    v[0] = sqrt(1 - v[2] * v[2]);
    v[1] = -v[2];
    v[3] = v[0];
    u[0] = (s[0] != 0) ? (a[0] * v[0] + a[1] * v[2]) / s[0] : 1;
    u[2] = (s[0] != 0) ? (a[2] * v[0] + a[3] * v[2]) / s[0] : 0;
    u[1] = (s[1] != 0) ? (a[0] * v[1] + a[1] * v[3]) / s[1] : -u[2];
    u[3] = (s[1] != 0) ? (a[2] * v[1] + a[3] * v[3]) / s[1] : u[0];
}

int main() {
    double a[4] = {1, 2, 3, 6}, u[4], s[2], v[4];
    svd22(a, u, s, v);
    printf("Matrix A:\n%f %f\n%f %f\n\n", a[0], a[1], a[2], a[3]);
    printf("Matrix U:\n%f %f\n%f %f\n\n", u[0], u[1], u[2], u[3]);
    printf("Matrix S:\n%f %f\n%f %f\n\n", s[0], 0, 0, s[1]);
    printf("Matrix V:\n%f %f\n%f %f\n\n", v[0], v[1], v[2], v[3]);
}

5

मुझे एक एल्गोरिथ्म की आवश्यकता है जो है

  • छोटी शाखा (उम्मीद है CMOVs)
  • कोई त्रिकोणमितीय फ़ंक्शन कॉल नहीं
  • 32 बिट फ्लोट के साथ उच्च संख्यात्मक सटीकता

हम निम्न प्रकार से और गणना करना चाहते हैं:c1,s1,c2,s2,σ1σ2

A=USV , जिसे बढ़ाया जा सकता है जैसे:

[abcd]=[c1s1s1c1][σ100σ2][c2s2s2c2]

मुख्य विचार एक घूर्णन मैट्रिक्स को खोजना है जो विकर्ण करता है, यह विकर्ण है।VATAVATAVT=D

याद करें कि

USV=A

US=AV1=AVT (चूंकि ऑर्थोगोनल है)V

VATAVT=(AVT)TAVT=(US)TUS=STUTUS=D

दोनों पक्षों को गुणा करके हम प्राप्त करते हैंS1

(STST)UTU(SS1)=UTU=STDS1

चूंकि विकर्ण है, को सेट करने से हमें मिलेगी , जिसका अर्थ है कि एक घूर्णन मैट्रिक्स है, एक विकर्ण मैट्रिक्स है, एक घूर्णन मैट्रिक्स और , बस जिसे हम देख रहे हैं। के लिये।DSDUTU=IdentityUSVUSV=A

विकर्ण रोटेशन की गणना निम्नलिखित समीकरण को हल करके की जा सकती है:

t22βαγt21=0

कहा पे

ATA=[acbd][abcd]=[a2+c2ab+cdab+cdb2+d2]=[αγγβ]

और , के कोण का स्पर्शरेखा है । यह विस्तार करके और इसके ऑफ-विकर्ण तत्वों को शून्य के बराबर बनाकर (वे एक-दूसरे के बराबर हैं) हो सकते हैं।t2VVATAVT

इस विधि के साथ समस्या यह है कि यह महत्वपूर्ण फ्लोटिंग पॉइंट सटीक खो देता है जब गणना में घटाव के कारण कुछ मैट्रिसेस के लिए और की गणना की जाती है। इसका समाधान पहले एक आरक्यू अपघटन ( , ऊपरी त्रिकोणीय और ऑर्थोगोनल) करना है, फिर को फैक्ट करने के लिए एल्गोरिथ्म का उपयोग करें । यह । सूचना कैसे स्थापित करने 0 (के रूप में ) अतिरिक्त / subtractions से कुछ दूर करता है। (मैट्रिक्स उत्पाद के विस्तार से आरक्यू अपघटन काफी तुच्छ है)।βαγA=RQRQUSV=RUSV=USVQ=RQ=AdR

एल्गोरिथ्म ने इस तरह लागू किया कुछ संख्यात्मक और तार्किक विसंगतियाँ हैं (उदाहरण के लिए या ), जो मैंने नीचे दिए गए कोड में तय किया है।S +DD

मैंने लगभग 2000 मिलियन रैंडमाइज्ड मेट्रिसेस को कोड में फेंक दिया, और निर्मित सबसे बड़ी संख्यात्मक त्रुटि लगभग (32 बिट फ़्लोट, ) के साथ थी। एल्गोरिथ्म लगभग 340 घड़ी चक्र (MSVC 19, आइवी ब्रिज) में चलता है।6107error=||USVM||/||M||

template <class T>
void Rq2x2Helper(const Matrix<T, 2, 2>& A, T& x, T& y, T& z, T& c2, T& s2) {
    T a = A(0, 0);
    T b = A(0, 1);
    T c = A(1, 0);
    T d = A(1, 1);

    if (c == 0) {
        x = a;
        y = b;
        z = d;
        c2 = 1;
        s2 = 0;
        return;
    }
    T maxden = std::max(abs(c), abs(d));

    T rcmaxden = 1/maxden;
    c *= rcmaxden;
    d *= rcmaxden;

    T den = 1/sqrt(c*c + d*d);

    T numx = (-b*c + a*d);
    T numy = (a*c + b*d);
    x = numx * den;
    y = numy * den;
    z = maxden/den;

    s2 = -c * den;
    c2 = d * den;
}


template <class T>
void Svd2x2Helper(const Matrix<T, 2, 2>& A, T& c1, T& s1, T& c2, T& s2, T& d1, T& d2) {
    // Calculate RQ decomposition of A
    T x, y, z;
    Rq2x2Helper(A, x, y, z, c2, s2);

    // Calculate tangent of rotation on R[x,y;0,z] to diagonalize R^T*R
    T scaler = T(1)/std::max(abs(x), abs(y));
    T x_ = x*scaler, y_ = y*scaler, z_ = z*scaler;
    T numer = ((z_-x_)*(z_+x_)) + y_*y_;
    T gamma = x_*y_;
    gamma = numer == 0 ? 1 : gamma;
    T zeta = numer/gamma;

    T t = 2*impl::sign_nonzero(zeta)/(abs(zeta) + sqrt(zeta*zeta+4));

    // Calculate sines and cosines
    c1 = T(1) / sqrt(T(1) + t*t);
    s1 = c1*t;

    // Calculate U*S = R*R(c1,s1)
    T usa = c1*x - s1*y; 
    T usb = s1*x + c1*y;
    T usc = -s1*z;
    T usd = c1*z;

    // Update V = R(c1,s1)^T*Q
    t = c1*c2 + s1*s2;
    s2 = c2*s1 - c1*s2;
    c2 = t;

    // Separate U and S
    d1 = std::hypot(usa, usc);
    d2 = std::hypot(usb, usd);
    T dmax = std::max(d1, d2);
    T usmax1 = d2 > d1 ? usd : usa;
    T usmax2 = d2 > d1 ? usb : -usc;

    T signd1 = impl::sign_nonzero(x*z);
    dmax *= d2 > d1 ? signd1 : 1;
    d2 *= signd1;
    T rcpdmax = 1/dmax;

    c1 = dmax != T(0) ? usmax1 * rcpdmax : T(1);
    s1 = dmax != T(0) ? usmax2 * rcpdmax : T(0);
}

से विचार:
http://www.cs.utexas.edu/users/inderjit/public_papers/HLA_SVD.pdf
http://www.math.pitt.edu/~sussmanm/2071Sprn08/lab09/index.html
http: // www.lucidarme.me/singular-value-decomposition-of-a-2x2-matrix/


3

मैंने इस C ++ कोड को बनाने के लिए http://www.lucidarme.me/?p=4624 पर विवरण का उपयोग किया है । मेट्रिसेस, ईगन लाइब्रेरी के हैं, लेकिन आप इस उदाहरण से आसानी से अपनी स्वयं की डेटा संरचना बना सकते हैं:

A=UΣVT

#include <cmath>
#include <Eigen/Core>
using namespace Eigen;

Matrix2d A;
// ... fill A

double a = A(0,0);
double b = A(0,1);
double c = A(1,0);
double d = A(1,1);

double Theta = 0.5 * atan2(2*a*c + 2*b*d,
                           a*a + b*b - c*c - d*d);
// calculate U
Matrix2d U;
U << cos(Theta), -sin(Theta), sin(Theta), cos(Theta);

double Phi = 0.5 * atan2(2*a*b + 2*c*d,
                         a*a - b*b + c*c - d*d);
double s11 = ( a*cos(Theta) + c*sin(Theta))*cos(Phi) +
             ( b*cos(Theta) + d*sin(Theta))*sin(Phi);
double s22 = ( a*sin(Theta) - c*cos(Theta))*sin(Phi) +
             (-b*sin(Theta) + d*cos(Theta))*cos(Phi);

// calculate S
S1 = a*a + b*b + c*c + d*d;
S2 = sqrt(pow(a*a + b*b - c*c - d*d, 2) + 4*pow(a*c + b*d, 2));

Matrix2d Sigma;
Sigma << sqrt((S1+S2) / 2), 0, 0, sqrt((S1-S2) / 2);

// calculate V
Matrix2d V;
V << signum(s11)*cos(Phi), -signum(s22)*sin(Phi),
     signum(s11)*sin(Phi),  signum(s22)*cos(Phi);

मानक साइन फ़ंक्शन के साथ

double signum(double value)
{
    if(value > 0)
        return 1;
    else if(value < 0)
        return -1;
    else
        return 0;
}

यह बिल्कुल वैसा ही मान देता है जैसे Eigen::JacobiSVD( https://eigen.tuxfamily.org/dox-devel/classEigen_1_1JacobiSVD.html देखें )।


1
S2 = hypot( a*a + b*b - c*c - d*d, 2*(a*c + b*d))
ग्रैग्गो

2

मैं यहाँ 2x2 असली SVD के लिए शुद्ध C कोड रखता हूँ । पंक्ति 559 देखें। यह अनिवार्य रूप से द्विघात को हल करके आइगेनवैल्यूज़ की गणना करता है , इसलिए यह आवश्यक रूप से सबसे मजबूत नहीं है, लेकिन यह व्यावहारिक रूप से भी-पैथोलॉजिकल मामलों के लिए अच्छा काम करता है। यह अपेक्षाकृत सरल है।ATA


मुझे नहीं लगता कि जब मैट्रिक्स के आइगेनवेल्स नकारात्मक होते हैं तो आपका कोड काम करता है। कोशिश करो [[१ १] [१ ०]], और u * s * vt मी के बराबर नहीं है ...
कार्लोस स्हीडेगर

2

अपनी व्यक्तिगत ज़रूरत के लिए, मैंने 2x2 svd के लिए न्यूनतम गणना को अलग करने की कोशिश की। मुझे लगता है कि यह शायद सबसे सरल और सबसे तेज़ समाधान में से एक है। : तुम मेरी निजी ब्लॉग पर जानकारी प्राप्त कर सकते http://lucidarme.me/?p=4624

लाभ: सरल, तेज और आप तीन मैट्रिसेस (एस, यू या डी) में से केवल एक या दो की गणना कर सकते हैं यदि आपको तीन मैट्रिस की आवश्यकता नहीं है।

ड्राबैक यह atan2 का उपयोग करता है, जो गलत हो सकता है और इसके लिए बाहरी लाइब्रेरी (टाइप। math.h) की आवश्यकता हो सकती है।


3
चूंकि लिंक शायद ही कभी स्थायी होते हैं, इसलिए उत्तर के रूप में लिंक प्रदान करने के बजाय दृष्टिकोण को संक्षेप में प्रस्तुत करना महत्वपूर्ण है।
पॉल

इसके अलावा, यदि आप अपने स्वयं के ब्लॉग के लिए एक लिंक पोस्ट करने जा रहे हैं, तो कृपया (ए) बताएं कि यह आपका ब्लॉग है, (बी) इससे भी बेहतर वास्तव में आपके दृष्टिकोण (सूत्रों की छवियों को काट या पेस्ट करना) होगा। कच्चे LaTeX में अनुवाद किया और MathJax का उपयोग करके प्रदान किया गया)। प्रश्न के इस प्रकार के फॉर्मूला के लिए सबसे अच्छे उत्तर, उक्त सूत्रों के लिए उद्धरण प्रदान करते हैं, और फिर कमियां, किनारे के मामले और संभावित विकल्पों की सूची बनाते हैं।
ज्योफ ऑक्सीबेरी

1

यहां एक 2x2 एसवीडी समाधान का कार्यान्वयन है। मैंने इसे विक्टर लियू के कोड से हटा दिया। कुछ मैट्रिसेस के लिए उनका कोड काम नहीं कर रहा था। : मैं हल के लिए गणितीय संदर्भ के रूप में इन दोनों दस्तावेजों का इस्तेमाल किया pdf1 और pdf2

मैट्रिक्स setDataविधि पंक्ति-प्रमुख क्रम में है। आंतरिक रूप से, मैं मैट्रिक्स डेटा का प्रतिनिधित्व 2 डी सरणी के रूप में करता हूं data[col][row]

void Matrix2f::svd(Matrix2f* w, Vector2f* e, Matrix2f* v) const{
    //If it is diagonal, SVD is trivial
    if (fabs(data[0][1] - data[1][0]) < EPSILON && fabs(data[0][1]) < EPSILON){
        w->setData(data[0][0] < 0 ? -1 : 1, 0, 0, data[1][1] < 0 ? -1 : 1);
        e->setData(fabs(data[0][0]), fabs(data[1][1]));
        v->loadIdentity();
    }
    //Otherwise, we need to compute A^T*A
    else{
        float j = data[0][0]*data[0][0] + data[0][1]*data[0][1],
            k = data[1][0]*data[1][0] + data[1][1]*data[1][1],
            v_c = data[0][0]*data[1][0] + data[0][1]*data[1][1];
        //Check to see if A^T*A is diagonal
        if (fabs(v_c) < EPSILON){
            float s1 = sqrt(j),
                s2 = fabs(j-k) < EPSILON ? s1 : sqrt(k);
            e->setData(s1, s2);
            v->loadIdentity();
            w->setData(
                data[0][0]/s1, data[1][0]/s2,
                data[0][1]/s1, data[1][1]/s2
            );
        }
        //Otherwise, solve quadratic for eigenvalues
        else{
            float jmk = j-k,
                jpk = j+k,
                root = sqrt(jmk*jmk + 4*v_c*v_c),
                eig = (jpk+root)/2,
                s1 = sqrt(eig),
                s2 = fabs(root) < EPSILON ? s1 : sqrt((jpk-root)/2);
            e->setData(s1, s2);
            //Use eigenvectors of A^T*A as V
            float v_s = eig-j,
                len = sqrt(v_s*v_s + v_c*v_c);
            v_c /= len;
            v_s /= len;
            v->setData(v_c, -v_s, v_s, v_c);
            //Compute w matrix as Av/s
            w->setData(
                (data[0][0]*v_c + data[1][0]*v_s)/s1,
                (data[1][0]*v_c - data[0][0]*v_s)/s2,
                (data[0][1]*v_c + data[1][1]*v_s)/s1,
                (data[1][1]*v_c - data[0][1]*v_s)/s2
            );
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.