วิธีเกลียวทอง
คุณบอกว่าคุณไม่สามารถใช้วิธีเกลียวทองได้ผลและนั่นเป็นเรื่องน่าเสียดายเพราะมันดีมากจริงๆ ฉันอยากจะให้คุณเข้าใจอย่างถ่องแท้เพื่อที่คุณจะได้เข้าใจว่าจะทำอย่างไรเพื่อไม่ให้สิ่งนี้ "ถูกมัด"
ต่อไปนี้เป็นวิธีที่รวดเร็วและไม่สุ่มในการสร้างโครงตาข่ายที่ถูกต้องโดยประมาณ ตามที่กล่าวไว้ข้างต้นไม่มีโครงตาข่ายใดที่สมบูรณ์แบบ แต่อาจจะดีพอ เมื่อเทียบกับวิธีอื่น ๆ เช่นที่BendWavy.orgแต่ก็มีรูปลักษณ์ที่สวยงามและสวยงามรวมถึงการรับประกันเกี่ยวกับการเว้นระยะห่างในขีด จำกัด
รองพื้น: ดอกทานตะวันเกลียวบนดิสก์ยูนิต
เพื่อทำความเข้าใจอัลกอริทึมนี้ก่อนอื่นฉันขอเชิญคุณดูอัลกอริทึมเกลียวดอกทานตะวัน 2 มิติ นี่ขึ้นอยู่กับความจริงที่ว่าจำนวนที่ไม่ลงตัวที่สุดคืออัตราส่วนทองคำ(1 + sqrt(5))/2
และถ้าใครปล่อยคะแนนออกมาโดยวิธี“ ยืนอยู่ที่จุดศูนย์กลางให้เปลี่ยนอัตราส่วนทองคำของรอบทั้งหมดจากนั้นปล่อยอีกจุดหนึ่งไปในทิศทางนั้น” หนึ่งสร้างโดยธรรมชาติ เกลียวซึ่งเมื่อคุณไปถึงจุดที่สูงขึ้นและสูงขึ้นอย่างไรก็ตามปฏิเสธที่จะมี 'แท่ง' ที่กำหนดไว้อย่างดีซึ่งจุดเรียงกัน (หมายเหตุ 1. )
อัลกอริทึมสำหรับการเว้นระยะห่างบนดิสก์คือ
from numpy import pi, cos, sin, sqrt, arange
import matplotlib.pyplot as pp
num_pts = 100
indices = arange(0, num_pts, dtype=float) + 0.5
r = sqrt(indices/num_pts)
theta = pi * (1 + 5**0.5) * indices
pp.scatter(r*cos(theta), r*sin(theta))
pp.show()
และให้ผลลัพธ์ที่ดูเหมือน (n = 100 และ n = 1000):
การเว้นจุดในแนวรัศมี
สิ่งสำคัญที่แปลกคือสูตรr = sqrt(indices / num_pts)
; ฉันมาที่นั่นได้อย่างไร (โน้ต 2.)
ฉันใช้สแควร์รูทตรงนี้เพราะฉันต้องการให้สิ่งเหล่านี้มีระยะห่างเท่ากันรอบ ๆ ดิสก์ นั่นก็เหมือนกับการบอกว่าในขีด จำกัด ของNขนาดใหญ่ฉันต้องการพื้นที่เล็กน้อยR ∈ ( r , r + d r ), Θ∈ ( θ , θ + d θ ) เพื่อให้มีจำนวนจุดตามสัดส่วนกับพื้นที่ ซึ่งเป็นR d R d θ ทีนี้ถ้าเราแกล้งทำเป็นว่าเรากำลังพูดถึงตัวแปรสุ่มตรงนี้มันมีการตีความอย่างตรงไปตรงมาว่าบอกว่าความหนาแน่นของความน่าจะเป็นร่วมสำหรับ ( R , Θ ) เป็นเพียงcrสำหรับค่าคงที่ = 1 / πค . Normalization บนดิสก์ยูนิตจะบังคับให้c
ตอนนี้ให้ฉันแนะนำเคล็ดลับ มันมาจากทฤษฎีความน่าจะเป็นที่เรียกว่าการสุ่มตัวอย่าง CDF ผกผันสมมติว่าคุณต้องการสร้างตัวแปรสุ่มที่มีความหนาแน่นของความน่าจะเป็นf ( z ) และคุณมีตัวแปรสุ่มU ~ Uniform (0, 1) เช่นเดียวกับที่ออกมาจากrandom()
ในภาษาโปรแกรมส่วนใหญ่ คุณจะทำอย่างไร?
- ขั้นแรกเปลี่ยนความหนาแน่นของคุณให้เป็นฟังก์ชันการแจกแจงสะสมหรือ CDF ซึ่งเราจะเรียกว่าF ( z ) โปรดจำไว้ว่า CDF จะเพิ่มขึ้นอย่างจำเจจาก 0 เป็น 1 ด้วยอนุพันธ์f ( z )
- จากนั้นคำนวณฟังก์ชันผกผันของ CDF F -1 ( z )
- คุณจะพบว่าZ = F -1 ( U ) กระจายตามความหนาแน่นของเป้าหมาย (หมายเหตุ 3)
ตอนนี้เคล็ดลับเกลียวอัตราส่วนทองคำจะชี้ให้เห็นในรูปแบบที่สวยงามสม่ำเสมอสำหรับθดังนั้นลองรวมมันเข้าด้วยกัน สำหรับดิสก์หน่วยที่เราจะเหลือF ( R ) = R 2 ดังนั้นฟังก์ชันผกผันคือF -1 ( u ) = u 1/2ดังนั้นเราจะสร้างจุดสุ่มบนดิสก์ในพิกัดเชิงขั้วด้วยr = sqrt(random()); theta = 2 * pi * random()
และดังนั้นเราจะสร้างจุดสุ่มบนดิสก์ในพิกัดเชิงขั้วกับ
ตอนนี้แทนการสุ่มเก็บตัวอย่างฟังก์ชันผกผันนี้เรากำลังสม่ำเสมอสุ่มตัวอย่างมันและสิ่งที่ดีเกี่ยวกับการสุ่มตัวอย่างเครื่องแบบคือว่าผลของเราเกี่ยวกับวิธีการจุดกระจายออกไปในวงเงินที่มีขนาดใหญ่Nจะทำงานเป็นถ้าเราได้สุ่มมัน การรวมกันนี้เป็นเคล็ดลับ แทนการrandom()
ที่เราใช้(arange(0, num_pts, dtype=float) + 0.5)/num_pts
เพื่อให้พูดว่าถ้าเราต้องการที่จะลิ้มลอง 10 r = 0.05, 0.15, 0.25, ... 0.95
จุดที่พวกเขามี เราสุ่มตัวอย่างrอย่างสม่ำเสมอเพื่อให้ได้ระยะห่างของพื้นที่เท่ากันและเราใช้การเพิ่มของดอกทานตะวันเพื่อหลีกเลี่ยง "แท่ง" ที่น่ากลัวในเอาต์พุต
ตอนนี้ทำทานตะวันบนทรงกลม
การเปลี่ยนแปลงที่เราต้องทำเพื่อจุดทรงกลมด้วยจุดนั้นเกี่ยวข้องกับการเปลี่ยนพิกัดเชิงขั้วสำหรับพิกัดทรงกลมเท่านั้น แน่นอนว่าพิกัดแนวรัศมีจะไม่เข้าสู่สิ่งนี้เพราะเราอยู่ในหน่วยทรงกลม เพื่อให้สิ่งเล็ก ๆ น้อย ๆ ที่สอดคล้องเพิ่มเติมได้ที่นี่แม้ว่าฉันได้รับการฝึกฝนให้เป็นนักฟิสิกส์ฉันจะใช้พิกัดคณิตศาสตร์ที่ 0 ≤ ไว ≤เธมีเส้นรุ้งลงมาจากเสาและ 0 ≤ θ ≤2πมีเส้นแวง ดังนั้นความแตกต่างจากข้างต้นคือการที่เรามีพื้นแทนที่ตัวแปรRกับφ
องค์ประกอบพื้นที่ของเราซึ่งเป็นr d r d θตอนนี้กลายเป็นบาป ( φ ) d φ d θที่ไม่ซับซ้อนมากขึ้น ดังนั้นความหนาแน่นร่วมของเราสำหรับระยะห่างสม่ำเสมอจึงเป็นบาป ( φ ) / 4π เมื่อรวมออกθเราจะพบf ( φ ) = sin ( φ ) / 2 ดังนั้นF ( φ ) = (1 - cos ( φ )) / 2 เมื่อเปลี่ยนสิ่งนี้เราจะเห็นว่าตัวแปรสุ่มที่เหมือนกันจะมีลักษณะเหมือน acos (1-2 u ) แต่เราสุ่มตัวอย่างแบบสม่ำเสมอแทนที่จะสุ่มดังนั้นเราจึงใช้φ k = acos แทน (1 - 2 ( k+ 0.5) /N ). และส่วนที่เหลือของอัลกอริทึมกำลังฉายสิ่งนี้บนพิกัด x, y และ z:
from numpy import pi, cos, sin, arccos, arange
import mpl_toolkits.mplot3d
import matplotlib.pyplot as pp
num_pts = 1000
indices = arange(0, num_pts, dtype=float) + 0.5
phi = arccos(1 - 2*indices/num_pts)
theta = pi * (1 + 5**0.5) * indices
x, y, z = cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi);
pp.figure().add_subplot(111, projection='3d').scatter(x, y, z);
pp.show()
อีกครั้งสำหรับ n = 100 และ n = 1,000 ผลลัพธ์จะมีลักษณะดังนี้:
การวิจัยต่อไป
ฉันอยากจะพูดถึงบล็อกของ Martin Roberts โปรดทราบว่าด้านบนฉันได้สร้างค่าชดเชยของดัชนีของฉันโดยเพิ่ม 0.5 ในแต่ละดัชนี นี่เป็นเพียงการดึงดูดสายตาสำหรับฉัน แต่ปรากฎว่าการเลือกออฟเซ็ตมีความสำคัญมากและไม่คงที่ตลอดช่วงเวลาและอาจหมายถึงความแม่นยำในการบรรจุที่ดีขึ้นถึง 8% หากเลือกอย่างถูกต้อง นอกจากนี้ยังควรมีวิธีที่จะทำให้ลำดับR 2ของเขาครอบคลุมทรงกลมและมันก็น่าสนใจที่จะดูว่าสิ่งนี้ให้การครอบคลุมที่ดีหรือไม่บางทีก็เป็นไปตามที่เป็นอยู่ แต่บางทีอาจจำเป็นต้องพูดโดยนำมาจากเพียงครึ่งหนึ่งของ สี่เหลี่ยมจัตุรัสของหน่วยตัดตามแนวทแยงมุมหรือมากกว่านั้นและยืดออกไปรอบ ๆ เพื่อให้ได้วงกลม
หมายเหตุ
"แท่ง" เหล่านั้นเกิดจากการประมาณอย่างมีเหตุผลกับจำนวนและการประมาณอย่างมีเหตุผลที่ดีที่สุดสำหรับจำนวนมาจากนิพจน์เศษส่วนต่อเนื่องโดยz + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))
ที่z
เป็นจำนวนเต็มและn_1, n_2, n_3, ...
เป็นลำดับที่ จำกัด หรือไม่สิ้นสุดของจำนวนเต็มบวก:
def continued_fraction(r):
while r != 0:
n = floor(r)
yield n
r = 1/(r - n)
เนื่องจากส่วนที่เป็นเศษส่วน1/(...)
อยู่ระหว่างศูนย์และหนึ่งเสมอจำนวนเต็มขนาดใหญ่ในเศษส่วนต่อเนื่องจึงช่วยให้สามารถหาค่าประมาณที่มีเหตุผลได้ดีโดยเฉพาะ: "หารด้วยค่าระหว่าง 100 ถึง 101" จะดีกว่า "หารด้วยค่าระหว่าง 1 ถึง 2" ดังนั้นจำนวนที่ไม่ลงตัวที่สุดจึงเป็นจำนวนที่มี1 + 1/(1 + 1/(1 + ...))
และไม่มีการประมาณเชิงเหตุผลที่ดีเป็นพิเศษ เราสามารถแก้φ = 1 + 1 / φโดยการคูณด้วยφเพื่อรับสูตรสำหรับอัตราส่วนทองคำ
สำหรับคนที่ไม่คุ้นเคยให้กับ NumPy - ทุกฟังก์ชั่นที่มี“vectorized” เพื่อให้sqrt(array)
เป็นเช่นเดียวกับสิ่งที่ภาษาอื่น ๆ map(sqrt, array)
อาจเขียน ดังนั้นนี่คือsqrt
แอปพลิเคชันทีละองค์ประกอบ เช่นเดียวกันกับการหารด้วยสเกลาร์หรือการบวกด้วยสเกลาร์ซึ่งใช้กับส่วนประกอบทั้งหมดแบบขนาน
การพิสูจน์นั้นง่ายมากเมื่อคุณรู้ว่านี่คือผลลัพธ์ ถ้าคุณถามว่าความน่าจะเป็นที่z < Z < z + d z เป็นเท่าใดนี่ก็เหมือนกับการถามความน่าจะเป็นที่z < F -1 ( U ) < z + d zคืออะไรให้ใช้Fกับทั้งสามนิพจน์โดยสังเกตว่าเป็น ฟังก์ชันที่เพิ่มขึ้นอย่างจำเจดังนั้นF ( z ) < U < F ( z + d z ) ให้ขยายด้านขวามือออกเพื่อค้นหาF ( z ) + f( z ) d zและเนื่องจากUสม่ำเสมอความน่าจะเป็นนี้จึงเป็นเพียงf ( z ) d zตามที่สัญญาไว้