मैटलैब का इंटीग्रल आउटपरफॉर्म स्काइप में एकीकृत क्यों होता है?


13

मैं जिस तरह से matlab संख्यात्मक एकीकरण बनाम Scipy संभालता है पर कुछ निराशा का अनुभव कर रहा हूँ। मैं अपने परीक्षण कोड में निम्नलिखित अंतरों का पालन करता हूं:

  1. मतलाब का संस्करण मेरे अजगर के मुकाबले औसतन 24 गुना तेज चलता है !
  2. मैथलैब का संस्करण बिना किसी चेतावनी के अभिन्न की गणना करने में सक्षम है, जबकि अजगर रिटर्न करता है nan+nanj

मैं यह सुनिश्चित करने के लिए क्या कर सकता हूं कि मुझे वर्णित दो बिंदुओं के संबंध में अजगर में समान प्रदर्शन मिले? दस्तावेज़ीकरण के अनुसार दोनों विधियों को अभिन्न को अनुमानित करने के लिए "वैश्विक अनुकूली चतुर्थांश" का उपयोग करना चाहिए।

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

अजगर

import numpy as np
from scipy import integrate
import time

def integral(integrand, a, b,  arg):
    def real_func(x,arg):
        return np.real(integrand(x,arg))
    def imag_func(x,arg):
        return np.imag(integrand(x,arg))
    real_integral = integrate.quad(real_func, a, b, args=(arg))
    imag_integral = integrate.quad(imag_func, a, b, args=(arg))   
    return real_integral[0] + 1j*imag_integral[0]

vintegral = np.vectorize(integral)


def f_integrand(s, omega):
    sigma = np.pi/(np.pi+2)
    xs = np.exp(-np.pi*s/(2*sigma))
    x1 = -2*sigma/np.pi*(np.log(xs/(1+np.sqrt(1-xs**2)))+np.sqrt(1-xs**2))
    x2 = 1-2*sigma/np.pi*(1-xs)
    zeta = x2+x1*1j
    Vc = 1/(2*sigma)
    theta =  -1*np.arcsin(np.exp(-np.pi/(2.0*sigma)*s))
    t1 = 1/np.sqrt(1+np.tan(theta)**2)
    t2 = -1/np.sqrt(1+1/np.tan(theta)**2)
    return np.real((t1-1j*t2)/np.sqrt(zeta**2-1))*np.exp(1j*omega*s/Vc);

t0 = time.time()
omega = 10
result = integral(f_integrand, 0, np.inf, omega)
print time.time()-t0
print result

Matlab

function [ out ] = f_integrand( s, omega )
    sigma = pi/(pi+2); 
    xs = exp(-pi.*s./(2*sigma));
    x1 = -2*sigma./pi.*(log(xs./(1+sqrt(1-xs.^2)))+sqrt(1-xs.^2));
    x2 = 1-2*sigma./pi.*(1-xs);
    zeta = x2+x1*1j;
    Vc = 1/(2*sigma);
    theta =  -1*asin(exp(-pi./(2.0.*sigma).*s));
    t1 = 1./sqrt(1+tan(theta).^2);
    t2 = -1./sqrt(1+1./tan(theta).^2);
    out = real((t1-1j.*t2)./sqrt(zeta.^2-1)).*exp(1j.*omega.*s./Vc);
end

t=cputime;
omega = 10;
result = integral(@(s) f_integrand(s,omega),0,Inf)
time_taken = cputime-t

4
आपको खुशी होनी चाहिए कि पायथन केवल 25x धीमा है (और 250x नहीं)।
stali

4
क्योंकि आप बार-बार एक लूप में एक अजगर-फ़ंक्शन को बुला रहे हैं (द्वारा छिपाया गया है np.vectorize)। एक बार में पूरे सरणी पर गणना करने का प्रयास करें। यह संभव नहीं है, सुंबा या साइथन पर भी एक नज़र है, लेकिन मुझे आशा है कि उत्तरार्द्ध आवश्यक नहीं है।
सेबिक्स

2
"वैश्विक अनुकूली चतुर्भुज" इंगित करता है कि जब तक यह एक निश्चित परिशुद्धता तक नहीं पहुंच जाता है, तब तक यह पालन करता है। यह सुनिश्चित करने के लिए कि आप एक ही चीज़ की तुलना पैरामीटर के लिए देख रहे हैं (निश्चित रूप से एक है) जो सटीक सेट करता है और इसे दोनों के लिए सेट करता है।
bgschaid

2
@ Bgschaid की टिप्पणी के बारे में , क्रमशः integralडिफ़ॉल्ट पूर्ण और सापेक्ष सहिष्णुता हैं 1e-10और 1e-6integrate.quadइन दोनों को निर्दिष्ट करता है 1.49e-8। मैं यह नहीं देखता कि integrate.quadएक "वैश्विक अनुकूली" विधि के रूप में कहां वर्णित है और यह निश्चित रूप से (अनुकूली गॉस-क्रोन्रोड, मेरा मानना ​​है) विधि से भिन्न है integral। मुझे यकीन नहीं है कि "वैश्विक" भाग का क्या मतलब है, खुद। इसके अलावा, यह / या के cputimeबजाय का उपयोग करने के लिए एक अच्छा विचार नहीं है । tictoctime it
क्षितिज 13

