2017-09-12 20 views
14

मैंने किसी चीज़ obj और कार्योंएक वस्तु को देखते हुए कार्यों कि विशेषताओं को बदलने की विशेषताओं के "बंद" कम्प्यूटिंग

def func1(obj): 
    #... 

    def func2(obj): 
    #... 

    def func3(obj): 
    #... 

कि प्रत्येक obj की विशेषताओं के मूल्यों को बदल की एक संख्या है।

मैं अपने इनपुट होना चाहता हूँ कुछ

obj = MyObject() 
obj.attr=22 

यह एक समारोह closure() कि उपरोक्त कार्यों के सभी संभव applictions गणना करने के लिए पारित किया जाना चाहिए, func1(func2(obj)), func3(func1(func1(obj))) आदि अर्थ एक निश्चित रोक हालत अप करने के लिए (जैसे उदाहरण के लिए 20 से अधिक फ़ंक्शन रचनाएं नहीं)।

आउटपुट सभी संभावित आउटपुट की एक सूची होनी चाहिए जिसमें सभी पथ मौजूद हैं। तो अगर 104 और 93obj.attr=22 पर एक संभावित अंतिम आउटपुट हैं, और 104 पर पहुंचने के दो तरीके हैं और एक 93 पर पहुंचने के दो तरीके हैं। तब

print closure(obj) 

[22, 64, 21, 104] #first path to 104 through , func1(obj),func1(func1(obj)), func1(func1(func3(obj))) 

[22, 73, 104] #second path to 104 through , func3(obj),func3(func2(obj)), 

[22, 11, 93] #the only path to arrive at 94 

की तरह कुछ होना चाहिए मैं यह कैसे लागू कर सकता है? टिप्पणियों में सुझाव दिया गया था, यह पेड़ों के साथ सबसे अच्छा किया जाता है, लेकिन हालांकि मैंने 2 दिनों की कोशिश की, मैंने लगभग कोई प्रगति नहीं की है कि मैं इसे लागू कर रहा हूं (मैं पाइथन/प्रोग्रामिंग के लिए नया हूं)!
मेरा उदाहरण इतना आसान है कि func(obj) के बजाय हम सीधे func(22) का उपयोग कर सकते हैं, लेकिन जिस उदाहरण पर मुझे काम करने की आवश्यकता है, वह अधिक जटिल है, जहां मुझे निश्चित रूप से वस्तुओं का उपयोग करने की आवश्यकता होगी, इसलिए यह केवल इसके लिए एक न्यूनतम कार्य उदाहरण होगा।

पेड़ शायद एक पूर्ण एन-आरी पेड़ नहीं होगा, क्योंकि प्रत्येक फ़ंक्शन एप्लिकेशन में एक परीक्षण होगा जिसमें इसे obj की वर्तमान स्थिति (विशेषताओं के) पर लागू किया जा सकता है और कुछ मामलों में परीक्षण छोड़ने में विफल रहेगा (के गुण) obj अपरिवर्तित।

+0

ऐसा लगता है कि आप एक वृक्ष संरचना चाहते हैं जहां प्रत्येक नोड एक राज्य है और शाखाओं द्वारा कार्य किया जाता है (प्रत्येक कार्य एक राज्य लेता है और ** नया ** नोड/राज्य बनाता है)। एआई और अन्य क्षेत्रों में यह सामान्य प्रथा है और यहां उपयोगी हो सकती है। एक बार जब आप आवश्यक राज्य तक पहुंचे तो पता लगाने के लिए बस रूट पर वापस जाएं। ओह, और यदि संभव हो तो इसे बीएफएस बनाएं :) –

+0

@ReutSharabani हां, ऐसा लगता है कि मुझे लगता है कि मैं सोचता हूं, thx। लेकिन हालांकि बीएफएस का उपयोग क्यों करें? – user47574

+1

ठीक है, यदि आप डीएफएस का उपयोग करते हैं और आपके पास फ़ंक्शंस का एक अनंत अनुप्रयोग पथ है ... यदि कोई "समाधान" है तो भी आपको कुछ भी सार्थक नहीं मिल रहा है। हालांकि, यदि कोई समाधान है, तो डीएफएस इसे खोजने की गारंटी देता है (लेकिन आप स्मृति में भुगतान करते हैं, डीएफएस के विपरीत जो निरंतर स्मृति है)। आप इसे रोकने के लिए पुनरावर्तक डीएफएस (इसे Google) भी उपयोग कर सकते हैं। –

उत्तर

3

यहाँ एक सरल उदाहरण खोजने के लिए एक नंबर (goal) जब Collatz conjecture में नियम लागू करने के एक पूर्ववर्ती एक और (inital_state) की है कि क्या की कोशिश करता है है।

अपने उदाहरण में, objstate है, और [func1, func2, ...] मेरे उदाहरण में functions है। यह संस्करण फ़ंक्शन अनुप्रयोगों की संख्या को कम करने, अंतिम आउटपुट के लिए पथ लौटाएगा। खोज के बजाय, आप लक्ष्य परीक्षण को हटाकर और prev_states लौटने के बाद सभी राज्यों को सूचीबद्ध कर सकते हैं।

from collections import deque 

def multiply_by_two(x): 
    return x * 2 

def sub_one_div_three(x): 
    if (x - 1) % 3 == 0: 
     return (x - 1) // 3 
    else: 
     return None # invalid 


functions = [multiply_by_two, sub_one_div_three] 

