सटीक फिनिशिंग पॉइंट और शून्य टर्मिनल वेग के साथ रेसट्रैक का वेरिएंट


9

परिचय

चुनौती खेल रेसट्रैक और उन दो चुनौतियों का एक बहुत ही दिलचस्प संस्करण है :

इस चुनौती का स्रोत यहां (जर्मन में) है: c't-Racetrack

यह चुनौती विशेष रूप से दिलचस्प है (और दो उपर्युक्त चुनौतियों से अलग) क्योंकि यह कुछ सटीक स्थितियों के साथ एक विशाल खोज-स्थान को जोड़ती है जिसे पूरा करना पड़ता है। विशाल खोज-स्थान के कारण विस्तृत खोज तकनीकों का उपयोग करना कठिन है, क्योंकि सटीक परिस्थितियों के कारण अनुमानित तरीके भी आसानी से उपयोग करने योग्य नहीं हैं। इस अनूठे संयोजन (प्लस भौतिकी से अंतर्निहित अंतर्ज्ञान) के कारण समस्या आकर्षक है (और रेसिंग कारों के संबंध में सब कुछ वैसे भी आकर्षक है;;)

चुनौती

निम्नलिखित रेसट्रैक ( स्रोत ) पर एक नज़र डालें :

यहां छवि विवरण दर्ज करें

आपको दीवारों में से एक को छूने के बिना (जर्मन में "ज़ील") पर शुरू (120,180)और खत्म करना होगा (320,220)

कार को फार्म के त्वरण वैक्टर द्वारा नियंत्रित किया (a_x,a_y)जाता है - उदाहरण के रूप में:

(8,-6)
(10,0)
(1,9)

पहला नंबर एक्स-वेक्टर के लिए त्वरण है, दूसरा वाई-वेक्टर के लिए है। उन्हें पूर्णांक होना चाहिए क्योंकि आपको ग्रिड पर पूर्णांक बिंदुओं का उपयोग करने की अनुमति है। इसके अतिरिक्त निम्नलिखित शर्त पूरी करनी होगी:

a_x^2 + a_y^2 <= 100,

जिसका अर्थ है कि किसी भी दिशा में त्वरण नीचे या उसके बराबर होना चाहिए 10

यह देखने के लिए कि यह कैसे काम करता है निम्नलिखित चित्र ( स्रोत ) पर एक नज़र है :

यहां छवि विवरण दर्ज करें

एक उदाहरण के रूप में: (120,180)आप से शुरू करके 8x- दिशा में और -6y- दिशा में तेजी लाते हैं । अगले चरण के लिए यह आपका वेग है जहां आप (10,0)अपने अगले परिणामी आंदोलन को प्राप्त करने के लिए (शारीरिक रूप से सही) अपने त्वरण को जोड़ते हैं (इंगित करने के लिए (146,168)। परिणामी आंदोलन वह होता है जब यह जांचने की बात आती है कि क्या आपने दीवारों में से एक को छुआ है। अगले चरण में आप फिर से अपने अगले त्वरण वेक्टर को अपने वर्तमान वेग में जोड़ते हैं ताकि अगले आंदोलन को प्राप्त किया जा सके। इसलिए हर कदम पर आपकी कार की एक स्थिति और एक वेग होता है। (नीले तीर के ऊपर चित्र में चित्र वेग के लिए है, नारंगी तीर। त्वरण के लिए और परिणामस्वरूप आंदोलन के लिए गहरे लाल तीर।)

(0,0)जब आप फिनिशिंग पॉइंट पर होते हैं तो अतिरिक्त स्थिति के रूप में आपके पास टर्मिनल वेलोसिटी होनी चाहिए (320,220)

आउटपुट को उपरोक्त रूप में त्वरण वैक्टर की एक सूची होना चाहिए।

विजेता वह है जो एक कार्यक्रम प्रदान करता है जो सबसे कम त्वरण वैक्टर के साथ एक समाधान पाता है।

टाईब्रेकर
इसके अलावा यह बहुत अच्छा होगा यदि आप दिखा सकते हैं कि यह एक इष्टतम समाधान है और क्या यह एकमात्र इष्टतम समाधान है या क्या कई इष्टतम समाधान हैं (और जो वे हैं)।

यह भी अच्छा होगा यदि आप एक सामान्य रूपरेखा दे सकते हैं कि आपका एल्गोरिदम कैसे काम करता है और कोड को कमेंट करता है ताकि हम इसे समझ सकें।

मेरे पास एक कार्यक्रम है जो यह जांचता है कि क्या कोई भी समाधान मान्य है और मैं प्रतिक्रिया दूंगा।

परिशिष्ट
आप किसी भी प्रोग्रामिंग भाषा का उपयोग कर सकते हैं, लेकिन मुझे विशेष रूप से खुशी होगी अगर कोई आर का उपयोग करता है क्योंकि मैं इसे अपने दिन के काम में बहुत उपयोग करता हूं और किसी भी तरह से इसका उपयोग किया जाता है :-)

