8

कहानी:उत्पन्न सूची

:

वर्तमान में, मैं एक समारोह-अंडर-परीक्षण है कि पूर्णांकों की सूची निम्नलिखित नियमों के साथ के सूची उम्मीद है

  1. उप-सूचियों (यह N कॉल) की संख्या हो सकती है से उप-सूचियों के अंदर मूल्यों की 1 50
  2. को संख्या में सभी उप-सूचियों के लिए एक ही है (आयताकार फार्म) और होना चाहिए> = 0 और < = 5
  3. उपन्यासकारों के अंदर मूल्य उपन्यासियों की कुल संख्या से अधिक या बराबर नहीं हो सकते हैं।

    [[0]] 
    [[2, 1], [2, 0], [3, 1], [1, 0]] 
    [[1], [0]] 
    

    नमूना गलत निविष्टियों:

    [[2]] # 2 is more than N=1 (total number of sublists) 
    [[0, 1], [2, 0]] # 2 is equal to N=2 (total number of sublists) 
    

    मैं कोशिश कर रहा हूँ दूसरे शब्दों में, एक sublist अंदर प्रत्येक मान एक पूर्णांक> = 0 और < N

नमूना मान्य इनपुट है संपत्ति-आधारित-परीक्षण के साथ पहुंचने के लिए और hypothesis library के साथ अलग-अलग मान्य इनपुट उत्पन्न करें औरके आसपास अपना सिर लपेटने का प्रयास करेंऔर integers(), लेकिन यह काम नहीं कर सकते हैं:

  • हालत # 1 lists() और min_size और max_size तर्क
  • हालत # 2 Chaining strategies together
  • तहत कवर किया जाता के साथ संपर्क करना आसान है # 3 शर्त है मैं इसके साथ संघर्ष कर रहा हूं - कारण, यदि हम ऊपर दिए गए उदाहरण से rectangle_lists का उपयोग करते हैं, तो हमारे पास integers()
के अंदर "पैरेंट" सूची की लंबाई का संदर्भ नहीं है 210

प्रश्न:

मैं कैसे उप-सूचियों की कुल संख्या की तुलना में कम होने के लिए उप-सूचियों के अंदर पूर्णांक मूल्यों सीमित कर सकते हैं?


मेरे प्रयास से कुछ:

from hypothesis import given 
from hypothesis.strategies import lists, integers 

@given(lists(lists(integers(min_value=0, max_value=5), min_size=1, max_size=5), min_size=1, max_size=50)) 
def test(l): 
    # ... 

यह एक आवश्यकताओं को पूरा करने से बहुत दूर था - सूची एक आयताकार रूप से सख्ती से नहीं है और उत्पन्न पूर्णांक मूल्यों सूची के आकार से अधिक उत्पन्न जा सकते हैं ।

from hypothesis import given 
from hypothesis.strategies import lists, integers 

@given(integers(min_value=0, max_value=5).flatmap(lambda n: lists(lists(integers(min_value=1, max_value=5), min_size=n, max_size=n), min_size=1, max_size=50))) 
def test(l): 
    # ... 

यहाँ, # 1 और # 2 हैं जरूरतें पूरी नहीं की जा रही थी, लेकिन पूर्णांक मूल्यों सूची के आकार से भी बड़ा जा सकते हैं - # 3 आवश्यकता पूरी नहीं कर रहा है।

उत्तर

5

ऐसी अच्छी सामान्य तकनीक है जो इस तरह की मुश्किल बाधाओं को हल करने की कोशिश करते समय अक्सर उपयोगी होती है: ऐसा कुछ बनाने की कोशिश करें जो आप चाहते हैं कि थोड़ा सा दिखता है लेकिन सभी बाधाओं को पूरा नहीं करता है और फिर इसे एक फ़ंक्शन के साथ लिखता है इसे संशोधित करता है (उदाहरण के लिए खराब बिट्स को फेंकना या उन बिट्स को पकड़ना जो काफी काम नहीं करते हैं) ताकि यह बाधाओं को पूरा कर सके।

from hypothesis.strategies import builds, lists, integers 

def prune_list(ls): 
    n = len(ls) 
    return [ 
     [i for i in sublist if i < n][:5] 
     for sublist in ls 
    ] 

