สิ่งที่อยากรู้ก่อนเริ่มพัฒนา Autorouter
(blog.autorouting.com)- ประสบการณ์พัฒนา PCB autorouter แบบโอเพนซอร์ส สำหรับ tscircuit เป็นเวลาราว 1 ปี แสดงให้เห็นว่าการออกแบบที่ลดปัญหาการค้นหา เช่น A*, การทำ visualization, spatial partitioning และ caching คือหัวใจของประสิทธิภาพ
- จุดเน้นของการปรับแต่งประสิทธิภาพไม่ได้อยู่ที่ภาษาโปรแกรมหรือความเร็วต่อหนึ่งรอบการวนซ้ำ แต่อยู่ที่ การลดจำนวนรอบการวนซ้ำ และแม้แต่ JavaScript ก็อาจเร็วกว่า implementation ระดับต่ำได้ หากใช้อัลกอริทึมที่ฉลาดกว่าและ cache ได้
- ในการค้นหาเชิงพื้นที่ Spatial Hash Index อาจเรียบง่ายและเร็วกว่าต้นไม้ทั่วไปอย่าง QuadTree แต่ถ้าเลือกขนาดเซลล์ผิด ก็จะเกิด fixed cost สูงในการ query แต่ละครั้ง
- pipeline ของ autorouter ที่ซับซ้อนจำเป็นต้อง visualize input/output ของแต่ละขั้นตอน และตรวจสอบกระบวนการวนซ้ำด้วย animation ขณะที่ recursive function และวิธีแบบ Monte Carlo เสียเปรียบในด้าน debugging, optimization และ determinism
- A* สามารถยอมลด optimality บางส่วนด้วย Greedy Multiplier ของ Weighted A* เพื่อเพิ่มความเร็วได้มาก และแต่ละขั้นตอนควรลดโอกาสล้มเหลวด้วยการสร้างสถานะที่ขั้นตอนถัดไปแก้ได้ง่ายขึ้น
ใช้ A* เป็นเครื่องมือค้นหาหลัก
- A* ไม่ใช่อัลกอริทึมสำหรับกริด 2D เท่านั้น แต่เป็นอัลกอริทึมพื้นฐานที่ใช้ได้กับ informed search หลายรูปแบบ
- BFS จะสำรวจ node ข้างเคียงทั้งหมด แต่ A* จะให้ความสำคัญกับ node ที่อยู่ใกล้เป้าหมายมากกว่า
- เพราะใช้ตัวชี้วัดระยะทางจากภายนอกกราฟ จึงจัดเป็น informed search
- อัลกอริทึมแบบ recursive มักใกล้เคียงกับ depth-first search (DFS) ส่วน loop ที่ค้นหาโดยไม่จัดเรียง candidate หรือ neighbor มักใกล้เคียงกับ BFS
- การเปลี่ยนโค้ดเดิมที่มีรูปแบบ BFS หรือ DFS ให้เป็น A* มักทำให้ประสิทธิภาพดีขึ้นอย่างมาก
- ใน autorouter มีการใช้ A* หลายระดับเพื่อหา hyperparameter ที่เหมาะกับปัญหา
- รันการตั้งค่า autorouter แต่ละแบบเป็น candidate
- จัดสรรรอบการวนซ้ำให้มากขึ้นกับการตั้งค่าที่เริ่ม route สำเร็จด้วย cost ที่ดี
- เป็นรูปแบบ meta-A* ที่ใช้ทั้ง distance cost และ iteration cost เป็น penalty
อัลกอริทึมสำคัญกว่าภาษา
- tscircuit autorouter เขียนด้วย JavaScript และในการถกเถียงเรื่องประสิทธิภาพ ภาษามักถูกชี้เป็นประเด็นแรก
- การปรับแต่งอัลกอริทึมแบ่งได้เป็นสองแกนใหญ่
- ทำให้อัลกอริทึมฉลาดขึ้นโดยลด จำนวนรอบการวนซ้ำ ที่จำเป็น
- เพิ่มความเร็วในการทำงานของแต่ละรอบการวนซ้ำ
- หากหมกมุ่นกับการเพิ่มความเร็วของหนึ่งรอบการวนซ้ำมากเกินไป อาจเป็นเพียงการรันแนวทางที่ผิดให้เร็วขึ้นเท่านั้น
- ตัวอย่างเช่น วิธีแปลงทุกอย่างเป็นกริดเพื่อตรวจการซ้อนทับ อาจช้าลงได้ไม่ว่าจะใช้ภาษาใด
- อัลกอริทึมที่ฉลาดใน JavaScript อาจเร็วกว่าอัลกอริทึมแบบง่ายที่ optimize ด้วย assembly ระดับต่ำ
- ควรใช้เวลา 95% ของการพัฒนาไปกับการลดจำนวนรอบการวนซ้ำ และภาษาที่ช่วยให้ไปถึงอัลกอริทึมที่ฉลาดที่สุดและ cache ได้เร็วที่สุดคือทางเลือกที่ดี
Spatial Hash Index อาจดีกว่าต้นไม้
- ในการ optimize พื้นที่หลายมิติ QuadTree มักถูกหยิบยกขึ้นมา แต่โครงสร้างข้อมูลแบบต้นไม้ทั่วไปอาจช้าได้
- QuadTree เป็นที่รู้จักในฐานะโครงสร้างข้อมูลที่ลดการค้นหา object ใกล้เคียงในพื้นที่ 2D/3D จาก
O(N)เป็นO(log(N))แต่ต้นไม้ไม่ใช่ representation แบบ informed ของข้อมูล - Spatial Hash Index ไม่ได้ hash ตัว object เอง แต่ hash ตำแหน่งของ object แล้วเก็บไว้ใน cell หรือ bucket ของสิ่งที่อยู่ใกล้กัน
- แนวทางนี้คือการนำการเข้าถึงแบบ hash ที่รวดเร็วเหมือน HashSet, HashMap มาใช้กับข้อมูลเชิงพื้นที่
- เหตุผลที่ spatial hash ไม่แพร่หลายเท่าคือจำเป็นต้องเลือก ขนาดเซลล์ ที่เหมาะสม
- หากปรับขนาดเซลล์ผิด จะเกิด fixed cost สูงในการ query แต่ละครั้ง
- ในทางปฏิบัติ ผู้เขียนมองว่าการเลือกขนาดเซลล์ที่สมเหตุสมผลไม่ได้ยากขนาดนั้น
Spatial partitioning และ caching เปลี่ยนประสิทธิภาพได้
- แผงวงจรอย่างภายใน iPhone อาจมี trace ประมาณ 10,000–20,000 เส้น และแม้ใช้เครื่องมือ EDA ระดับสูงสุด ทีมก็อาจใช้เวลาหลายเดือนในการ route
- แนวคิดง่ายๆ ที่สำคัญในปัญหา autorouting คือ สิ่งที่ถูก route แล้วนั้นเคยถูก route มาก่อน
- นักพัฒนาเกม bake navigation mesh ไว้ล่วงหน้า ส่วน LLM บีบอัดอินเทอร์เน็ตเป็น weights เพื่อการค้นหา
- autorouter รุ่นถัดไปสามารถแบ่งปัญหาเชิงพื้นที่ และใช้ cache ขนาดใหญ่ที่บรรจุคำตอบที่แก้ไว้แล้ว
- หาก 99% ของปัญหา autorouting ถูกแก้ไว้ล่วงหน้าใน cache ความเร็วของอัลกอริทึมเองก็สำคัญน้อยลง
- ปัจจุบันอัลกอริทึมจำนวนมากยังไม่ได้ให้ความสำคัญกับ cache reusability และ spatial partitioning มากพอ
- ต้นทุน storage และ caching ดูเหมือนจะลดลงเร็วกว่าการเพิ่มความเร็วในการคำนวณ และผู้เขียนมองว่าการใช้ cache 1GB เพื่อทำให้ autorouter เร็วขึ้น 50% ไม่ใช่ปัญหาใหญ่
มองปัญหาโดยตรงด้วย visualization และ profiling
- หลักการสำคัญคือ หากไม่มี visualization ของปัญหา ก็จะแก้ปัญหาไม่ได้
- การดูแต่ตัวเลขทำให้ debugging ยาก และหากสร้าง visualization ให้กับ subproblem เล็กๆ แต่ละส่วน ก็จะเข้าใจปัญหาได้เร็วขึ้นมาก
- ในการพัฒนา autorouter หลายครั้งเริ่มแก้ปัญหาจาก visualization ก่อน
- มีการ visualize อัลกอริทึมย่อยที่หาเส้นทาง 45 องศาด้วย ซึ่งใช้ใน Path Simplification Phase ที่เกือบเป็นขั้นตอนสุดท้ายของ autorouter
- เครื่องมือ profiling ของ JavaScript แสดงเวลารวมที่ใช้ในแต่ละบรรทัดของโค้ดเป็นหน่วยมิลลิวินาที
- เพียงรัน JavaScript ในเบราว์เซอร์แล้วเปิดแท็บ Performance
- มี flame chart และฟีเจอร์ดูการใช้หน่วยความจำด้วย
- วิดีโอสั้นที่เกี่ยวข้อง: youtube short
หลีกเลี่ยง recursion และ Monte Carlo
- ในโค้ดที่เน้นประสิทธิภาพ ควรหลีกเลี่ยง recursive function
- แทบจะทำงานแบบ synchronous เสมอ จึงตัดกลางคันเพื่อทำ animation ได้ยาก
- โดยธรรมชาติแล้วเป็น DFS และแปลงเป็น A* ได้ยาก
- ติดตามจำนวนรอบการวนซ้ำได้ไม่ง่าย
- ใน recursive function ความเป็น mutable ดูไม่เป็นธรรมชาติ แต่สำหรับประสิทธิภาพ ความเป็น mutable อาจสำคัญ
- implementation แบบ iterative สามารถเก็บ set
visitedNodesและตรวจ node ก่อนค้นหาได้ จึงอาจเร็วกว่า - อัลกอริทึม Monte Carlo เข้าใกล้คำตอบด้วย randomness แต่ผู้เขียนมองว่าเพราะไม่ deterministic จึง debug ยาก และแทบไม่ค่อยเหมาะที่สุดเมื่อเทียบกับ heuristic
- เมื่อรู้ว่าจะประเมิน candidate อย่างไร แต่ไม่รู้วิธีไปถึงคำตอบ วิธี Monte Carlo อาจช่วยให้ได้ intuition
- หากมีสิ่งที่ใกล้เคียงกับ cost function แล้ว ควรใช้วิธีที่ดีกว่าเทคนิคสุ่มอย่าง Monte Carlo หรือ Simulated Annealing
- หากอ่อนไหวต่อ local minimum อาจพิจารณา hyperparameter หรือ cost function ที่ซับซ้อนขึ้น
- เช่นเดียวกับที่นักออกแบบ PCB ไม่ลากเส้นสุ่มบนแผงวงจร ผู้เขียนมองว่าในโดเมนนี้สามารถหา heuristic ที่ดีกว่าได้
ให้อัลกอริทึมระหว่างทางอยู่ในระบบพิกัดเดียวกัน
- ปัจจุบัน autorouter เป็น pipeline ที่ประกอบด้วย 13 ขั้นตอนและอัลกอริทึมย่อยประมาณ 20 ตัว
- มีการวัดจำนวนรอบการวนซ้ำในงานต่างๆ เช่น การตัดสินใจ spatial partitioning หรือการทำ path simplification ที่ขอบเขตของพื้นที่ซึ่งถูก autoroute อย่างอิสระ
- หาก visualize input และ output ของแต่ละขั้นตอนซ้อนกัน จะเข้าใจบริบทของปัญหาที่กำลังแก้อยู่ได้
- ปัญหาใน downstream stage โดยเฉพาะขั้นตอน high density routing มักแก้ได้ด้วยการปรับปรุง output ของขั้นตอนก่อนหน้า
- เมื่อสร้างอัลกอริทึมย่อย มักมีแรงจูงใจให้แยกปัญหาออกมาในรูปแบบที่ง่ายที่สุด และ normalize พิกัดให้อยู่รอบ
(0, 0) - normalization หรือการแปลงที่ซับซ้อนอาจทำให้มองเห็นผลกระทบของผลลัพธ์จากขั้นตอนต้นต่อขั้นตอนถัดไปได้ยากขึ้นอย่างรวดเร็ว
- การคง coordinate space ให้สอดคล้องกันตลอด lifecycle ของอัลกอริทึมเป็นแนวทางที่ได้เปรียบ
- การดูแต่ละขั้นตอนตามลำดับและ zoom เข้าไปช่วยหาขั้นตอนที่เป็นสาเหตุของ Design Rule Check ที่ล้มเหลวได้
Animation ของการวนซ้ำและการหลีกเลี่ยงกริด
- เพราะการลดจำนวนรอบการวนซ้ำเป็นเรื่องสำคัญ การดูรอบการวนซ้ำของอัลกอริทึมเป็น animation จะช่วยให้เห็นการค้นหาที่สูญเปล่าได้โดยสัญชาตญาณ
- Animation มีประโยชน์เป็นพิเศษเมื่อปรับ Greedy Multiplier
- เคสที่ trace ง่ายๆ เส้นหนึ่งควรล้มเหลว แต่กลับไม่ล้มเหลวทันทีและพยายามแก้ต่อไปด้านนอกอย่างไม่รู้จบ เป็นสิ่งที่จับได้ยากหากไม่มี animation
- วิธีตัดสินว่า trace A และ B ซ้อนทับกันหรือไม่ แบ่งได้กว้างๆ เป็นสองแบบ
- ดูแต่ละ segment ของ A และ B แล้วตรวจว่าตัดกันหรือไม่
- ทำเครื่องหมายกริดที่ B อยู่ แล้วตรวจว่ากริดที่ A ผ่านมี B อยู่หรือไม่
- วิธีแบบกริดอาจช้าลงได้ง่ายถึง 1000 เท่า
- หากใช้ vector math ที่เร็ว การคำนวณ dot product เพื่อดูว่า segment สองเส้นตัดกันหรือไม่ อาจเร็วกว่าการเข้าถึงหน่วยความจำเพื่อตรวจ cell กริดเพียงช่องเดียว
- หากพูดอย่างเคร่งครัด ควรใช้การคำนวณระยะห่างระหว่าง segment เพื่อรับประกัน clearance ที่เหมาะสม ซึ่งซับซ้อนกว่าการตรวจการตัดกันเล็กน้อย แต่ไม่ได้ต่างกันมาก
โอกาสล้มเหลวและ Weighted A*
- ในขั้นตอน spatial partitioning สามารถวัดโอกาสที่แต่ละขั้นตอนจะแก้ไม่สำเร็จเป็น leading indicator ได้
- Unravel Autorouter ติดตามโอกาสล้มเหลวของ Capacity Node แต่ละตัวใน pipeline stage หลักๆ
- แต่ละขั้นตอนมุ่งลดโอกาสล้มเหลวผ่านการจัดโครงสร้าง node ข้างเคียงใหม่หรือการ reroute
- โอกาสล้มเหลวสามารถวัดได้จริง และเมื่ออัลกอริทึมเปลี่ยน การคาดการณ์ก็ปรับปรุงได้ด้วย
- แต่ละขั้นตอนสามารถทำงานไปในทิศทางที่ลดความเป็นไปได้ที่ขั้นตอนถัดไปจะล้มเหลว
- การให้ความสำคัญกับ solvability ก่อนย่อมดีกว่าการใส่ constraint จำนวนมากเกินไปพร้อมกัน
- เมื่อ board ถูกแก้ได้แล้ว การจัดการคำตอบเดิมมักง่ายกว่าการสร้างคำตอบที่ optimal ตั้งแต่แรก
ประนีประนอมความเร็วกับ optimality ด้วย Greedy Multiplier
- A* พื้นฐานรับประกันคำตอบที่ optimal แต่หากให้ความสำคัญกับความเร็วมากกว่า ก็สามารถปรับ
f(n)เล็กน้อยเพื่อใช้ Weighted A* ได้ - A* ปกติ:
f(n) = g(n) + h(n) - Weighted A*:
f(n) = g(n) + w * h(n) - Weighted A* แก้ปัญหาแบบ greedy มากขึ้น และโดยทั่วไปทำงานได้เร็วกว่ามาก
- วิธีนี้ทำหน้าที่เป็น Greedy Multiplier ที่เพิ่มประสิทธิภาพของ A* ได้มาก แลกกับการยอมลด optimality บางส่วน
- ดู Weighted A* และ variant อื่นๆ ของ A* เพิ่มเติมได้ที่ weighted A* and other A* variants here
- นักพัฒนาเกมจัดการปัญหาหลายอย่างที่คล้ายกับนักพัฒนา autorouting ดังนั้นเมื่อค้นหางานวิจัยที่เกี่ยวข้อง อาจลองดู paper ด้าน game development ได้
autorouter ที่กำลังจะเปิดเผย
- autorouter สำหรับ tscircuit ใกล้ถึงการ release แล้ว
- ผลงานจะเผยแพร่เป็น โอเพนซอร์ส ภายใต้ MIT license
- ผู้เขียนมองว่าการแก้ปัญหา autorouting จะเปิดทางให้เกิดนวัตกรรมในโลกกายภาพอย่างมาก และเป็นชิ้นส่วนสำคัญที่ทำให้เกิด “vibe-building” สำหรับอุปกรณ์อิเล็กทรอนิกส์ได้
- บัญชีที่เกี่ยวข้อง: follow me on twitter.
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
โดยรวมแล้วผมไม่ค่อยเชื่อใจ autorouter และเครื่องมือ AI ที่เข้ามาในวงการนี้ก็เช่นกัน แต่ก็ปฏิเสธได้ยากว่ามีโอกาสใหญ่ในการสร้างบางส่วนของเลย์เอาต์ใน eCAD ได้อย่างรวดเร็ว
ผมน่าจะใช้ เครื่องมือแบบร่วมสร้าง มากกว่าเครื่องมืออัตโนมัติเต็มรูปแบบ เพราะในช่วงต้นของการออกแบบ ตำแหน่งวางชิ้นส่วนมักยังไม่แน่นอน และการจัดวางมีผลต่อการเดินลายวงจรมาก ผมไม่เห็นในหน้าเว็บว่าการจัดวางถูกนำไปรวมในอัลกอริทึมหรือไม่ ตอนนี้ก็ใช้เครื่องมืออย่าง push-and-shove หรือบางครั้งก็ใช้ autocomplete อยู่แล้ว
ตลาดนี้เล็ก เครื่องมือก็แตกกระจาย ผู้เล่นเดิมเป็นบริษัทยักษ์ใหญ่ที่เชื่องช้า และผู้ใช้ก็เป็นกลุ่มแฟนพันธุ์แท้ที่เรื่องมาก ผมคงปล่อย KiCad ไปไม่ได้จริง ๆ ไม่ได้มีความเห็นมากนักกับเรื่องที่ autorouter เขียนด้วย JavaScript แต่สงสัยว่ามีแผนจะไปเชื่อมกับผู้ขาย CAD หรือระบบนิเวศเครื่องมือโอเพนซอร์สหรือไม่ หรือกำลังพยายามดึงคนไปสู่อีกระบบนิเวศใหม่อีกชุดหนึ่ง
ถ้าเป็นมิตรกับแคช ความเร็วในการย้ายชิ้นส่วนและลองเลย์เอาต์แบบต่าง ๆ จะเร็วขึ้นมาก ตอนนี้ JavaScript มีแม้กระทั่ง runtime ขนาดเล็กอย่าง QuickJS หรือ Proffor แล้ว จึงค่อนข้างพอร์ตได้ดี และน่าจะรันในเครื่องพร้อมสร้างแคชขนาดใหญ่เองได้
ใน EDA เรื่อง lock-in และการแตกกระจายของระบบนิเวศเป็นสิ่งที่ทุกคนควรกังวล แต่ tscircuit กับ autorouter ตัวนี้เป็นเทคโนโลยีภายใต้ สัญญาอนุญาตแบบ MIT ที่เปิดกว้าง จึงสามารถทำให้ทำงานร่วมกับทุกฝ่ายได้ ซึ่งพบไม่บ่อยในวงการ EDA
หลังจากกำหนด footprint, การจัดวาง, ข้อจำกัด และตรึง net ที่เดินลายเองไว้แล้ว ก็สามารถวนทำซ้ำได้เร็วมาก
หลังจาก Cadence ซื้อ SPECCTRA ในยุค 90 PCB autorouter ก็ค่อนข้างหยุดนิ่งมานาน จึงน่ายินดีที่มีคนกลับมาจับเรื่องนี้อีกครั้ง เท่าที่จำได้ คนที่สร้าง SPECCTRA ย้ายไปทาง VLSI แล้วไม่กลับมาอีก ชื่อเสียงและเงินน่าจะอยู่ตรงนั้น นี่อาจเคยเป็นทุ่งกับระเบิดด้านสิทธิบัตรอยู่พักหนึ่ง และตอนนี้ก็อาจยังเป็นอยู่
การจัดวางอัตโนมัติเป็นปัญหาที่รับมือได้ยากมากตั้งแต่ตอนนั้น และตอนนี้ก็ดูยังเป็นเช่นนั้น แต่แนวทาง generative AI อาจเข้ากันได้ดี การจัดวางชิ้นส่วนรอบแรกที่ดีโดยใช้ generative AI อาจช่วยลดเวลารวมได้ ปัญหาใหญ่ที่สุดคือการโน้มน้าวคนหัวแข็งว่าถึงจะไม่สมบูรณ์แบบ ก็อาจดีพอได้
ความพยายามทำ schematic as code ทำให้ผมค่อนข้างสงสัย ถ้าใช้เป็นรูปแบบ backend แล้วได้ผลก็คงดี และโดยเฉพาะความก้าวหน้าแบบฝั่ง jitx ที่เข้ารหัสกฎการออกแบบระดับ app note และ datasheet ลงในโมเดลชิ้นส่วนนั้นดูดี การอ่าน datasheet ทั้งหมดให้ถึงระดับที่จำเป็นสำหรับงานออกแบบเชิงพาณิชย์เป็นงานมากกว่าที่คิดมาก และการให้วิศวกรจูเนียร์เรียนรู้กระบวนการนั้นก็เช่นกัน ดังนั้นการทำอัตโนมัติจึงมีประโยชน์
แต่แนวทางเหล่านี้ดูเหมือนหยั่งรากอยู่กับความคิดที่มอง schematic เป็นข้อมูลป้อนเข้าเลย์เอาต์ เป็นเสมือน source code อย่างหนึ่ง ทั้งที่ schematic ยังเป็นเอกสารออกแบบที่มีภาษาภาพซึ่งวิวัฒน์มาอย่างพิถีพิถัน และควรเข้าถึงได้แม้กับคนที่ไม่ได้ติดตั้งชุดผลิตภัณฑ์ EDA คนที่เรียนรู้จากการถอดความ schematic แบบสไตล์ Adafruit/Sparkfun/Shenzhen ที่ลดการเดินสายแบบชัดเจนให้น้อยที่สุด อาจไม่ค่อยเข้าใจคุณค่าของ schematic ที่ดี
อีกเรื่องคือมีแนวโน้มที่จะพึ่งพาการเปรียบเทียบมากเกินไป จนพยายามทำให้งานออกแบบระดับ PCB กลายเป็นเหมือนงานออกแบบ VLSI ผมไม่ได้มองว่าเป็นไปไม่ได้โดยสิ้นเชิง ถ้า DRC และเครื่องมือตรวจสอบดีขึ้น งานออกแบบระดับชิ้นส่วนก็อาจเข้าใกล้ VLSI มากขึ้นได้ แต่ความเชื่อมโยงระหว่างการออกแบบ, EDA/CAM/การจำลอง, การตรวจสอบ, ผู้ผลิต, ผู้ประกอบ, ผู้ขายชิ้นส่วน และหน่วยงานกำกับดูแล·รับรองนั้นหลวมเกินไป แค่ทำมุมใดมุมหนึ่งในนี้ให้ดีได้ก็ถือเป็นผลงานใหญ่แล้ว
ทุกวันนี้แนวทางคือทำ งานออกแบบ UHF แบบควบคุมอิมพีแดนซ์ ร่วมกับเครื่องมือจำลองเฉพาะโดเมน ดังนั้นจึงเดินลายสำคัญด้วยมือก่อน สร้าง island pour แล้วค่อยจัดการการเชื่อมต่อไฟเป็นขั้นสุดท้าย
เลย์เอาต์ของ KiCad ดีกว่าไม่มีอยู่บ้าง แต่การพยายามทำให้มันกลายเป็นเครื่องมือจำลองแบบครึ่ง ๆ กลาง ๆ อีกตัวดูน่าขำ
นั่นคือการรองรับฐานข้อมูลและฟีเจอร์ outjob ที่เหลือเป็นเรื่องของการนำไปใช้และผู้ใช้จะใช้ฟีเจอร์เหล่านี้อย่างไรเสียมากกว่า และฐานข้อมูลก็มักมาพร้อมระบบราชการภายในองค์กรเกี่ยวกับการจัดระเบียบข้อมูลมากขึ้น
ในมุม workflow ที่ทำให้การวางเลย์เอาต์เร็วขึ้น ผมคิดว่า KiCad เองก็กำลังไปทางนั้นอยู่พอสมควรแล้ว เช่นมีฟีเจอร์ “trace autocomplete” ที่น่าจะเข้ามาราวเวอร์ชัน 7.0 ใน pcbnew น่าจะเป็นคีย์ลัด F ซึ่งจะวาง trace ของ track ที่กำลังวางอยู่ให้ เมื่อใช้คู่กับคีย์ลัด E สำหรับ “เดินลายจากอีกด้านของ track” จะช่วยเพิ่ม productivity ได้มากเวลาทำงานระหว่าง ballout grid สองแบบที่ต่างกัน
ในเวอร์ชัน 9 สามารถลาก bus หรือหลาย track ได้แล้ว ทำให้ flow นี้เร็วขึ้นอีก
พูดตรง ๆ ถ้าสามารถไปถึงการจัดวางที่น่าพอใจ และให้ข้อจำกัดตำแหน่งการเดินลายกับ autorouter ได้ ผมคิดว่าส่วนใหญ่ของงานออกแบบสามารถปล่อยให้ autorouter จัดการได้ ตัวอย่างเช่นปีที่แล้วผมทำบอร์ดที่ใช้ NXP iMX8MP กับ eMMC โดย ballout รอบโปรเซสเซอร์เข้ากับ ballout ของ eMMC ได้ดีมาก แค่วางชิปให้ตรงกันแล้วลากเส้นก็พอ ถ้า autorouter รู้แค่ว่าต้องคง data bus ไว้ที่เลเยอร์บนสุด มันคงทำงานที่ใช้เวลา 10 นาทีให้เสร็จในไม่กี่วินาที
โปรเจกต์ autorouter มักมีปัญหาเรื่องเกณฑ์ความสำเร็จ ดูเหมือนว่าต้องจัดการ ทุกอย่าง บนบอร์ดได้ถึงจะถือว่า “เสร็จ” แต่ในฐานะวิศวกรไฟฟ้าที่ทำงานจริง ผมไม่ได้ต้องการแบบนั้น ผมต้องการ autorouter ที่ช่วยจัดการงานออกแบบเป็นก้อนเล็ก ๆ ทีละส่วน ให้เวลาตรวจทาน แล้วค่อยไปก้อนถัดไป
ถ้ากำหนดข้อจำกัดข้ามเลเยอร์ได้ด้วยก็จะทรงพลังมาก เช่น “ให้ net ทุกเส้นที่ชื่อ D0-7 อยู่บนเลเยอร์ 1 และ 3 ปรับความยาวให้ต่างกันไม่เกิน 5mm และใช้ D0 เป็นความยาวอ้างอิง” อะไรแบบนี้ ถ้าทำได้ก็เท่ากับแก้ปัญหา DRAM length tuning แล้ว และทำให้งานออกแบบที่มีความซับซ้อนกว้างขึ้นมากเป็นไปได้สำหรับผู้ใช้ทั่วไปด้วย
ถ้ามีเวลา ผมอยากทำเดโมให้ดูว่าหมายถึงอะไร
การตัด วิธีมอนติคาร์โล ทิ้งเร็วเกินไปในข้อ 8 ถือเป็นความผิดพลาดครั้งใหญ่
แก่นของมอนติคาร์โลคือสามารถแลกความแม่นยำกับความเร็วได้ ยิ่งปล่อยให้อัลกอริทึมรันนานเท่าไร ก็ยิ่งแม่นยำขึ้นเท่านั้น
สิ่งที่น่าสนใจกว่านั้นคือมักใช้ในทางกลับกันได้ด้วย คือได้ผลลัพธ์ที่ไม่แม่นยำมากอย่างรวดเร็วมาก แทนที่จะสำรวจทุกเส้นทาง ก็สำรวจแค่เส้นทางเดียวที่สุ่มเลือกมา
วิธีนี้จะโดดเด่นเมื่อใส่ไว้ในลูปซ้อนชั้นในสุดของอัลกอริทึม ตัวอย่างเช่น ถ้าจะฝึกโครงข่ายประสาทให้เรียนรู้การเดินสายอัตโนมัติ ลูปด้านนอกจะอัปเดตพารามิเตอร์ของโครงข่ายประสาท ส่วนลูปด้านในจะคำนวณเส้นทางผ่านกราฟ
เมื่อใช้มอนติคาร์โล หากไม่มี bias ก็สามารถลดลูปด้านในที่ควบคุมความแม่นยำนี้ให้เหลือการวนซ้ำ 1 ครั้งได้ ความแปรปรวนจะเพิ่มขึ้นทำให้ลูปด้านนอกช้าลง แต่แมชชีนเลิร์นนิงก็ “ในทางทฤษฎี” ยังเรียนรู้ได้
ดังนั้นจึงสามารถสร้างนโยบายที่เลือกการตัดสินใจที่ถูกต้องโดยสัญชาตญาณได้ เหมือนในหมากรุกหรือโกะ ในการดัดแปลง Monte Carlo Tree Search เช่น AlphaGo Zero, AlphaChess Zero, AlphaRouter Zero แม้ไม่มีส่วนค้นหา แคชขนาดมหึมาที่เข้ารหัสอยู่ในพารามิเตอร์ของโครงข่ายประสาท หลังฝึกเสร็จแล้วก็สามารถคำนวณเส้นทางที่คาดว่าดีที่สุดได้ด้วยการส่งผ่านโครงข่ายประสาทหนึ่งครั้ง หรือก็คือเวลาแบบคงที่ ค่าคงที่นี้สามารถแลกหน่วยความจำกับความเร็วได้ง่าย ๆ ด้วยการเพิ่มพารามิเตอร์หรือฝึกให้นานขึ้น
MC เป็นอัลกอริทึมที่ช่วยให้จับความสมจริงได้ แม้จะช้า แต่แทบจะเสมอไปที่ implementation จะง่ายมาก และเชื่อถือได้ในการตรวจยืนยันซ้ำด้วยความมั่นใจสูงมากว่าไม่ได้หลุดไปคนละทิศคนละทางโดยสิ้นเชิง
เป็นการถกเถียงที่ยอดเยี่ยมเกี่ยวกับการเดินสายอัตโนมัติ แต่พอจบด้วยประโยคว่า “ชิ้นส่วนสำคัญที่ทำให้เกิด vibe-building ของอุปกรณ์อิเล็กทรอนิกส์ได้” ก็รู้สึกเจ็บนิด ๆ
ตัวการเดินสายเองนั้นง่าย ความซับซ้อนเกิดขึ้นทันทีที่ต้องรื้อสิ่งที่วางไว้แล้วออกเพื่อใส่สายใหม่ และ combinatorial explosion ก็ถาโถมเข้ามา
คิดถึง autorouter ที่เคยมีใน KiCad มันถูกถอดออกด้วยเหตุผลด้านทรัพย์สินทางปัญญาที่คลุมเครือ เพราะผู้เขียนเคยทำงานในบริษัททำ autorouter มาก่อน สำหรับผู้ใช้ที่ขอให้ใส่กลับมา ก็มีคำตอบทำนองว่า “ลูกผู้ชายตัวจริงไม่ใช้ autorouter”
https://forum.kicad.info/t/autorouting-and-autoplacement/185...
หวังว่า autorouter ตัวนี้และเครื่องมืออื่น ๆ ที่จะตามมา จะช่วยให้ผู้คนปล่อย ผลิตภัณฑ์อิเล็กทรอนิกส์ชิ้นแรก ได้โดยไม่ต้องมีแผนที่มากมายหรือการศึกษาแบบเป็นทางการ
แน่นอนว่า autorouter ที่ดีควรมีประโยชน์ต่อผู้เชี่ยวชาญด้วย จึงหวังว่าจะช่วยในส่วนนั้นเช่นกัน
แต่ในฐานะคนรุ่นเก่าจู้จี้คนหนึ่งที่ไม่ค่อยอยากเห็น KiCad ทุ่มแรงไปกับ autorouter มากนัก autorouter สำหรับ PCB มักเป็นเรื่องปวดหัวและทำงานได้ไม่ดี
เหตุผลว่าทำไมเป็นเช่นนั้นดูได้จาก autorouter ของ VLSI autorouter ของ VLSI ก็เคยเป็นเรื่องปวดหัวและทำงานได้ไม่ดีเช่นกัน ต่อมา VLSI มีเลเยอร์จำนวนมากขึ้นมาก และสามารถจัดสรรเลเยอร์สำหรับการเดินสายแนวตั้ง เลเยอร์สำหรับการเดินสายแนวนอน และเลเยอร์สำหรับไฟเลี้ยงแยกกันได้ แล้วยังมีเลเยอร์เพิ่มเติมอีกหลายชั้นสำหรับการเชื่อมต่อแนวตั้งทั่วทั้งชิป การเชื่อมต่อแนวนอนทั่วทั้งชิป และไฟเลี้ยงทั่วทั้งชิป
ปัญหาพื้นฐานของการเดินสายอัตโนมัติบน PCB คือ PCB มี สิ่งกีดขวาง มากกว่าชิป VLSI มาก ประการแรก ตัวชิ้นส่วนเองเป็นทั้งสิ่งกีดขวางและคอขวด ประการที่สอง via บน PCB แทบจะเสมอไปที่บล็อกทุกเลเยอร์ของบอร์ด แต่ via ของ VLSI บล็อกเฉพาะสองเลเยอร์ที่เชื่อมต่อกัน ประการที่สาม via บน PCB โดยทั่วไปใหญ่กว่าความกว้างของโลหะเดินสาย ประการที่สี่ จำนวนเลเยอร์ที่ใช้ใน PCB น้อยกว่า VLSI มาก แบบที่พบบ่อยคือ 4 เลเยอร์ และในนั้นมีเพียง 2 เลเยอร์เท่านั้นที่ใช้เดินสายทั่วไปได้จริง อีกทั้งด้วยเหตุผลด้านต้นทุน แบบ 2 เลเยอร์ก็มีจำนวนมากและยิ่งเดินสายอัตโนมัติได้ยากกว่า ส่วน 6 เลเยอร์มีเพียงส่วนน้อยมาก
ผลลัพธ์คือการเดินสายอัตโนมัติบน PCB เป็นงานที่ซับซ้อนกว่าการเดินสายอัตโนมัติบน VLSI มาก
จุดที่บทความให้ความสำคัญกับ การทำ Visualization และผลของแคชเป็นพิเศษนั้นดี
แต่มีบางจุดที่ติดใจอยู่บ้าง คำกล่าวที่ว่า “อัลกอริทึมแบบเรียกซ้ำคือการค้นหาแบบลึกก่อน และลูปที่ค้นหาโดยไม่เรียงลำดับตัวเลือกหรือโหนดเพื่อนบ้านคือการค้นหาแบบกว้างก่อน” ดูจะผิดหรือพลาดสัญชาตญาณสำคัญไป ทั้ง DFS และ BFS เขียนได้ทั้งด้วยลูปหรือรีเคอร์ชัน ความต่างจริง ๆ คือหยิบตัวเลือกถัดไปจากด้านบนหรือด้านล่างของสแตก กล่าวคือใช้สแตก (FILO) หรือคิว (FIFO) ต่างหาก
คำกล่าวที่ว่า A* เป็นฐานที่ดีที่สุดของการค้นหาแบบอิงข้อมูลทุกแบบก็ต้องมีบริบทด้วย มันมีประโยชน์กับการค้นหาเส้นทางเมื่อมีแนวคิดเรื่อง “ระยะทาง” ไปยังเป้าหมายที่คำนวณได้ง่าย และรันคิวรีบนกราฟเดียวกันเพียงไม่กี่ครั้ง หากวางแผนจะรันคิวรีจำนวนมากบนกราฟที่แทบคงที่อย่างเครือข่ายถนน อัลกอริทึมพรีโพรเซสอย่าง contraction hierarchy อาจดีกว่า หากเป็นการปรับให้เหมาะที่สุดแต่ไม่มีเป้าหมายตายตัว เช่น ปัญหาพนักงานขายเดินทาง ฮิวริสติกการค้นหาเฉพาะที่แบบอื่นอย่าง 2-opt อาจดีกว่า
“BFS สำรวจโหนดที่อยู่ติดกันทั้งหมด ส่วน A* ให้ความสำคัญกับโหนดที่ใกล้ปลายทางก่อน” นั้นเป็นความต่างอย่างหนึ่งก็จริง แต่ความต่างที่ใหญ่กว่าคือ A* เป็น อัลกอริทึมแบบไดนามิก จึงสามารถมั่นใจได้ว่าเจอเส้นทางสั้นที่สุดแล้วและจบก่อนเวลาได้ BFS อาจยังมั่นใจไม่ได้จนกว่าจะสำรวจกราฟทั้งหมด และกราฟอาจมีขนาดมหาศาล
ในภาษาส่วนใหญ่ การเขียนแบบนั้นง่ายกว่าการนึกถึงสแตกภายนอก ดังนั้นเมื่อเห็นรีเคอร์ชันในโค้ดจริง ก็มีโอกาสสูงที่จะใกล้เคียงกับ DFS มากกว่า แต่ไม่ใช่กฎตายตัว
BFS ใช้คิว FIFO, DFS ใช้สแตก LIFO, ส่วน A* มักใช้ priority queue ที่มักอิมพลีเมนต์ด้วยฮีป
นี่เป็นหนึ่งใน invariant พื้นฐานที่ทำให้ BFS ให้ผลลัพธ์ถูกต้อง ดังนั้นเมื่อไปถึงเป้าหมายทั้งหมดแล้วก็จบก่อนเวลาได้
ความต่างระหว่าง A* กับ BFS คือ BFS ไม่ได้หาเส้นทางสั้นที่สุดระหว่างสองจุด แต่หา เส้นทางสั้นที่สุดจากจุดเริ่มต้นเดียวไปยังทุกจุดในกราฟ ส่วน A* เป็นการแลกเปลี่ยนที่ตอบคำถามที่อ่อนกว่าเพื่อให้คิวรีรายครั้งเร็วขึ้น
หากโครงสร้างของปัญหาเอื้อ แค่เปลี่ยนการเรียก A* หลายพันครั้งให้เป็นการเรียก BFS หรือ Dijkstra ครั้งเดียว ก็อาจได้ความเร็วเพิ่มขึ้นมาก อีกความต่างสำคัญคือ BFS ทำงานได้เฉพาะกับกราฟที่ความยาวของขอบทุกเส้นเท่ากัน ส่วน A* รองรับความยาวขอบที่ต่างกันได้ ทั้งสองอย่างไม่ใช่สิ่งที่ใช้แทนกันได้ เหมือนกับที่การหาสมาชิกที่น้อยที่สุดในลิสต์ไม่ได้ทดแทนการเรียงลำดับลิสต์
คำกล่าวอย่าง “quadtree และโครงสร้างข้อมูลต้นไม้สารพัดประโยชน์ทั้งหมดช้าอย่างบ้าคลั่ง”, “ต้นไม้ไม่ใช่การแทนข้อมูลที่มีสารสนเทศเกี่ยวกับข้อมูล”, “ทุกครั้งที่ใช้ต้นไม้ คุณกำลังใช้อัลกอริทึม O(log N) ที่ซับซ้อนกว่า แทนอัลกอริทึมแฮช O(~1)” นั้นค่อนข้างผิดทิศทางมาก
แนวทางแบบแฮชชิงนั้นใช้ได้ดีเมื่อจุดกระจายอย่างสม่ำเสมอ และเมื่อคิวรีเฉพาะบริเวณที่ใกล้กับการแบ่งส่วนคงที่ที่เลือกไว้ ไม่เช่นนั้น O(1) นั้นอาจพังลงเป็น O(n) ได้
เมื่อไม่รู้การกระจายของข้อมูล ต้นไม้ คือการแทนข้อมูลที่มีสารสนเทศ
อัลกอริทึมแบบสุ่มก็คล้ายกัน ถ้าพื้นที่ค้นหาประกอบด้วยรายการหรือความเป็นไปได้เป็นล้านล้านขึ้นไปจะทำอย่างไร? ถ้าไม่มีฮิวริสติกเลยล่ะ? ในสถานการณ์ที่ใช้ brute force ก็ไม่ได้ และใช้อัลกอริทึมฉลาด ๆ ก็ไม่ได้ อัลกอริทึมแบบสุ่มก็กลายเป็นผู้ช่วยชีวิต
แอปพลิเคชันเฉพาะนี้อาจไม่จำเป็นต้องใช้ แต่ควรหลีกเลี่ยงการฟันธงแบบเหมารวม
ถ้าพูดจริงจังกว่านั้น อัลกอริทึมที่อิงต้นไม้มักถูกประเมินค่าสูงเกินไป และผู้คนดูเหมือนจะหมกมุ่นกับพฤติกรรม Big-O มากเกิน จนลืมว่าปัจจัยคงที่มีความสำคัญมากแม้มีสมาชิกระดับหลายแสนตัวก็ตาม เรื่องอย่าง locality ของข้อมูลก็เช่นกัน บางครั้งการสแกนตามลำดับไปตรง ๆ อาจเร็วกว่าไปทำงานบัญชีของโครงสร้างที่ซับซ้อนกว่า
โดยรวมแล้ว ควรห่อการดำเนินการไว้ใน wrapper เล็ก ๆ ทำอิมพลีเมนต์แบบง่ายก่อน แล้วค่อยตัดสินจากการวัดผล
กรณีแย่ที่สุดคือต้องเขียนทั้งโปรแกรมใหม่ให้เข้ากับโครงสร้างอื่นเพื่อหวังประสิทธิภาพที่ดีกว่า แต่จากประสบการณ์ เมื่อเขียนไฟล์ใหม่ตั้งแต่ต้น ก็มักได้การปรับปรุงฟรีติดมาพอสมควร
ยังไม่พบวิธีที่น่าพอใจสำหรับเก็บจุด 2D หรือ 3D แล้วคิวรีจุดใกล้เคียง kD-tree นั้นดี แต่ผมอยากเพิ่มจุดไปเรื่อย ๆ ระหว่างดำเนินการ ไม่ใช่สร้างโครงสร้างจากชุดข้อมูลที่คงที่
เนื้อหาแทบทั้งหมดตรงกับ ฮิวริสติกการพัฒนาเกม ของผมเลย เข้าใจได้ว่าทำไมถึงเลือก JavaScript
ตอนนี้ผมกำลังสร้างเฟรมเวิร์กม็อดเกมที่ทำงานด้วย S-expression แบบ Lisp อยู่ และได้รู้ว่าการปรับให้เวลาวนซ้ำเชิงสร้างสรรค์สั้นลงนั้นสำคัญกว่าอะไรทั้งหมด
อัลกอริทึมอย่าง A*, Lee algorithm ล้วนยอดเยี่ยม การทำ flood fill ไม่ว่าแบบไหนโดยไม่ทำ visualization ควบคู่ไปด้วยแทบจะเป็นอาชญากรรมเลย เท่ากับปล่อยโดปามีนให้สูญเปล่ามากเกินไป
อ่านบทความนี้แล้วทำให้สงสัยว่าเทคนิคแถว ๆ การพัฒนาเกมที่ผมยังไม่เคยอ่าน จะมีประโยชน์กับปัญหาแบบนี้ด้วยไหม ผมคงไม่ใช่คนแรกที่คิดว่า boids router น่าจะสนุกทีเดียว พูดให้จริงจังกว่านั้น signed distance field ที่อิงกับ jump flooding น่าจะให้พลังได้มาก
โดยเฉพาะส่วนเกี่ยวกับ spatial hashing ตรงกับประสบการณ์ของผมเลย เกือบ 20 ปีที่ผ่านมา ผมแทบไม่ค่อยเห็นกรณีที่โครงสร้างแบบ tree คุ้มค่ากับเวลาที่ทุ่มลงไป มีข้อยกเว้นหนึ่งอย่างคือ text editor แนวเลิฟคราฟต์ที่ผมทำ ใช้ trie ค่อนข้างเยอะกับการประมวลผลเชิงตอบสนอง มันเป็นวิธีที่ดีในการแปลงคำ 45,000 คำให้เป็น state machine แบบบีบอัดสำหรับจัดการ event
ก่อนหน้านี้ผมเคยเขียนถึง autorouter แบบ recursive pattern ซึ่งพื้นที่คำตอบค่อนข้างเล็ก ทำให้ทำนายด้วยอัลกอริทึม machine learning แบบเดิม ๆ ได้ค่อนข้างง่าย ในงาน autorouting ยังมีพื้นที่น่าสนใจที่ยังไม่ถูกสำรวจอีกมาก
ผมไม่รู้จัก jump flooding มาก่อน ขอเสริมให้คนอื่น ๆ ว่ามันเป็นอัลกอริทึมสำหรับประมาณ distance field แบบขนานได้อย่างรวดเร็ว แน่นอนว่าน่าจะน่าสนใจได้ ขอบคุณที่บอกกัน
tree ก็เข้ากับ recursive algorithm ได้ดี และผู้เขียนบอกว่ามีเหตุผลที่จะเลือก iterative algorithm แทน recursive ดังนั้นคำแนะนำเหล่านี้จึงสอดรับกัน
มองกว้าง ๆ แล้ว การแบ่งเป็น “recursive” กับ “non-recursive” ค่อนข้างเป็นการแบ่งที่สร้างขึ้นเอง คำถามจริง ๆ คือ “อัลกอริทึมที่เตรียมไว้ล่วงหน้าและมีกฎเข้มงวดเป็นผู้ควบคุม flow control หรือผมเป็นผู้ควบคุมเอง” ถ้าคุณใส่ใจประสิทธิภาพมาก คำตอบควรเป็นฝ่ายที่คุณควบคุมเอง และเมื่อ execution state ถูก abstract เข้าไปใน stack ที่ runtime environment จัดให้ จนยากจะแก้แปลก ๆ ตอน runtime มันก็เริ่มกลายเป็นอุปสรรค
คำพูดที่ว่า “95% ของสมาธิควรใช้ไปกับการลดจำนวนรอบการทำซ้ำ ดังนั้นภาษาไม่สำคัญ” นั้นถูกอยู่ระดับหนึ่ง แต่ถ้าหลังจากสร้างอัลกอริทึมที่ดีและมีประสิทธิภาพด้วยภาษาตีความ/เชิงนามธรรม/ช้า ๆ ที่สนุกและ expressive แล้ว ประสิทธิภาพยังสำคัญอยู่ ก็แค่เขียนสิ่งเดิมใหม่ด้วยภาษา low-level ที่มีประสิทธิภาพ และถ้าจำเป็นก็เขียน assembly เฉพาะสถาปัตยกรรมเพิ่มได้
มีเหตุผลที่ numpy, pandas, OpenCV, TensorFlow ไม่ได้เขียนด้วย Python ล้วน ๆ Python ทำหน้าที่สั่งงานที่ implement ด้วย C++/assembly/CUDA ฯลฯ ประสิทธิภาพสูง
ต่อให้ภูมิใจแค่ไหนที่ได้สำรวจ problem space หาอัลกอริทึมที่มีประสิทธิภาพ แล้วเขียนเป็นบล็อก แต่ถ้าดึงดันว่าจะเขียนด้วย Python หรือ JavaScript ล้วน ๆ ก็คงยากที่จะกลายเป็นไลบรารีคำนวณเชิงตัวเลขยอดนิยม
เป็นบทความที่สนุกก็จริง แต่ถ้า insight ด้านอัลกอริทึมของผู้เขียนทำให้ HEVC encoder แบบ JavaScript ล้วนลดจาก 1 วันต่อเฟรมเหลือ 3 ชั่วโมง ก็คงยากที่จะสรุปแบบเดียวกันได้
เห็นคีย์เวิร์ดที่จำได้จากสมัยมหาวิทยาลัยเต็มไปหมด อยากมีโอกาสได้ใช้อัลกอริทึมดัง ๆ เท่ ๆ บ้าง
แต่ในความเป็นจริงผมแค่ทำ UI component กับ REST API เพื่อแสดงผลลัพธ์จาก Elasticsearch ของสนุก ๆ ทั้งหมดถูกฝังอยู่ใน black box
ในการพัฒนาเกมมีอัลกอริทึมที่หลีกเลี่ยงไม่ได้อยู่มาก ถ้าอยากสร้างอัลกอริทึม ลองทำอะไรอย่าง tower defense ดู แล้วจะได้แตะอัลกอริทึมคลาสสิกเยอะทีเดียว
อย่างน้อยผมคิดว่า ปริญญาวิทยาการคอมพิวเตอร์ ในปัจจุบันควรถูกแยกออกเป็นส่วน ๆ ฝั่งคณิตศาสตร์เจ๋ง ๆ ควรเป็นปริญญาแยก และอาจรวมกับปริญญาใหม่ด้าน AI ได้ ทฤษฎีฐานข้อมูลและเครือข่ายก็ควรเป็นปริญญาแยก เช่นเดียวกับ assembly ระดับต่ำ ส่วนการทำงานของชิ้นส่วนอิเล็กทรอนิกส์, NAND gate, Boolean algebra ฯลฯ ควรย้ายไปอยู่ในวิศวกรรมไฟฟ้า
คนที่ตลาดต้องการมากที่สุด คือคนที่ผลิตแอป CRUD ได้ ถ้าจะยืนยันว่าจำเป็นต้องมีความรู้เชิงวิชาการจริง ๆ ก็ควรทำเป็นปริญญาแยก หรือย้ายไปสายอาชีวศึกษา
ในขณะเดียวกัน gatekeeper ของข้อกำหนดการจ้างงานก็ควรถูกจัดการด้วยกฎหมายด้วย ไม่ควรอนุญาตให้เรียกวุฒิที่แทบไม่เกี่ยวข้องกับงานจริง ตอนนี้มันทำให้เด็ก ๆ เสียเวลาในชีวิตไปหลายปีและเป็นหนี้ตั้งแต่หลักหมื่นถึงหลักแสนดอลลาร์ เพียงเพื่อช่วยให้บริษัทคัดคนออกได้ง่ายขึ้นเท่านั้น
แม้จะไม่ได้จัดการปัญหาเชิงพื้นที่ 2D/3D โดยตรง แต่บทเรียนที่ใหญ่ที่สุดคือ คุณค่าของ visualization
มนุษย์เก่งมากในการทำความเข้าใจและวิเคราะห์ภาพ อีกอย่างคือไอเดียในการใช้วิธีเชิงความน่าจะเป็นหรือ brute force เพื่อทำความเข้าใจรูปร่างของปัญหาก่อน แล้วค่อยเลือกวิธีที่ดีกว่าให้สอดคล้องกับสิ่งนั้น ไม่ใช่อาศัยความเข้าใจเชิงทฤษฎีล้วน ๆ อย่างเดียว
คำว่า “ภาษาที่ใช้ implement ไม่สำคัญ” อาจจะถูกในสาขานี้ แต่ถ้านำไปใช้กับวิศวกรรมซอฟต์แวร์ทั่วไป ผมคิดว่าสมมติฐานที่ว่าการเลือกภาษาไม่ส่งผลต่อความเร็วและจำนวนรอบการทำซ้ำที่จำเป็นนั้นผิดไปมาก
ถ้าอยู่ในขั้นควบคุมพจน์เอกซ์โปเนนเชียลหรือพหุนาม ความแตกต่างระหว่าง Rust หรือ assembly ที่ hardcode กับ JavaScript หรือ VisualBasic ก็อาจแทบไม่มีความหมาย