परिशिष्ट II
पहली बार मैंने एक इनाम की शुरुआत की - उम्मीद है कि यह गेंद को लुढ़कने वाला है (या बेहतर: कार की सवारी करें) :-)


@Mego: फिर भी ... इसके बारे में सोचा: मुझे यकीन नहीं है कि मुझे कम से कम दो कारणों से कार्यक्रम जोड़ना चाहिए: सबसे पहले, मूल चुनौती में इसे या तो शामिल नहीं किया गया था, दूसरे, इसमें दिनचर्या शामिल है जो इसका हिस्सा हैं चुनौती (उदाहरण के टकराव का पता लगाने) तो यह मज़ा का हिस्सा खराब कर देगा ... मुझे इस पर सोना होगा ...
vonjd

1
क्या कार्यक्रम को वास्तव में पथ की गणना करने की आवश्यकता है, या क्या मैं पहले से इष्टतम पथ की गणना कर सकता हूं, और फिर कुछ ऐसा पोस्ट कर सकता हूं print "(10,42)\n(62,64)..."?
लोजोवो

@ लोजोवो: नहीं, कार्यक्रम को स्वयं पथ की गणना करनी है, इसलिए कार्यक्रम में बुद्धिमत्ता को शामिल किया जाना चाहिए, न कि केवल आउटपुट रूटीन के रूप में।
vonjd

जवाबों:


4

अजगर, 24 कदम (प्रगति में काम)

यह विचार था कि निरंतर समस्या को पहले हल किया जाए, खोज स्थान को बहुत कम किया जाए, और फिर परिणाम को ग्रिड में परिमाणित करें (निकटतम ग्रिडपॉइंट पर चक्कर लगाकर और आसपास के 8 वर्गों की खोज)

मैं ट्रिमोनोमेट्रिक फ़ंक्शंस के योग के रूप में पथ को परिमार्जित करता हूं (बहुपद के विपरीत, वे विचलन नहीं करते हैं और चेक में रखना आसान है)। मैं त्वरण के बजाय सीधे वेग को नियंत्रित करता हूं, क्योंकि इसकी भार सीमा को लागू करने के लिए सीमा स्थिति को लागू करना आसान होता है जो अंत में 0 पर जाता है।
मेरे उद्देश्य फ़ंक्शन में
त्वरण के लिए -exponential स्कोर होता है>
अंतिम बिंदु और लक्ष्य के बीच यूक्लिडियन दूरी के लिए 10- पोलीनोमियल स्कोर
, दीवार के किनारों की ओर घटते हुए, एक दीवार के साथ प्रत्येक चौराहे के लिए निरंतर स्कोर

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

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

