এসভিডি এর জন্য দৃ Rob় অ্যালগরিদম


26

ম্যাট্রিকের এসভিডি গণনার জন্য একটি সাধারণ অ্যালগরিদম কী ?2×2

আদর্শভাবে, আমি একটি সংখ্যার শক্তিশালী অ্যালগরিদম চাই, তবে আমি সহজ এবং না-সহজ উভয় বাস্তবায়ন দেখতে চাই। সি কোড গৃহীত হয়েছে।

কাগজপত্র বা কোডের কোনও রেফারেন্স?


5
উইকিপিডিয়া একটি 2x2 বদ্ধ ফর্ম সমাধানের তালিকাবদ্ধ করে, তবে এর সংখ্যাসমূহ সম্পর্কে আমার কোনও ধারণা নেই।
ড্যামিয়েন

রেফারেন্স হিসাবে, "সংখ্যার রেসিপি", প্রেস এট।, কেমব্রিজ প্রেস। বেশ ব্যয়বহুল বই কিন্তু মূল্য প্রতি শতাংশ। এসভিডি সমাধান ছাড়াও আপনি প্রচুর অন্যান্য দরকারী অ্যালগোরিদম পাবেন।
জান হ্যাকেনবার্গ

উত্তর:


19

Https://math.stackexchange.com/questions/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θ)

এই পদ্ধতির সাথে রক্ষা করার একমাত্র জিনিস হ'ল এটিএন 2 এর জন্য G=F=0 বা H=E=0আমি সন্দেহ করি যে এর চেয়ে আরও শক্তিশালী আর কিছু হতে পারে( আপডেট: দেখুন অ্যালেক্স ইফতিমিয়াদের উত্তর!)।

তথ্যসূত্রটি হ'ল: http://dx.doi.org/10.1109/38.486688 (সেখানে রাহুল প্রদত্ত) যা এই ব্লগ পোস্টের নীচে থেকে আসে: http://metamerist.blogspot.com/2006/10/linear-algebra -for-গ্রাফিক্স-গুরুদের-svd.html

আপডেট: @ ভিক্টরলিউ একটি মন্তব্যে যেমন উল্লেখ করেছেন, sy negative ণাত্মক হতে পারে। ইনপুট ম্যাট্রিক্সের নির্ধারকটি যদি নেতিবাচক হয় তবেই তা ঘটে। যদি এটি হয় এবং আপনি ধনাত্মক একবচনীয় মান চান, তবে এরsy পরম মানটি ধরুন


1
দেখে মনে হচ্ছে প্রশ্ন < আর আর হলে negative ণাত্মক হতে পারে । এটি সম্ভব না হওয়া উচিত। syQ<R
ভিক্টর লিউ

@ ভিক্টোরিলিউ যদি ইনপুট ম্যাট্রিক্স ফ্লিপ হয় তবে একমাত্র স্থানটি প্রতিফলিত হতে পারে এটি স্কেলিং ম্যাট্রিক্সে রয়েছে, কারণ ঘূর্ণন ম্যাট্রিকগুলি সম্ভবত ফ্লিপ করতে পারে না। কেবল এটিকে ফ্লিপ করুন মেট্রিকিকে ইনপুট দেবেন না। আমি এখনও গণিতটি করি নি তবে আমি বাজি ধরেছি যে ইনপুট ম্যাট্রিক্সের নির্ধারকের সাইনটি বা R এর চেয়ে বড় কিনা তা নির্ধারণ করবে । QR
পেড্রো গিমেনো

Q2R2m00m11m01m10

9

@ পেড্রো গিমেনো

"আমি সন্দেহ করি যে এর চেয়ে আরও শক্তিশালী আর কিছু হতে পারে।"

চ্যালেঞ্জ গ্রহন করা হল.

আমি লক্ষ্য করেছি যে স্বাভাবিক পন্থাটি এটিান 2 এর মতো ট্রিগার ফাংশন ব্যবহার করা। স্বজ্ঞাতভাবে, ট্রিগ ফাংশন ব্যবহার করার প্রয়োজন হবে না। প্রকৃতপক্ষে, সমস্ত ফলাফল সমুদ্র এবং আর্টিকানের কোসাইন হিসাবে শেষ হয় - যা বীজগণিত ফাংশনে সরলীকৃত করা যেতে পারে। এটি বেশ খানিকটা সময় নিয়েছিল, তবে আমি কেবলমাত্র বীজগণিতীয় ফাংশনগুলি ব্যবহার করতে পেড্রোর অ্যালগরিদমকে সহজ করে তুললাম।

