ฉันจะเขียนโค้ดผู้ไม่เชื่อเรื่องพระเจ้าได้อย่างไร


19

ฉันมักจะพบว่าตัวเองกำลังเขียนโค้ดที่คล้ายกันมากสำหรับรุ่นหนึ่งสองและสามมิติของการดำเนินการ / อัลกอริทึมที่กำหนด การบำรุงรักษาเวอร์ชันเหล่านี้ทั้งหมดอาจกลายเป็นเรื่องน่าเบื่อ การสร้างโค้ดอย่างง่ายนั้นใช้งานได้ดี แต่ดูเหมือนว่าจะต้องมีวิธีที่ดีกว่า

มีวิธีที่ค่อนข้างง่ายในการเขียนการดำเนินการเพียงครั้งเดียวและมีการพูดคุยกับมิติที่สูงขึ้นหรือต่ำลงหรือไม่?

ตัวอย่างที่ชัดเจนประการหนึ่งคือสมมติว่าฉันต้องการคำนวณการไล่ระดับสีของสนามความเร็วในอวกาศ ในสามมิติลูป Fortran จะมีลักษณะดังนี้:

do k = 1, n
  do j = 1, n
    do i = 1, n
      phi(i,j,k) = ddx(i)*u(i,j,k) + ddx(j)*v(i,j,k) + ddx(k)*w(i,j,k)
    end do
  end do
end do

โดยที่ddxarray นั้นถูกกำหนดอย่างเหมาะสม (เราสามารถทำได้ด้วยการคูณเมทริกซ์) โค้ดสำหรับโฟลว์สองมิตินั้นเกือบจะเหมือนกันทุกประการยกเว้น: มิติที่สามถูกดร็อปจากลูปดัชนีและจำนวนของคอมโพเนนต์ มีวิธีที่ดีกว่าในการแสดงสิ่งนี้หรือไม่?

อีกตัวอย่างคือ: สมมติว่าฉันมีความเร็วของของไหลที่กำหนดจุด - ฉลาดในตารางสามมิติ เพื่อสอดแทรกความเร็วไปยังตำแหน่งตามอำเภอใจ (กล่าวคือไม่สอดคล้องกับจุดกริด) เราสามารถใช้อัลกอริทึมเนวิลล์หนึ่งมิติติดกันตลอดทั้งสามมิติ (เช่นการลดมิติ) มีวิธีง่าย ๆ ในการลดขนาดหรือไม่เนื่องจากการใช้อัลกอริธึมแบบง่ายในมิติเดียว?

คำตอบ:


13