# find the path to a given function 
def bfs(initial_state, goal): 
    initial_path = [] 
    states = deque([(initial_state, initial_path)])  # deque of 2-tuples: (state, list of functions to get there) 
    prev_states = {initial_state}      # keep track of previously visited states to avoid infinite loop 

    while states: 
     # print(list(map(lambda x: x[0], states)))  # print the states, not the paths. useful to see what's going on 
     state, path = states.popleft() 

     for func in functions: 
      new_state = func(state) 

      if new_state == goal:      # goal test: if we found the state, we're done 
       return new_state, path + [func] 

      if (new_state is not None and   # check that state is valid 
       new_state not in prev_states):  # and that state hasn't been visited already 
       states.append((new_state, path + [func])) 
      prev_states.add(new_state)    # make sure state won't be added again 
    else: 
     raise Exception("Could not get to state") 

print(functions) 
print(bfs(1, 5)) 

# prints (5, [<function multiply_by_two at 0x000002E746727F28>, <function multiply_by_two at 0x000002E746727F28>, <function multiply_by_two at 0x000002E746727F28>, <function multiply_by_two at 0x000002E746727F28>, <function sub_one_div_three at 0x000002E7493C9400>]). You can extract the path from here. 
+0

मैं वर्तमान में कोड को समझने की कोशिश कर रहा हूं (मेरे साथ भालू भालू, क्योंकि मैं एक नौसिखिया हूं), ताकि मैं इसे अपनी जरूरतों के अनुसार अनुकूलित कर सकूं। ऐसा लगता है कि आपका बीएफएस फ़ंक्शन किसी दिए गए ग्राफ के बीएफएस की गणना नहीं करता है, लेकिन सीधे ग्राफ बनाता है, है ना? क्या यह मानक डिज़ाइन पसंद है, या संभावना है कि पहले एक पेड़ वर्ग/ऑब्जेक्ट को अलग से बनाया जाए, जहां प्रत्येक नोड फॉर्म 'func3 (func1 (func (2 (...))) की सूची है) और फिर इसे पार करने के लिए एक बीएफएस का उपयोग करें? कम से कम अवधारणात्मक रूप से यह है कि मैंने इसे कैसे किया होगा। – user47574

+0

आप सही हैं, मैं स्पष्ट रूप से ग्राफ/पेड़ की गणना नहीं कर रहा हूं। यदि आपको ग्राफ पर अधिक संचालन करने की आवश्यकता है, तो इसे कैश करने का अर्थ होगा, लेकिन यदि यह एकमात्र ऑपरेशन है, तो इसे स्पष्ट रूप से बनाने के लिए कोई कारण नहीं है – user3080953

+0

मैंने इन्ट्स के बजाय ऑब्जेक्ट्स का उपयोग करने के बारे में आपका संपादन देखा। इसे ठीक करने के लिए, आपको अपने राज्य को हर्षित करने की आवश्यकता है ('__hash__' लागू करें) और 'func (state)' को ऑब्जेक्ट वापस कर दें, 'स्थिति' को संशोधित न करें – user3080953

1

मज़ेदार लगता है, चलिए इसे चरणों में तोड़ दें।

  1. कार्यों के संभावित संयोजनों को चित्रित करें।

  2. कार्यों के संभावित संयोजन का मूल्यांकन करें।

संभव संयोजनों

एक तरह से यह करने के लिए जनरेटर का उपयोग कर रहा है इसके बारे में पता। वे स्मृति के मामले में कुशल हैं, इसलिए आप मूल्यों का एक गुच्छा बनाने और ढेर को अधिकतम करने का अंत नहीं करते हैं।

तो हम सभी संयोजन कैसे प्राप्त करते हैं। पायथन डॉक्स की एक त्वरित खोज itertools का उपयोग करने का सुझाव देती है। तो चलो करते हैं।

from itertools import combinations 

def comb(fns, n): 
    return combinations(fns, n) 

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

यह पेड़ में एक स्तर है। हम अगले स्तर को कैसे प्राप्त करते हैं। खैर, हम आकार 1 के सभी संयोजन और फिर आकार 2 के सभी संयोजन प्राप्त कर सकते हैं। चूंकि जनरेटर आलसी हैं, इसलिए हम व्याख्याकर्ता को उड़ाए बिना ऐसा करने में सक्षम होने के लिए कुछ भी कर सकते हैं।

def combo_tot(fns): 
    start=1 
    while (start <= len(fns)): 
     for c in comb(fns, start): 
      yield c 
     start += 1 

का मूल्यांकन संभव संयोजनों

तो अब हम सभी संभव संयोजनों, जो निरर्थक है। चलिए सामान का मूल्यांकन करने के लिए इसका इस्तेमाल करते हैं।

def evalf(fns_to_compose, initval): 
    v = initval 
    for fn in fns_to_compose: 
     v = fn(v) 
    return v 

तो यह दो भाग है। अब आपको चेन एम करना है।

def results(fns, init): 
    return (evalf(fn, init) for fn in combo_tot(fns)) 

अब आपको जितनी जरूरत हो उतनी नतीजे लें।

नकारात्मक पहलू किसी भी विधि का obj क्लोन नहीं है के साथ के रूप में

ही। यह वस्तु को म्यूट करने जा रहा है। इसके अलावा, हमारे पास जेनरेटर का ओवरहेड है (जो फॉर-लूप से थोड़ा धीमा हो सकता है)। हमारे पास पठनीयता के लिए भी हिट है (विशेष रूप से यदि कोई जनरेटर से परिचित नहीं है)।

अस्वीकरण: मैं इसे एक फोन पर टाइप कर रहा हूं। मामूली टाइपो आदि मौजूद हो सकते हैं।

संबंधित मुद्दे