परिमाणीकरण
एक पैरामीट्रिक पथ खोजने के बाद, दशमलव बिंदुओं को हटाने का समय था। 3x3 पड़ोस को देखने से खोज की जगह लगभग 300 ^ N से 9 ^ N तक कम हो जाती है, लेकिन इसे लागू करने के लिए अभी भी बहुत बड़ा और उबाऊ है। इससे पहले कि मैं इस सड़क से नीचे जाता, मैंने उद्देश्य समारोह (टिप्पणी भागों) में "स्नैप से ग्रिड" शब्द जोड़ने की कोशिश की। अद्यतन उद्देश्य के साथ अनुकूलन के सौ और चरण केवल समाधान प्राप्त करने के लिए पर्याप्त थे।

[(9, -1), (4, 0), (1, 1), (2, 2), (-1, 2), (-3, 4), (-3, 3), (-2 , 3), (-2, 2), (-1, 1), (0, 0), (1, -2), (2, -3), (2, -2), (3, -5) ), (2, -4), (1, -5), (-2, -3), (-2, -4), (-3, -9), (-4, -4), (- 5, 8), (-4, 8), (5, 8)]

चरणों की संख्या तय की गई थी और अनुकूलन का हिस्सा नहीं था, लेकिन जब से हमारे पास पथ का एक विश्लेषणात्मक विवरण है, (और चूंकि अधिकतम त्वरण 10 से नीचे है), हम इसे छोटी संख्या के साथ आगे अनुकूलन के लिए एक प्रारंभिक बिंदु के रूप में पुन: उपयोग कर सकते हैं। timesteps

from numpy import *
from scipy.optimize import fmin
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection as LC

walls = array([[[0,0],[500,0]],   # [[x0,y0],[x1,y1]]
        [[500,0],[500,400]],
        [[500,400],[0,400]],
        [[0,400],[0,0]],

        [[200,200],[100,200]],
        [[100,200],[100,100]],
        [[100,100],[200,100]],

        [[250,300],[250,200]],

        [[300,300],[300,100]],
        [[300,200],[400,200]],
        [[300,100],[400,100]],

        [[100,180],[120, 200]], #debug walls
        [[100,120],[120, 100]],
        [[300,220],[320, 200]],
        #[[320,100],[300, 120]],
])

start = array([120,180])
goal = array([320,220])

###################################
# Boring stuff below, scroll down #
###################################
def weightedintersection2D(L1, L2):
    # http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
    p = L1[0]
    q = L2[0]
    r = L1[1]-L1[0]
    s = L2[1]-L2[0]
    d = cross(r,s)
    if d==0: # parallel
        if cross(q-p,r)==0: return 1 # overlap
    else:
        t = cross(q-p,s)*1.0/d
        u = cross(q-p,r)*1.0/d
        if 0<=t<=1 and 0<=u<=1: return 1-0*abs(t-.5)-1*abs(u-.5) # intersect at p+tr=q+us
    return 0

def sinsum(coeff, tt):
    '''input: list of length 2(2k+1), 
    first half for X-movement, second for Y-movement.
    Of each, the first k elements are sin-coefficients
    the next k+1 elements are cos-coefficients'''
    N = len(coeff)/2
    XS = [0]+list(coeff[:N][:N/2])
    XC =     coeff[:N][N/2:]
    YS = [0]+list(coeff[N:][:N/2])
    YC =     coeff[N:][N/2:]
    VX = sum([XS[i]*sin(tt*ww[i]) + XC[i]*cos(tt*ww[i]) for i in range(N/2+1)], 0)
    VY = sum([YS[i]*sin(tt*ww[i]) + YC[i]*cos(tt*ww[i]) for i in range(N/2+1)], 0)
    return VX*weightfunc, VY*weightfunc

def makepath(vx, vy):
    # turn coordinates into line segments, to check for intersections
    xx = cumsum(vx)+start[0]
    yy = cumsum(vy)+start[1]
    path = []
    for i in range(1,len(xx)):
        path.append([[xx[i-1], yy[i-1]],[xx[i], yy[i]]])
    return path