5
कुछ भी करने से पहले मैं जांच करूंगा कि क्या समस्या एल्गोरिथ्म या भाषा है: एक वैश्विक काउंटर चर जोड़ें जो कार्यों के अंदर बढ़ा हुआ है। एकीकरण के बाद आपको यह बताना चाहिए कि प्रत्येक फ़ंक्शन का मूल्यांकन कितनी बार किया जाता है। यदि ये काउंटर काफी भिन्न होते हैं तो कम से कम समस्या का हिस्सा यह है कि MATLAB बेहतर एल्गोरिथ्म का उपयोग करता है
bgschaid

जवाबों:


15

प्रश्न के दो बहुत अलग उपवर्ग हैं। मैं पहले वाले को ही संबोधित करूंगा।

मतलाब का संस्करण मेरे अजगर के मुकाबले औसतन 24 गुना तेज चलता है !

दूसरा व्यक्तिपरक है। मैं कहूंगा कि उपयोगकर्ता को यह बताएं कि अभिन्न के साथ कुछ समस्या है, यह एक अच्छी बात है और यह SciPy व्यवहार किसी को चुप रखने के लिए Matlab`s से बेहतर प्रदर्शन करता है और किसी तरह से आंतरिक रूप से केवल Matabab इंजीनियरों द्वारा ज्ञात तरीके से निपटने की कोशिश करता है जो यह सबसे अच्छा होने का फैसला किया।

मैंने NaN की चेतावनी से बचने के लिए एकीकरण अवधि को 0 से 30 ( 0 से np.inf के बजाय ) में बदल दिया और एक JIT संकलन जोड़ा। समाधान को बेंचमार्क करने के लिए मैंने 300 बार एकीकरण को दोहराया, परिणाम मेरे लैपटॉप से ​​हैं।

JIT संकलन के बिना:

$ ./test_integrate.py
34.20992112159729
(0.2618828053067563+0.24474506983644717j)

JIT संकलन के साथ:

$ ./test_integrate.py
0.8560323715209961
(0.261882805306756+0.24474506983644712j)

इस तरह कोड की दो पंक्तियों को जोड़ने से गैर-जेआईटी संस्करण की तुलना में पायथन कोड के लगभग 40 गुना स्पीडअप कारक हो जाते हैं । मेरे पास बेहतर तुलना प्रदान करने के लिए मेरे लैपटॉप पर कोई माटलैब नहीं है, हालांकि, अगर यह 24/40 = 0.6 की तुलना में आपके पीसी के लिए अच्छी तरह से मापता है, तो जेआईटी के साथ पायथन को इस विशेष उपयोगकर्ता एल्गोरिथ्म के लिए मतलब के रूप में लगभग दोगुना होना चाहिए । पूर्ण कोड:

#!/usr/bin/env python3
import numpy as np
from scipy import integrate
from numba import complex128,float64,jit
import time

def integral(integrand, a, b,  arg):
    def real_func(x,arg):
        return np.real(integrand(x,arg))
    def imag_func(x,arg):
        return np.imag(integrand(x,arg))
    real_integral = integrate.quad(real_func, a, b, args=(arg))
    imag_integral = integrate.quad(imag_func, a, b, args=(arg))   
    return real_integral[0] + 1j*imag_integral[0]

vintegral = np.vectorize(integral)


@jit(complex128(float64, float64), nopython=True, cache=True)
def f_integrand(s, omega):
    sigma = np.pi/(np.pi+2)
    xs = np.exp(-np.pi*s/(2*sigma))
    x1 = -2*sigma/np.pi*(np.log(xs/(1+np.sqrt(1-xs**2)))+np.sqrt(1-xs**2))
    x2 = 1-2*sigma/np.pi*(1-xs)
    zeta = x2+x1*1j
    Vc = 1/(2*sigma)
    theta =  -1*np.arcsin(np.exp(-np.pi/(2.0*sigma)*s))
    t1 = 1/np.sqrt(1+np.tan(theta)**2)
    t2 = -1/np.sqrt(1+1/np.tan(theta)**2)
    return np.real((t1-1j*t2)/np.sqrt(zeta**2-1))*np.exp(1j*omega*s/Vc);

t0 = time.time()
omega = 10
for i in range(300): 
    #result = integral(f_integrand, 0, np.inf, omega)
    result = integral(f_integrand, 0, 30, omega)
print (time.time()-t0)
print (result)

अपने पीसी के अंतर को देखने के लिए @jit लाइन पर टिप्पणी करें।


1

कभी-कभी एकीकृत करने का कार्य JITed नहीं किया जा सकता है। उस मामले में, एक और एकीकरण विधि का उपयोग करना समाधान होगा।

मैं सिफारिश scipy.integrate.romberg (रेफरी) करूंगा । rombergजटिल कार्यों को एकीकृत कर सकते हैं, और सरणी के साथ फ़ंक्शन का मूल्यांकन कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.