নিম্নলিখিত অজগর কোডটি কৌশলটি করে।

ন্যালি আমদানি আসারায় থেকে, ডায়াগ

Def svd2 (মি):

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 আলগোরিদিম কিউ পচানি অংশ অন্তর্নিহিত সমাধানকারী হয়েছে gsl_linalg_SV_decomp। দেখুন svdstep.cফাইল এবং জন্য চেহারা svd2ফাংশন। ফাংশনটিতে কয়েকটি বিশেষ কেস রয়েছে, একেবারে তুচ্ছ নয় এবং সংখ্যাগতভাবে যত্নবান হওয়ার জন্য বেশ কয়েকটি কাজ করা দেখায় (যেমন, hypotঅতিরিক্ত প্রবাহ এড়াতে ব্যবহার করা)।


1
এই ফাংশনে কি কোনও ডকুমেন্টেশন আছে? এর ইনপুট পরামিতিগুলি কী তা আমি জানতে চাই।
ভিক্টর লিউ

@ ভিক্টরলিউ: দুঃখজনকভাবে আমি নিজে ফাইলটিতে স্বল্প মন্তব্য ছাড়া আর কিছু দেখিনি। ChangeLogআপনি জিএসএল ডাউনলোড করলে ফাইলটিতে কিছুটা আছে । এবং আপনি svd.cসামগ্রিক অ্যালগরিদমের বিশদটি দেখতে পারেন । একমাত্র সত্য ডকুমেন্টেশন মনে হয় উচ্চ স্তরের ব্যবহারকারী-কলযোগ্য ফাংশনগুলির জন্য, যেমন gsl_linalg_SV_decomp,।
হর্চলার

7

যখন আমরা "সংখ্যার দিক থেকে দৃust়" বলি তখন আমরা সাধারণত একটি অ্যালগরিদম বোঝায় যেখানে আমরা ত্রুটি প্রচার এড়াতে পাইভটিংয়ের মতো কাজ করি। তবে, 2x2 ম্যাট্রিক্সের জন্য আপনি সুস্পষ্ট সূত্রের শর্তে ফলাফল লিখতে পারেন - যেমন, এসভিডি উপাদানগুলির জন্য সূত্রগুলি লিখুন যা ফলাফলকে কেবল ইনপুটগুলির শর্তে লিখবে, পূর্বে গণনা করা মধ্যবর্তী মানগুলির পরিবর্তে । তার মানে আপনার বাতিল হতে পারে তবে কোনও ত্রুটি প্রচার নেই no

মুল বক্তব্যটি হ'ল 2x2 সিস্টেমের জন্য দৃ about়তা সম্পর্কে চিন্তিত হওয়া জরুরি নয়।


এটি ম্যাট্রিক্সের উপর নির্ভর করতে পারে। আমি এমন একটি পদ্ধতি দেখেছি যা বাম এবং ডান কোণ পৃথকভাবে আবিষ্কার করে (প্রতিটি আর্ক্টান 2 (y, x) এর মাধ্যমে) যা সাধারণত সূক্ষ্মভাবে কাজ করে। কিন্তু যখন একবচনীয় মানগুলি একত্রে কাছাকাছি থাকে, তখন এই আর্টিকানগুলির প্রত্যেকটি 0/0 তে থাকে, সুতরাং ফলাফলটি ভুল হতে পারে। পেড্রো গিমেনো প্রদত্ত পদ্ধতিতে, এ 2 এর গণনাকে এই ক্ষেত্রে ভালভাবে সংজ্ঞায়িত করা হবে, এবং এ 1 অ-সংজ্ঞায়িত হয়ে উঠবে; আপনার এখনও একটি ভাল ফলাফল আছে কারণ পচনের বৈধতা কেবল থিটা + ফাইয়ের সাথে সংবেদনশীল যখন এস.ভালগুলি একসাথে কাছাকাছি থাকে, থিতা-ফাইয়ের সাথে নয়।
গ্রেগগো

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