limited_list_strategy = builds(
    prune_list, 
    lists(lists(integers(0, 49), average_size=5), max_size=50, min_size=1) 
) 

इस हम में:

अपने मामले के लिए, आप निम्नलिखित की तरह कुछ कर सकते हैं

  1. एक सूची है कि मोटे तौर पर सही लग रहा है उत्पन्न (यह पूर्णांकों और की सूची की एक सूची है पूर्णांक एक ही सीमा में हैं क्योंकि सभी संभव सूचकांक मान्य हो सकते हैं)।
  2. उप-सूचियों से किसी भी अवैध सूचकांक बाहर छँटाई
  3. किसी भी उप-सूचियों उनमें अभी भी अधिक से अधिक 5 तत्वों

परिणाम सभी तीन शर्तों आप की जरूरत को पूरा करना चाहिए है कि काटें।

औसत_ आकार पैरामीटर सख्ती से जरूरी नहीं है लेकिन इसके प्रयोग में मैंने पाया कि यह खाली sublists अन्यथा उत्पादन करने के लिए थोड़ा सा प्रवण था।

ईटीए: माफी। मुझे अभी एहसास हुआ है कि मैंने आपकी शर्तों में से एक को गलत तरीके से पढ़ा है - यह वास्तव में आप जो चाहते हैं वह वास्तव में नहीं करता है क्योंकि यह सुनिश्चित नहीं करता है कि प्रत्येक सूची एक ही लंबाई है। यहाँ यह है कि ठीक करने के लिए संशोधित करने के लिए एक रास्ता है (यह थोड़ा और अधिक जटिल हो जाता है, तो मैं बजाय समग्र का उपयोग कर अपना ली है बनाता है):

from hypothesis.strategies import composite, lists, integers, permutations 


@composite 
def limisted_lists(draw): 
    ls = draw(
     lists(lists(integers(0, 49), average_size=5), max_size=50, min_size=1) 
    ) 
    filler = draw(permutations(range(50))) 
    sublist_length = draw(integers(0, 5)) 

    n = len(ls) 
    pruned = [ 
     [i for i in sublist if i < n][:sublist_length] 
     for sublist in ls 
    ] 

    for sublist in pruned: 
     for i in filler: 
      if len(sublist) == sublist_length: 
       break 
      elif i < n: 
       sublist.append(i) 
    return pruned 

विचार यह है कि हम एक "पूरक" सूची प्रदान करता है कि उत्पन्न एक सुस्त दिखने के लिए डिफ़ॉल्ट (जैसे वे एक दूसरे के समान होने की दिशा में कम हो जाते हैं) और फिर उस स्थिरता को प्राप्त करने के लिए उपन्यासियों की लंबाई को आकर्षित करने के लिए आकर्षित करें।

यह बहुत जटिल है मैं स्वीकार करता हूं। आप रिकर्सिवइरिकॉन के फ्लैटमैप आधारित संस्करण का उपयोग करना चाह सकते हैं। मुख्य कारण यह है कि मैं इसे पसंद करता हूं कि यह बेहतर हो जाएगा, इसलिए आपको इसके अच्छे उदाहरण मिलेंगे।

+1

बढ़िया, मुझे यह विचार मिला! इस भयानक लाइब्रेरी के लेखक को एसओ पर मदद करने के लिए खुशी हुई, उत्तर और परिकल्पना के लिए बहुत बहुत धन्यवाद - यह एक उत्कृष्ट कृति है! – alecxe

+1

आपका बहुत स्वागत है। खुशी है कि आप पुस्तकालय का आनंद ले रहे हैं। :-) – DRMacIver

4

आप इसे flatmap के साथ भी कर सकते हैं, हालांकि यह एक छोटा सा गर्भपात है।

from hypothesis import strategies as st 
from hypothesis import given, settings 

number_of_lists = st.integers(min_value=1, max_value=50) 
list_lengths = st.integers(min_value=0, max_value=5) 

def build_strategy(number_and_length): 
    number, length = number_and_length 
    list_elements = st.integers(min_value=0, max_value=number - 1) 
    return st.lists(
     st.lists(list_elements, min_size=length, max_size=length), 
     min_size=number, max_size=number) 

mystrategy = st.tuples(number_of_lists, list_lengths).flatmap(build_strategy) 