คุณดูว่า deal.II ( http://www.dealii.org/ ) ทำอย่างไร - ที่นั่นความเป็นอิสระด้านมิติอยู่ที่ใจกลางของห้องสมุดและมีการจำลองเป็นอาร์กิวเมนต์แม่แบบสำหรับประเภทข้อมูลส่วนใหญ่ ตัวอย่างเช่นตัวแก้ Laplace ขนาดไม่เชื่อเรื่องพระเจ้าในโปรแกรมการสอนขั้นตอนที่ 4:

http://www.dealii.org/developer/doxygen/deal.II/step_4.html

ดูสิ่งนี้ด้วย

https://github.com/dealii/dealii/wiki/Frequently-Asked-Questions#why-use-templates-for-the-space-dimension


ฉันเห็นด้วยอย่างยิ่ง ฉันไม่พบวิธีการที่ดีกว่าสิ่งที่ Deal.II กำลังทำอยู่ พวกเขาใช้เทมเพลตในวิธีที่น่าสนใจมากในการแก้ไขปัญหานี้
Eldila

1
ทรัพยากรที่ดี แต่ค่อนข้างน่ากลัวหากคุณไม่ได้เทมเพลต C ++
meawoppl

@ Wolfgang Bangerth: deal.ii กำหนดตัวทำซ้ำโดยใช้แม่แบบด้วยหรือไม่?
Matthew Emmett

@ MatthewEmmett: ใช่
Wolfgang Bangerth

@meawoppl: อันที่จริงไม่ ฉันสอนชั้นเรียนเป็นประจำ II และในตอนแรกเพียงบอกนักเรียนว่าทุกสิ่งที่ระบุว่า ClassWhtml <2> เป็น 2d ClassWhething <3> เป็น 3 มิติและ ClassWhething <dim> อยู่ในระดับต่ำ ผมนำบทเรียนเกี่ยวกับแม่ที่ไหนสักแห่งในสัปดาห์ที่ 3 และในขณะที่เป็นไปได้ว่านักเรียนไม่เข้าใจวิธีการทำงานก่อนที่พวกเขากำลังทำงานอย่างเต็มที่โดยใช้มันต่อไป
Wolfgang Bangerth

12

คำถามเน้นว่าภาษาการเขียนโปรแกรม "ธรรมดา" ส่วนใหญ่ (C, Fortran อย่างน้อย) ไม่อนุญาตให้คุณทำสิ่งนี้อย่างหมดจด ข้อ จำกัด เพิ่มเติมคือคุณต้องการความสะดวกสบายและประสิทธิภาพที่ดี

ดังนั้นแทนที่จะเขียนรหัสเฉพาะมิติลองเขียนรหัสที่สร้างรหัสเฉพาะมิติ ตัวสร้างนี้ไม่ขึ้นอยู่กับขนาดแม้ว่ารหัสการคำนวณจะไม่ กล่าวอีกนัยหนึ่งคุณเพิ่มเลเยอร์ของการให้เหตุผลระหว่างสัญกรณ์ของคุณและรหัสที่แสดงการคำนวณ เทมเพลต C ++ นั้นมีจำนวนเท่ากัน: คว่ำมันสร้างขึ้นในภาษา ข้อเสียพวกเขาค่อนข้างยุ่งยากในการเขียน สิ่งนี้จะช่วยลดคำถามเกี่ยวกับวิธีสร้างตัวสร้างโค้ดในทางปฏิบัติ

OpenCL ช่วยให้คุณสามารถสร้างรหัสในเวลาทำงานได้ค่อนข้างดี นอกจากนี้ยังทำให้แยกสะอาดระหว่าง 'โปรแกรมควบคุมภายนอก' และ 'ลูปภายใน / เมล็ด' โปรแกรมสร้างภายนอกส่วนใหญ่มีข้อ จำกัด ด้านประสิทธิภาพน้อยกว่าดังนั้นอาจเขียนด้วยภาษาที่สะดวกสบายเช่น Python นั่นคือความหวังของฉันสำหรับวิธีPyOpenCLจะได้ใช้ - ขอโทษสำหรับปลั๊กไร้ยางอายใหม่


อันเดรีย! ยินดีต้อนรับสู่ scicomp! ดีใจที่มีคุณในเว็บไซต์ฉันคิดว่าคุณรู้วิธีติดต่อกับฉันถ้าคุณมีคำถามใด ๆ
Aron Ahmadia

2
+10000 สำหรับการสร้างรหัสอัตโนมัติเพื่อแก้ไขปัญหานี้แทนเวทมนตร์ C ++
Jeff

9

สามารถทำได้ในภาษาใด ๆ ด้วยต้นแบบคร่าวๆต่อไปนี้:

  1. สร้างรายการขอบเขตของแต่ละมิติ (บางอย่างเช่นรูปร่าง () ใน MATLAB ฉันคิดว่า)
  2. สร้างรายการที่ตั้งปัจจุบันของคุณในแต่ละมิติ
  3. เขียนลูปบนแต่ละมิติที่มีการวนรอบการเปลี่ยนแปลงขนาดของ whos ตามลูปภายนอก

จากนั้นเป็นคำถามของการต่อสู้กับไวยากรณ์ของภาษาของคุณเพื่อให้รหัสของคุณสอดคล้องกับมาตรฐาน

หลังจากเขียนตัวแก้สมการพลศาสตร์ของไหลสองมิติฉันพบว่ามันมีประโยชน์ที่จะมีภาษาที่รองรับการคลายรายการเช่นวัตถุเป็นอาร์กิวเมนต์ของฟังก์ชัน คือ a = (1,2,3) f (a *) -> f (1,2,3) นอกจากนี้ตัวทำซ้ำขั้นสูง (เช่นndenumerateเป็นnumpy) ทำให้โค้ดมีลำดับความสำคัญมากขึ้น


ไวยากรณ์ Python สำหรับการทำสิ่งนี้ดูดีและรวบรัด ฉันสงสัยว่ามีวิธีที่ดีที่จะทำเช่นนี้กับ Fortran ...
แมทธิวเอ็มเม็ต

1
มันเจ็บปวดเล็กน้อยที่จะจัดการกับหน่วยความจำแบบไดนามิกใน Fortran อาจเป็นเรื่องสำคัญที่ฉันร้องเรียนด้วยภาษา
meawoppl

5

n1×n2×n3nJ=1


ดังนั้นเพื่อเป็นมิติอิสระโค้ดของคุณจะต้องเขียนสำหรับ maxdim + 1 มิติโดย maxdim เป็นมิติสูงสุดที่ผู้ใช้เคยพบ สมมติว่า maxdim = 100 รหัสผลลัพธ์มีประโยชน์อย่างไร
Jeff

4

คำตอบที่ชัดเจนหากคุณต้องการรักษาความเร็วของ Fortran ให้ใช้ภาษาที่มีการสร้างรหัสที่เหมาะสมเช่น Julia หรือ C ++ เทมเพลต C ++ ได้ถูกกล่าวถึงแล้วดังนั้นฉันจะพูดถึงเครื่องมือของ Julia ที่นี่ ฟังก์ชันที่สร้างขึ้นของ Julia ช่วยให้คุณใช้ metaprogramming เพื่อสร้างฟังก์ชันตามต้องการผ่านข้อมูลประเภท สิ่งสำคัญที่คุณสามารถทำได้ที่นี่ก็คือทำ

@generated function f(x)
   N = ndims(x)
   quote
     # build the code for the function
   end
end

และจากนั้นคุณใช้Nโปรแกรมสร้างรหัสที่คุณต้องการที่จะดำเนินการให้ว่ามันเป็นNมิติ จากนั้นห้องสมุดหรือแพ็คเกจCartesianของ Julia เช่นนิพจน์Einsum.jlสามารถสร้างขึ้นได้อย่างง่ายดายสำหรับNฟังก์ชันมิติ

สิ่งที่ดีเกี่ยวกับจูเลียที่นี่ก็คือฟังก์ชั่นนี้ถูกรวบรวมและปรับให้เหมาะสมสำหรับอาร์เรย์มิติใหม่แต่ละอันที่คุณใช้ดังนั้นมันจะไม่รวบรวมมากกว่าที่คุณต้องการ แต่มันจะทำให้คุณได้รับความเร็ว C / Fortran ในที่สุดสิ่งนี้ก็คล้ายกับการใช้เทมเพลต C ++ แต่มันเป็นภาษาระดับสูงที่มีเครื่องมือมากมายที่จะทำให้มันง่ายขึ้น (ง่ายพอที่จะเป็นปัญหาการบ้านที่ดีสำหรับนักศึกษาปริญญาตรี)

ภาษาอื่นที่ดีสำหรับเรื่องนี้คือเสียงกระเพื่อมเหมือนเสียงกระเพื่อมสามัญ มันใช้งานง่ายตั้งแต่จูเลียมันทำให้ AST ที่คอมไพล์แล้วมีเครื่องมือวิปัสสนาสร้างขึ้นมากมาย แต่ต่างจากจูเลียมันจะไม่รวบรวมโดยอัตโนมัติ (ในการแจกแจงส่วนใหญ่)


1

ฉันอยู่ในเรือลำเดียวกัน (Fortran) เมื่อฉันมีองค์ประกอบ 1D, 2D, 3D และ 4D (ฉันทำเรขาคณิต projective) ฉันจะสร้างตัวดำเนินการเดียวกันสำหรับแต่ละประเภทแล้วเขียนตรรกะของฉันด้วยสมการระดับสูงที่ทำให้ชัดเจนว่าเกิดอะไรขึ้น ไม่ช้าอย่างที่คุณคิดว่ามีการแยกลูปของแต่ละการดำเนินการและสำเนาหน่วยความจำมากมาย ฉันให้คอมไพเลอร์ / โปรเซสเซอร์ทำการปรับให้เหมาะสม

ตัวอย่างเช่น

interface operator (.x.)
    module procedure cross_product_1x2
    module procedure cross_product_2x1
    module procedure cross_product_2x2
    module procedure cross_product_3x3
end interface 

subroutine cross_product_1x2(a,b,c)
    real(dp), intent(in) :: a(1), b(2)
    real(dp), intent(out) :: c(2)

    c = [ -a(1)*b(2), a(1)*b(1) ]
end subroutine

subroutine cross_product_2x1(a,b,c)
    real(dp), intent(in) :: a(2), b(1)
    real(dp), intent(out) :: c(2)

    c = [ a(2)*b(1), -a(1)*b(1) ]
end subroutine

subroutine cross_product_2x2(a,b,c)
    real(dp), intent(in) :: a(2), b(2)
    real(dp), intent(out) :: c(1)

    c = [ a(1)*b(2)-a(2)*b(1) ]
end subroutine

subroutine cross_product_3x3(a,b,c)
    real(dp), intent(in) :: a(3), b(3)
    real(dp), intent(out) :: c(3)

    c = [a(2)*b(3)-a(3)*b(2), a(3)*b(1)-a(1)*b(3), a(1)*b(2)-a(2)*b(1)]
end subroutine

เพื่อนำมาใช้ในสมการอย่างเช่น

m = e .x. (r .x. g)  ! m = e×(r×g)

ที่ไหนeและrและgสามารถมีมิติที่ทำให้รู้สึกทางคณิตศาสตร์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.