আমার একটি অ্যালগরিদম দরকার ছিল

  • সামান্য শাখা (আশা করি সিএমওভ)
  • কোনও ত্রিকোণমিত্রিক ফাংশন কল নেই
  • এমনকি 32 বিট ফ্লোট সহ উচ্চ সংখ্যার যথার্থতা

c1,s1,c2,s2,σ1σ2

A=USV

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

VATAVATAVT=D

মনে আছে

USV=A

US=AV1=AVTV

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

βαγA=RQRQUSV=RUSV=USVQ=RQ=AdR

S +DD

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_paper/HLA_SVD.pdf
http://www.math.pitt.edu/~sussmanm/2071Spring08/lab09/index.html
http: // www.lucidarme.me/singular-value-decomposition-of-a-2x2-matrix/


3

আমি এই সি ++ কোডটি তৈরি করতে 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_1 জ্যাকোবিএসভিডি এইচটিএমএল দেখুন )।


1
S2 = hypot( a*a + b*b - c*c - d*d, 2*(a*c + b*d))
গ্রেগগো 20


2

আমার ব্যক্তিগত প্রয়োজনের জন্য, আমি 2x2 এসভিডি-র সর্বনিম্ন গণনা আলাদা করার চেষ্টা করেছি। আমার ধারণা এটি সম্ভবত সবচেয়ে সহজ এবং দ্রুত সমাধানগুলির মধ্যে একটি। আপনি আমার ব্যক্তিগত ব্লগে বিশদটি পেতে পারেন: http://lucidarme.me/?p=4624

সুবিধা: সহজ, দ্রুত এবং আপনার যদি তিনটি ম্যাট্রিকের প্রয়োজন না হয় তবে আপনি কেবলমাত্র তিনটি ম্যাট্রিকের (এস, ইউ বা ডি) একটি বা দুটি গণনা করতে পারেন।

অপূর্ণতা এটা ATAN2, যা inacurate হতে পারে ব্যবহার করে এবং একটি বহিস্থিত লাইব্রেরী (typ। Math.h) প্রয়োজন হতে পারে।


3
যেহেতু লিঙ্কগুলি খুব কমই স্থায়ী হয়, কেবলমাত্র উত্তর হিসাবে একটি লিঙ্ক সরবরাহ করার চেয়ে পদ্ধতির সংক্ষিপ্ত বিবরণ দেওয়া গুরুত্বপূর্ণ।
পল

এছাড়াও, আপনি যদি নিজের ব্লগে কোনও লিঙ্ক পোস্ট করতে চলেছেন তবে দয়া করে (ক) এটি প্রকাশ করুন যে এটি আপনার ব্লগ, (খ) আপনার পদ্ধতির সংক্ষিপ্তসার বা কাট-পেস্ট করা আরও ভাল হবে (সূত্রগুলির চিত্রগুলি পারে কাঁচা ল্যাটেক্সে অনুবাদ করুন এবং ম্যাথজ্যাক্স ব্যবহার করে রেন্ডার করুন)। এই জাতীয় প্রশ্নের সূত্রের সূত্রগুলির সর্বোত্তম উত্তর, উক্ত সূত্রগুলির জন্য উদ্ধৃতি প্রদান করুন এবং তারপরে ঘাটতি, প্রান্তের কেস এবং সম্ভাব্য বিকল্পগুলির তালিকা তৈরি করুন।
জিফ অক্সবেরি

1

এখানে 2x2 এসভিডি সমাধানের একটি বাস্তবায়ন দেওয়া হয়েছে। আমি এটিকে ভিক্টর লিউ-র কোডের বাইরে রেখেছি। তার কোড কিছু ম্যাট্রিকের জন্য কাজ করছে না। সমাধানের জন্য আমি এই দুটি নথিকে গাণিতিক রেফারেন্স হিসাবে ব্যবহার করেছি: পিডিএফ 1 এবং পিডিএফ 2

ম্যাট্রিক্স setDataপদ্ধতিটি সারি-প্রধান ক্রমে। অভ্যন্তরীণভাবে, আমি প্রদত্ত 2D অ্যারে হিসাবে ম্যাট্রিক্স ডেটা উপস্থাপন করি 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
            );
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.