@settings(max_examples=5000) 
@given(mystrategy) 
def test_constraints(list_of_lists): 
    N = len(list_of_lists) 

    # condition 1 
    assert 1 <= N <= 50 

    # Condition 2 
    [length] = set(map(len, list_of_lists)) 
    assert 0 <= length <= 5 

    # Condition 3 
    assert all((0 <= element < N) for lst in list_of_lists for element in lst) 

दाऊद उल्लेख किया है, इस खाली सूचियों का एक बहुत का उत्पादन करते हैं करता है, इसलिए कुछ औसत आकार ट्यूनिंग की आवश्यकता होगी।

>>> mystrategy.example() 
[[24, 6, 4, 19], [26, 9, 15, 15], [1, 2, 25, 4], [12, 8, 18, 19], [12, 15, 2, 31], [3, 8, 17, 2], [5, 1, 1, 5], [7, 1, 16, 8], [9, 9, 6, 4], [22, 24, 28, 16], [18, 11, 20, 21], [16, 23, 30, 5], [13, 1, 16, 16], [24, 23, 16, 32], [13, 30, 10, 1], [7, 5, 14, 31], [31, 15, 23, 18], [3, 0, 13, 9], [32, 26, 22, 23], [4, 11, 20, 10], [6, 15, 32, 22], [32, 19, 1, 31], [20, 28, 4, 21], [18, 29, 0, 8], [6, 9, 24, 3], [20, 17, 31, 8], [6, 12, 8, 22], [32, 22, 9, 4], [16, 27, 29, 9], [21, 15, 30, 5], [19, 10, 20, 21], [31, 13, 0, 21], [16, 9, 8, 29]] 
>>> mystrategy.example() 
[[28, 18], [17, 25], [26, 27], [20, 6], [15, 10], [1, 21], [23, 15], [7, 5], [9, 3], [8, 3], [3, 4], [19, 29], [18, 11], [6, 6], [8, 19], [14, 7], [25, 3], [26, 11], [24, 20], [22, 2], [19, 12], [19, 27], [13, 20], [16, 5], [6, 2], [4, 18], [10, 2], [26, 16], [24, 24], [11, 26]] 
>>> mystrategy.example() 
[[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []] 
>>> mystrategy.example() 
[[], [], [], [], [], [], [], [], [], [], [], [], [], [], []] 
>>> mystrategy.example() 
[[6, 8, 22, 21, 22], [3, 0, 24, 5, 18], [16, 17, 25, 16, 11], [2, 12, 0, 3, 15], [0, 12, 12, 12, 14], [11, 20, 6, 6, 23], [5, 19, 2, 0, 12], [16, 0, 1, 24, 10], [2, 13, 21, 19, 15], [2, 14, 27, 6, 7], [22, 25, 18, 24, 9], [26, 21, 15, 18, 17], [7, 11, 22, 17, 21], [3, 11, 3, 20, 16], [22, 13, 18, 21, 11], [4, 27, 21, 20, 25], [4, 1, 13, 5, 13], [16, 19, 6, 6, 25], [19, 10, 14, 12, 14], [18, 13, 13, 16, 3], [12, 7, 26, 26, 12], [25, 21, 12, 23, 22], [11, 4, 24, 5, 27], [25, 10, 10, 26, 27], [8, 25, 20, 6, 23], [8, 0, 12, 26, 14], [7, 11, 6, 27, 26], [6, 24, 22, 23, 19]] 
+0

अतिरिक्त स्पष्ट टिप्पणियों और दावों के लिए अलग-अलग धन्यवाद! अच्छी तरह से काम! – alecxe

1

सुंदर देर से, लेकिन भावी पीढ़ी के लिए: सबसे आसान समाधान आयाम लेने के लिए है, तो तत्व रणनीति से निर्माण है।

from hypothesis.strategies import composite, integers, lists 

@composite 
def complicated_rectangles(draw, max_N): 
    list_len = draw(integers(1, max_N)) 
    sublist_len = draw(integers(0, 5)) 
    element_strat = integers(0, min(list_len, 5)) 
    sublist_strat = lists(
     element_strat, min_size=sublist_len, max_size=sublist_len) 
    return draw(lists(
     sublist_strat, min_size=list_len, max_size=list_len)) 
संबंधित मुद्दे