def checkpath(path):
    intersections = 0
    for line1 in path[:-1]: # last two elements are equal, and thus wrongly intersect each wall
        for line2 in walls:
            intersections += weightedintersection2D(array(line1), array(line2))
    return intersections

def eval_score(coeff):
    # tweak everything for better convergence
    vx, vy = sinsum(coeff, tt)
    path = makepath(vx, vy)
    score_int = checkpath(path)
    dist = hypot(*(path[-1][1]-goal))
    score_pos = abs(dist)**3
    acc = hypot(diff(vx), diff(vy))
    score_acc = sum(exp(clip(3*(acc-10), -10,20)))
    #score_snap = sum(abs(diff(vx)-diff(vx).round())) + sum(abs(diff(vy)-diff(vy).round()))
    print score_int, score_pos, score_acc#, score_snap
    return score_int*100 + score_pos*.5 + score_acc #+ score_snap

######################################
# Boring stuff above, scroll to here #
######################################
Nw = 4 # <3: paths not squiggly enough, >6: too many dimensions, slow
ww = [1*pi*k for k in range(Nw)]
Nt = 30 # find a solution with tis many steps
tt = linspace(0,1,Nt)
weightfunc = tanh(tt*30)*tanh(30*(1-tt)) # makes sure end velocity is 0

guess = random.random(4*Nw-2)*10-5
guess = array([ 5.72255365, -0.02720178,  8.09631272,  1.88852287, -2.28175362,
        2.915817  ,  8.29529905,  8.46535503,  5.32069444, -1.7422171 ,
       -3.87486437,  1.35836498, -1.28681144,  2.20784655])  # this is a good start...
array([ 10.50877078,  -0.1177561 ,   4.63897574,  -0.79066986,
         3.08680958,  -0.66848585,   4.34140494,   6.80129358,
         5.13853914,  -7.02747384,  -1.80208349,   1.91870184,
        -4.21784737,   0.17727804]) # ...and it returns this solution      

optimsettings = dict(
    xtol = 1e-6,
    ftol = 1e-6,
    disp = 1,
    maxiter = 1000, # better restart if not even close after 300
    full_output = 1,
    retall = 1)

plt.ion()
plt.axes().add_collection(LC(walls))
plt.xlim(-10,510)
plt.ylim(-10,410)
path = makepath(*sinsum(guess, tt))
plt.axes().add_collection(LC(path, color='red'))
plt.plot(*start, marker='o')
plt.plot(*goal, marker='o')
plt.show()

optres = fmin(eval_score, guess, **optimsettings)
optcoeff = optres[0]    

#for c in optres[-1][::optimsettings['maxiter']/10]:
for c in array(optres[-1])[logspace(1,log10(optimsettings['maxiter']-1), 10).astype(int)]:
    vx, vy = sinsum(c, tt)
    path = makepath(vx,vy)
    plt.axes().add_collection(LC(path, color='green'))
    plt.show()

करने के लिए: जीयूआई जो आपको दिशा का मोटा अर्थ प्राप्त करने के लिए एक प्रारंभिक मार्ग आकर्षित करने देता है। कुछ भी 14-आयामी अंतरिक्ष से बेतरतीब ढंग से नमूना लेने से बेहतर है


बहुत बढ़िया! ऐसा लगता है कि 17 कदम न्यूनतम है - आप इस अतिरिक्त जानकारी के साथ समाधान खोजने के लिए अपने कार्यक्रम को कैसे बदलेंगे?
वॉनजड

ओह प्रिये: मेरा कार्यक्रम दिखाता है कि आप (३२०,२२०) पर (३२,२४०) पर समाप्त नहीं होते - क्या आप कृपया
जाँचेंगे

1
वूप्स, समाधान अद्यतन, यह भी 24 चरणों के लिए नीचे resamped। हाथ से बारीक ट्यूनिंग तस्वीर को देखकर बहुत आसान है, इसे एक सामान्य मामले के साथ काम करने के लिए स्वचालित करना - इतना नहीं
DenDenDo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.