2025, Oct 17 10:31
SymPy linsolve में मुक्त चरों का स्थिरीकरण: Tuple व subs का सटीक उपयोग
SymPy linsolve के पैरामीट्रिक समाधान में free variables को ठोस करें: Tuple में लपेटें, free_symbols से प्रतीक चुनें और subs से शून्य, पूर्णांक/Rational मान दें.
जब SymPy का linsolve पैरामीट्रिक समाधान लौटाता है, तो उसमें प्रायः मुक्त चर (free variables) होते हैं। उस समाधान को ठोस रूप देने का मतलब आमतौर पर उन पैरामीटरों के लिए मान प्रतिस्थापित करना होता है। मुश्किल यह है कि इसे साफ-सुथरे और एकसमान तरीके से कैसे किया जाए—खासकर तब, जब अलग-अलग प्रणालियों में मुक्त चरों का समूह बदलता रहता है।
समस्या की रूपरेखा
मान लें कि आपके पास linsolve से आया एक समाधान वेक्टर है, जिसमें कई प्रतीक मुक्त हैं। उदाहरण के लिए, इस संरचना को देखें:
from sympy import symbols
y2, y4, y5, y6, y7, y8 = symbols('y2 y4 y5 y6 y7 y8')
ans_vec = (
    -2.0*y2 - 2.0,
    4.0*y4 + 4.0*y7 + 2.0,
    y2,
    -2.0*y4 - 1.0*y5 - 2.0*y7 - 2.0,
    y4,
    y5,
    y6,
    y7,
    y8,
)
यहाँ y2, y4, y5, y6, y7, y8 मुक्त चर हैं। यदि आप एक ठोस उदाहरण चाहते हैं, तो आप इन्हें शून्य से बदल सकते हैं और (-2.0, 2.0, 0, -2.0, 0, 0, 0, 0, 0) जैसा संख्यात्मक वेक्टर पा सकते हैं। इसे हाथ से छँटाई किए बिना भरोसेमंद तरीके से करने के लिए एक ऐसा कंटेनर चाहिए जो प्रतिस्थापन के अनुकूल हो, और शामिल प्रतीकों को एक स्थिर तरीके से इकट्ठा किया जा सके।
पर्दे के पीछे क्या होता है
SymPy के अभिव्यक्तियों में subs से प्रतिस्थापन किया जा सकता है, पर Python के साधारण tuples में SymPy की यह यांत्रिकी मौजूद नहीं होती। उपाय यह है कि समाधान के अवयवों को ऐसे कंटेनर में लपेटें जिसे SymPy समझता हो, ताकि subs पूरी संरचना में चल सके। एक और व्यावहारिक बात यह है कि मुक्त चरों का सेट बदलता रहता है, इसलिए नामों को हाथ से चुनना त्रुटिप्रवण हो जाता है। अभिव्यक्ति की अपनी free_symbols संपत्ति का उपयोग करके हम सीधे SymPy से पूछ लेते हैं कि किन प्रतीकों की उपस्थिति है—और समस्या सुलझ जाती है।
साफ-सुथरे प्रतिस्थापन पैटर्न
एक संक्षिप्त तरीका यह है कि अनुक्रम को Tuple में रखें और एक डिक्शनरी के साथ subs लागू करें। यदि आपको पहले से पता है कि किन चरों को स्थिर करना है, तो उन्हें स्पष्ट रूप से मैप करें:
from sympy import Tuple as TPack
# केवल ज्ञात प्रतीकों के उपसमुच्चय का प्रतिस्थापन करें
TPack(*ans_vec).subs({s: 0 for s in (y2, y4, y5, y6, y7, y8)})
# परिणाम: (-2.0, 2.0, 0, -2.0, 0, 0, 0, 0, 0)
यदि मुक्त चरों का सेट बदलता रहता है और आप अभिव्यक्ति में उपस्थित हर चीज़ को बस शून्य करना चाहते हैं, तो लिपटे हुए ऑब्जेक्ट की free_symbols का उपयोग करें:
wrapped = TPack(*ans_vec)
wrapped.subs({t: 0 for t in wrapped.free_symbols})
# परिणाम: (-2.0, 2.0, 0, -2.0, 0, 0, 0, 0, 0)
प्रतिस्थापन का लक्ष्य अनिवार्य रूप से शून्य नहीं होना चाहिए। वह कोई भी वैध वस्तु हो सकती है—जैसे 1 जैसा पूर्णांक या कोई अन्य प्रतीक। यदि आपको एकदम सटीक भिन्न चाहिए, जैसे एक-तिहाई, तो 1/3 सीधे न लिखें, क्योंकि वह दशमलवी अनुमान में बदल सकता है; सटीक Rational के लिए S(1)/3 प्रयोग करें।
from sympy import Symbol, S
z = Symbol('z')
wrapped.subs({t: z for t in wrapped.free_symbols})
wrapped.subs({t: S(1)/3 for t in wrapped.free_symbols})
यह क्यों मायने रखता है
पैरामीट्रिक समाधानों में मुक्त चरों की सूची स्थिर नहीं रहती। प्रतिस्थापन मैप हाथ से बनाना न तो स्केलेबल है और न ही त्रुटियों से मुक्त। समाधान को subs-सक्षम कंटेनर में लपेटना और free_symbols पर भरोसा करना कार्यप्रवाह को सधा हुआ और मजबूत बनाता है। साथ ही, जहाँ आवश्यकता हो, पैरामीटरों को शून्य करना, पूर्णांक भरना या सटीक भिन्न डालना—इनके बीच स्विच करना भी आसान हो जाता है।
मुख्य बातें
linsolve के आउटपुट का पोस्ट-प्रोसेसिंग करते समय परिणाम को Tuple में लपेटकर SymPy अभिव्यक्ति की तरह लें और subs के जरिए प्रतिस्थापन करें। आप या तो किसी खास प्रतीकों के उपसमुच्चय को लक्ष्य बना सकते हैं, या जब सब कुछ एक साथ बदलना हो तो free_symbols का सहारा लें। यदि सटीक भिन्न चाहिए, तो अनचाही दशमलवी निकटता से बचने के लिए 1/3 की जगह S(1)/3 को प्राथमिकता दें।
यह लेख StackOverflow पर प्रश्न (लेखक: some1fromhell) और smichr के उत्तर पर आधारित है।