Schläfli Convex Regular Polytope ล่าม


15

พื้นหลัง

Schläfliสัญลักษณ์เป็นเครื่องหมายของแบบฟอร์ม {p, Q, R, ... } ที่กำหนดเรขาคณิตระดับประถมปกติและ tessellations

สัญลักษณ์Schläfliเป็นคำอธิบายแบบเรียกซ้ำโดยเริ่มจากรูปหลายเหลี่ยมแบบปกติด้าน p เป็น {p} ตัวอย่างเช่น {3} เป็นรูปสามเหลี่ยมด้านเท่า {4} เป็นรูปสี่เหลี่ยมและอื่น ๆ

รูปทรงหลายเหลี่ยมปกติที่มีรูปหลายเหลี่ยมหน้ารูปตัว q ปกติที่ล้อมรอบจุดยอดแต่ละจุดจะถูกแทนด้วย {p, q} ตัวอย่างเช่นลูกบาศก์มี 3 สี่เหลี่ยมล้อมรอบแต่ละจุดยอดและแสดงด้วย {4,3}

polytope 4 มิติปกติที่มีเซลล์ {}, q} polyhedral รอบ ๆ แต่ละขอบจะถูกแทนด้วย {p, q, r} ตัวอย่างเช่น tesseract {4,3,3} มี 3 คิวบ์, {4,3}, รอบ ๆ ขอบ

โดยทั่วไป polytope ปกติ {p, q, r, ... , y, z} มี z {p, q, r, ... , y} ทุกแง่มุมรอบยอดสูงสุดที่ยอดเป็นยอดในรูปทรงหลายเหลี่ยม ขอบใน 4-polytope ใบหน้าใน 5-polytope เซลล์ใน 6-polytope และ (n-3) -face ใน n-polytope

โพลีท็อปปกติมีรูปยอดจุดปกติ รูปจุดยอดของ polytope ปกติ {p, q, r, ... y, z} คือ {q, r, ... y, z}

polytopes ปกติสามารถมีองค์ประกอบรูปหลายเหลี่ยมดาวเช่นรูปดาวห้าแฉกที่มีสัญลักษณ์ {5/2} แทนด้วยจุดยอดของรูปห้าเหลี่ยม แต่เชื่อมต่อสลับกัน

สัญลักษณ์Schläfliสามารถเป็นตัวแทนของรูปทรงหลายเหลี่ยมนูน จำกัด , tessellation อนันต์ของพื้นที่ยูคลิดอนันต์, หรือ tessellation อนันต์ของพื้นที่ซึ่งเกินความจริงซึ่งขึ้นอยู่กับข้อบกพร่องมุมของการก่อสร้าง ข้อบกพร่องมุมบวกช่วยให้ร่างจุดสุดยอดที่จะพับเข้าไปในมิติที่สูงขึ้นและวนกลับเข้าไปในตัวเองในฐานะ polytope ข้อบกพร่องที่เป็นศูนย์จะทำให้พื้นที่ในมิติเดียวกันเป็นแง่มุม tessellates ข้อผิดพลาดมุมเชิงลบไม่สามารถมีอยู่ในพื้นที่ปกติ แต่สามารถสร้างในพื้นที่ซึ่งเกินความจริง

การแข่งขัน

เป้าหมายของคุณคือการสร้างโปรแกรมซึ่งเมื่อผ่านการเป็นสัญลักษณ์ของSchläfliจะส่งคืนคำอธิบายที่สมบูรณ์เกี่ยวกับโพลีป้อนแบบนูน นี่เป็นเพียงส่วนย่อยของสัญลักษณ์ของSchläfli แต่มันเป็นสิ่งที่ง่ายที่สุดฉันเชื่อว่าแม้จะไม่มีความเป็นไปได้อื่น ๆ ก็ตามนี่จะเป็นงานที่ยากมากและโพลีสเตปเป็นจุดเริ่มต้นของการทดสอบ กฎของคำถามนี้ได้รับการออกแบบโดยมีแนวคิดว่าผลลัพธ์นี้เป็น API และฉันไม่สามารถค้นหาโปรแกรมดังกล่าวบนอินเทอร์เน็ตได้

โปรแกรมของคุณจะต้องสำเร็จทั้งหมดดังต่อไปนี้

  • โปรแกรมนั้นจะต้องสามารถสร้างโพลิปท็อปนูนที่มีมิติ จำกัด ได้ ใน 2 มิติรวมถึง n-gons ใน 3 มิติเหล่านี้คือของแข็งสงบใน 4 มิติซึ่งรวมถึง tesseract, orthoplex และอื่น ๆ ไม่กี่)
  • โปรแกรมต้อง (a) วางจุดบนจุดเริ่มต้นหรือ (b) ตรวจสอบให้แน่ใจว่าค่าเฉลี่ยของจุดทั้งหมดเป็นจุดเริ่มต้น การวางแนวไม่สำคัญ ขนาดโดยรวมไม่สำคัญ
  • โปรแกรมจะต้องให้คำอธิบายที่สมบูรณ์ซึ่งหมายความว่าสำหรับวัตถุ 4 มิติโปรแกรมจะส่งคืน / พิมพ์จุดยอดขอบใบหน้าและรูปทรงหลายเหลี่ยม คำสั่งเหล่านี้ถูกรายงานไม่สำคัญ สำหรับรูปทรงหลายเหลี่ยมนี่เป็นข้อมูลที่คุณต้องการเพื่อแสดงผลวัตถุ

คุณไม่จำเป็นต้องจัดการ:

  • Tesselations
  • เรขาคณิตแบบไฮเปอร์โบลิค
  • สัญลักษณ์Schläfliเศษส่วน (ไม่นูน)
  • สัญลักษณ์Schläfliในตัว (การเอียงไม่สม่ำเสมอ)

หากถูกขอให้ทำสิ่งเหล่านี้คุณสามารถส่งคืนข้อผิดพลาดได้

ตัวอย่าง: Cube

การป้อนข้อมูล:

4 3

เอาท์พุท:

Vertices
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1    

Edges (These are the vertex pairs that make up the edges)
0 1
0 2
0 4
1 3
1 5
2 3
2 6
3 7
4 5
4 6
5 7
6 7

Faces (These are the squares which are the faces of the cube)
0 1 3 2
0 1 5 4
0 2 6 4
6 7 5 4
7 6 2 3
7 5 1 3

ฉันมีความคิดบางอย่างเกี่ยวกับวิธีการทำงานของอัลกอริทึมและเรียกซ้ำได้ แต่จนถึงตอนนี้ฉันล้มเหลว แต่ถ้าคุณกำลังมองหาแรงบันดาลใจลองดู: https://en.wikipedia.org/wiki/Euler_characteristic

เป็นตัวอย่างของการหาจำนวนจุดยอดขอบและใบหน้าพิจารณาลูกบาศก์ซึ่งคือ {4,3} ถ้าเราดูที่ค่าเริ่มต้น 4 มันก็มี 4 ขอบและ 4 จุดยอด ทีนี้ถ้าเราดูที่ 3 ถัดไปเรารู้ว่า 3 ขอบพบกันที่จุดยอดแต่ละจุดแต่ละเส้นเชื่อมต่อกับ 2 จุดยอด, 2 ใบหน้าพบกันที่ขอบแต่ละข้าง, แต่ละใบหน้าเชื่อมต่อกับ 4 ขอบ (เพราะด้านเหลี่ยม) และเรามี สูตรลักษณะออยเลอร์

E = 3/2 V

E = 4/2 F

V - E + F = 2

ซึ่งให้ E = 12, V = 8, F = 6

เกณฑ์การให้คะแนน

เพื่อที่จะเก็บคำถามในหัวข้อนี้ได้รับการแก้ไขเป็นรหัสกอล์ฟ รหัสที่สั้นที่สุดชนะ

มีการสร้าง github สำหรับคำถามนี้


1
Googling แสดงให้เห็นว่ามีโพลิปท็อปปกติเพียง 3 ตระกูลที่ขยายเกิน 4 มิติคล้ายกับลูกบาศก์แปดด้านและทรงสี่หน้า ดูเหมือนว่าจะง่ายกว่าที่จะเขียนให้กับครอบครัวเหล่านี้และทำการ hardcode ส่วนที่เหลือ (โพลีทรี 3 มิติสองอันโพลิป 4d สามอันและตระกูลที่ไม่มีที่สิ้นสุดของโพลีป 2d) เท่าที่ฉันเห็นว่าตรงตามมาตรฐาน นั่นเป็นคำตอบที่ถูกต้องหรือไม่? มันอาจเป็นไปได้ที่จะเขียนอัลกอริธึมแบบเรียกซ้ำเพื่อสร้างกราฟทอพอโลยีที่อยู่นอกขอบเขตของข้อมูลจำเพาะ แต่นักฆ่าด้วยวิธีการนั้นแม้ภายในสเป็คจะคำนวณพิกัด
เลเวลริเวอร์เซนต์

เราจะรู้จุดยอดจริงได้อย่างไรโดยรู้เพียงว่าพวกเขาเป็นรูปสามเหลี่ยมด้านเท่า?
Matthew Roh

@SIGSEGV ข้อกำหนดเฉพาะที่ระบุไว้คือต้นกำเนิดควรสอดคล้องกับจุดศูนย์กลางหรือจุดใดจุดหนึ่ง ที่ให้ขอบเขตมากมายในการหมุนรูปร่างตามที่คุณต้องการ en.wikipedia.org/wiki/Simplexให้อัลกอริทึมสำหรับการคำนวณพิกัดของไฮเพทราฮีดตรอน (ซึ่งอาจขยายไปยัง icosahedron และอะนาล็อก 4 มิติ แต่การทำนั้นมากเกินไปสำหรับฉันดังนั้นคำถามของฉัน) hypercubes และ hyperoctahedrons พิกัดจำนวนเต็มที่ดี (และความดันโลหิตสูงเกินไปจริง ๆ แล้ว แต่มักจะมีเฉพาะในมิติที่มากกว่ารูปร่างของตัวเองซึ่งไม่เป็นระเบียบ)
เลเวลริเวอร์เซนต์

@LevelRiverSt ใช่แล้วเนื่องจากโพลิปปรกติเพียงอันเดียวที่มีอยู่จะถูกกล่าวถึงในข้อเสนอแนะของคุณใช่แล้วคุณจึงสามารถ hardcode พวกมันได้
Tony Ruth

ฉันลงคะแนนปิดคำถามนี้เพราะมันเป็นความท้าทายแบบปืนที่เร็วที่สุดในฝั่งตะวันตกซึ่งคำตอบแรกที่ถูกต้องชนะ โดยทั่วไปจะไม่ถือว่าเป็นเกณฑ์การชนะที่ถูกต้อง ฉันไม่ทราบว่าสิ่งนี้เปิดมานานเท่าไรแล้วควรจะปิด
โพสต์ Rock Garf Hunter

คำตอบ:


2

หลาม

นี่คือโปรแกรมแบบเรียกซ้ำโดยไม่มีกรณีพิเศษใด ๆ ไม่สนใจบรรทัดว่างเปล่าและความคิดเห็นมีน้อยกว่า100 90 บรรทัดรวมถึงการตรวจสอบสูตรออยเลอร์โดยไม่ต้องเสียค่าใช้จ่ายในตอนท้าย ไม่รวมคำจำกัดความของฟังก์ชั่นคณิตศาสตร์ ad-hoc (ซึ่งอาจมีให้โดยห้องสมุด) และ i / o, การสร้าง polytope คือรหัส 50 บรรทัด และมันก็ยังทำโพลีเอสต์รูปดาวอีกด้วย!

โพลีท็อปเอาท์พุทจะมีความยาวขอบ 1 และจะอยู่ในตำแหน่งและการวางแนวซึ่งเป็นที่ยอมรับในแง่ต่อไปนี้:

  • จุดสุดยอดแรกคือจุดกำเนิด
  • ขอบแรกอยู่ตามแกน + x
  • ใบหน้าแรกอยู่ใน + y ครึ่งระนาบของระนาบ xy
  • 3 เซลล์แรกอยู่ใน +z half-space ของ xyz space เป็นต้น

นอกจากนั้นรายการเอาท์พุทจะไม่เรียงตามลำดับ (จริง ๆ แล้วนั่นไม่จริงทั้งหมด -พวกเขาจะออกมาอย่างคร่าวๆเพื่อเริ่มต้นจากองค์ประกอบแรกและขยายออกไปด้านนอก)

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

ถ้าคุณขอระนาบระนาบไม่มีที่สิ้นสุดเช่น {4,4} หรือ {3,6} หรือ {6,3} โปรแกรมจะเริ่มสร้างการเรียงต่อกัน แต่มันจะไปตลอดกาลจนกว่ามันจะหมดพื้นที่ไม่เคย การตกแต่งหรือการผลิตผลผลิต สิ่งนี้จะไม่ยากเกินกว่าจะแก้ไขได้ (เพียงกำหนดจำนวนองค์ประกอบที่จะสร้างผลลัพธ์ควรเป็นขอบเขตที่ค่อนข้างสอดคล้องกันของภาพที่ไม่มีที่สิ้นสุดเนื่องจากองค์ประกอบถูกสร้างขึ้นตามลำดับการค้นหาแบบกว้างแรก

รหัส

#!/usr/bin/python3
# (works with python2 or python3)

#
# schlafli_interpreter.py
# Author: Don Hatch
# For: /codegolf/114280/schl%C3%A4fli-convex-regular-polytope-interpreter
#
# Print the vertex coords and per-element (edges, faces, etc.) vertex index
# lists of a regular polytope, given by its schlafli symbol {p,q,r,...}.
# The output polytope will have edge length 1 and will be in canonical position
# and orientation, in the following sense:
#  - the first vertex is the origin,
#  - the first edge lies along the +x axis,
#  - the first face is in the +y half-plane of the xy plane,
#  - the first 3-cell is in the +z half-space of the xyz space, etc.
# Other than that, the output lists are in no particular order.
#

import sys
from math import *

# vector minus vector.
def vmv(a,b): return [x-y for x,y in zip(a,b)]
# matrix minus matrix.
def mmm(m0,m1): return [vmv(row0,row1) for row0,row1 in zip(m0,m1)]
# scalar times vector.
def sxv(s,v): return [s*x for x in v]
# scalar times matrix.
def sxm(s,m): return [sxv(s,row) for row in m]
# vector dot product.
def dot(a,b): return sum(x*y for x,y in zip(a,b))
# matrix outer product of two vectors; that is, if a,b are column vectors: a*b^T
def outer(a,b): return [sxv(x,b) for x in a]
# vector length squared.
def length2(v): return dot(v,v)
# distance between two vectors, squared.
def dist2(a,b): return length2(vmv(a,b))
# matrix times vector, homogeneous (i.e. input vector ends with an implicit 1).
def mxvhomo(m,v): return [dot(row,v+[1]) for row in m]
# Pad a square matrix (rotation/reflection) with an extra column of 0's on the
# right (translation).
def makehomo(m): return [row+[0] for row in m]
# Expand dimensionality of homogeneous transform matrix by 1.
def expandhomo(m): return ([row[:-1]+[0,row[-1]] for row in m]
                         + [[0]*len(m)+[1,0]])
# identity matrix
def identity(dim): return [[(1 if i==j else 0) for j in range(dim)]
                                               for i in range(dim)]
# https://en.wikipedia.org/wiki/Householder_transformation. v must be unit.
# Not homogeneous (makehomo the result if you want that).
def householderReflection(v): return mmm(identity(len(v)), sxm(2, outer(v,v)))

def sinAndCosHalfDihedralAngle(schlafli):
  # note, cos(pi/q)**2 generally has a nicer expression with no trig and often
  # no radicals, see http://www.maths.manchester.ac.uk/~cds/articles/trig.pdf
  ss = 0
  for q in schlafli: ss = cos(pi/q)**2 / (1 - ss)
  if abs(1-ss) < 1e-9: ss = 1  # prevent glitch in planar tiling cases
  return sqrt(ss), sqrt(1 - ss)

# Calculate a set of generators of the symmetry group of a {p,q,r,...} with
# edge length 1.
# Each generator is a dim x (dim+1) matrix where the square part is the initial
# orthogonal rotation/reflection and the final column is the final translation.
def calcSymmetryGenerators(schlafli):
  dim = len(schlafli) + 1
  if dim == 1: return [[[-1,1]]]  # one generator: reflect about x=.5
  facetGenerators = calcSymmetryGenerators(schlafli[:-1])
  # Start with facet generators, expanding each homogeneous matrix to full
  # dimensionality (i.e. from its previous size dim-1 x dim to dim x dim+1).
  generators = [expandhomo(gen) for gen in facetGenerators]
  # Final generator will reflect the first facet across the hyperplane
  # spanned by the first ridge and the entire polytope's center,
  # taking the first facet to a second facet also containing that ridge.
  # v = unit vector normal to that bisecting hyperplane
  #   = [0,...,0,-sin(dihedralAngle/2),cos(dihedralAngle/2)]
  s,c = sinAndCosHalfDihedralAngle(schlafli)
  v = [0]*(dim-2) + [-s,c]
  generators.append(makehomo(householderReflection(v)))
  return generators

# Key for comparing coords with roundoff error.  Makes sure the formatted
# numbers are not very close to 0, to avoid them coming out as "-0" or "1e-16".
# This isn't reliable in general, but it suffices for this application
# (except for very large {p}, no doubt).
def vert2key(vert): return ' '.join(['%.9g'%(x+.123) for x in vert])

# Returns a pair verts,edgesEtc where edgesEtc is [edges,faces,...]
def regular_polytope(schlafli):
  dim = len(schlafli) + 1
  if dim == 1: return [[0],[1]],[]

  gens = calcSymmetryGenerators(schlafli)

  facetVerts,facetEdgesEtc = regular_polytope(schlafli[:-1])

  # First get all the verts, and make a multiplication table.
  # Start with the verts of the first facet (padded to full dimensionality),
  # so indices will match up.
  verts = [facetVert+[0] for facetVert in facetVerts]
  vert2index = dict([[vert2key(vert),i] for i,vert in enumerate(verts)])
  multiplicationTable = []
  iVert = 0
  while iVert < len(verts):  # while verts is growing
    multiplicationTable.append([None] * len(gens))
    for iGen in range(len(gens)):
      newVert = mxvhomo(gens[iGen], verts[iVert])
      newVertKey = vert2key(newVert)
      if newVertKey not in vert2index:
        vert2index[newVertKey] = len(verts)
        verts.append(newVert)
      multiplicationTable[iVert][iGen] = vert2index[newVertKey]
    iVert += 1

  # The higher-level elements of each dimension are found by transforming
  # the facet's elements of that dimension.  Start by augmenting facetEdgesEtc
  # by adding one more list representing the entire facet.
  facetEdgesEtc.append([tuple(range(len(facetVerts)))])
  edgesEtc = []
  for facetElementsOfSomeDimension in facetEdgesEtc:
    elts = facetElementsOfSomeDimension[:]
    elt2index = dict([[elt,i] for i,elt in enumerate(elts)])
    iElt = 0
    while iElt < len(elts):  # while elts is growing
      for iGen in range(len(gens)):
        newElt = tuple(sorted([multiplicationTable[iVert][iGen]
                               for iVert in elts[iElt]]))
        if newElt not in elt2index:
          elt2index[newElt] = len(elts)
          elts.append(newElt)
      iElt += 1
    edgesEtc.append(elts)

  return verts,edgesEtc

# So input numbers can be like any of "8", "2.5", "7/3"
def parseNumberOrFraction(s):
  tokens = s.split('/')
  return float(tokens[0])/float(tokens[1]) if len(tokens)==2 else float(s)

if sys.stdin.isatty():
  sys.stderr.write("Enter schlafli symbol (space-separated numbers or fractions): ")
  sys.stderr.flush()
schlafli = [parseNumberOrFraction(token) for token in sys.stdin.readline().split()]
verts,edgesEtc = regular_polytope(schlafli)

# Hacky polishing of any integers or half-integers give or take rounding error.
def fudge(x): return round(2*x)/2 if abs(2*x-round(2*x))<1e-9 else x

print(repr(len(verts))+' Vertices:')
for v in verts: print(' '.join([repr(fudge(x)) for x in v]))
for eltDim in range(1,len(edgesEtc)+1):
  print("")
  elts = edgesEtc[eltDim-1]
  print(repr(len(elts))+' '+('Edges' if eltDim==1
                        else 'Faces' if eltDim==2
                        else repr(eltDim)+'-cells')+" ("+repr(len(elts[0]))+" vertices each):")
  for elt in elts: print(' '.join([repr(i) for i in elt]))

# Assert the generalization of Euler's formula: N0-N1+N2-... = 1+(-1)**(dim-1).
N = [len(elts) for elts in [verts]+edgesEtc]
eulerCharacteristic = sum((-1)**i * N[i] for i in range(len(N)))
print("Euler characteristic: "+repr(eulerCharacteristic))
if 2.5 not in schlafli: assert eulerCharacteristic == 1 + (-1)**len(schlafli)

ลองใช้ในบางกรณี

อินพุต ( คิวบ์ ):

4 3

เอาท์พุท:

8 Vertices:
0.0 0.0 0.0
1.0 0.0 0.0
0.0 1.0 0.0
1.0 1.0 0.0
0.0 0.0 1.0
1.0 0.0 1.0
0.0 1.0 1.0
1.0 1.0 1.0

12 Edges (2 vertices each):
0 1
0 2
1 3
2 3
0 4
1 5
4 5
2 6
4 6
3 7
5 7
6 7

6 Faces (4 vertices each):
0 1 2 3
0 1 4 5
0 2 4 6
1 3 5 7
2 3 6 7
4 5 6 7

อินพุตจากเชลล์คำสั่ง unix ( polychoron 120 เซลล์ ):

$ echo "5 3 3" | ./schlafli_interpreter.py | grep ":"

เอาท์พุท:

600 Vertices:
1200 Edges (2 vertices each):
720 Faces (5 vertices each):
120 3-cells (20 vertices each):

อินพุต ( polytope ข้ามมิติ):

$ echo "3 3 3 3 3 3 3 3 4" | ./schlafli_interpreter.py | grep ":"

เอาท์พุท:

20 Vertices:
180 Edges (2 vertices each):
960 Faces (3 vertices each):
3360 3-cells (4 vertices each):
8064 4-cells (5 vertices each):
13440 5-cells (6 vertices each):
15360 6-cells (7 vertices each):
11520 7-cells (8 vertices each):
5120 8-cells (9 vertices each):
1024 9-cells (10 vertices each):

อินพุต ( เริมมิติ 15 ):

$ echo "3 3 3 3 3 3 3 3 3 3 3 3 3 3" | ./schlafli_interpreter.py | grep ":"

16 Vertices:
120 Edges (2 vertices each):
560 Faces (3 vertices each):
1820 3-cells (4 vertices each):
4368 4-cells (5 vertices each):
8008 5-cells (6 vertices each):
11440 6-cells (7 vertices each):
12870 7-cells (8 vertices each):
11440 8-cells (9 vertices each):
8008 9-cells (10 vertices each):
4368 10-cells (11 vertices each):
1820 11-cells (12 vertices each):
560 12-cells (13 vertices each):
120 13-cells (14 vertices each):
16 14-cells (15 vertices each):

โพลีเอสตาร์รูปดาว

ฮะและมันก็เป็นเพียงแค่ดาราโพลีโอป ฉันไม่จำเป็นต้องลอง :-) ยกเว้นว่าบิตเกี่ยวกับสูตรของออยเลอร์ในตอนท้ายก็ล้มเหลวเนื่องจากสูตรนั้นไม่ถูกต้องสำหรับโพลิปท็อปดาว

อินพุต ( dodecahedron ที่มีขนาดเล็ก ):

5/2 5

เอาท์พุท:

12 Vertices:
0.0 0.0 0.0
1.0 0.0 0.0
0.8090169943749473 0.5877852522924732 0.0
0.19098300562505266 0.5877852522924732 0.0
0.5 -0.36327126400268034 0.0
0.8090169943749473 -0.2628655560595667 0.5257311121191336
0.19098300562505266 -0.2628655560595667 0.5257311121191336
0.5 0.162459848116453 -0.3249196962329062
0.5 0.6881909602355867 0.5257311121191336
0.0 0.32491969623290623 0.5257311121191336
0.5 0.1624598481164533 0.8506508083520398
1.0 0.32491969623290623 0.5257311121191336

30 Edges (2 vertices each):
0 1
0 2
1 3
2 4
3 4
0 5
1 6
5 7
6 7
0 8
2 9
7 8
7 9
1 8
0 10
3 11
5 9
4 10
7 11
4 9
2 5
1 10
4 11
6 11
6 8
3 10
3 6
2 10
9 11
5 8

12 Faces (5 vertices each):
0 1 2 3 4
0 1 5 6 7
0 2 7 8 9
1 3 7 8 11
0 4 5 9 10
2 4 5 7 11
1 4 6 10 11
0 3 6 8 10
3 4 6 7 9
2 3 9 10 11
1 2 5 8 10
5 6 8 9 11
Traceback (most recent call last):
  File "./schlafli_interpreter.py", line 185, in <module>
    assert sum((-1)**i * N[i] for i in range(len(N))) == 1 + (-1)**len(schlafli)
AssertionError

อินพุต ( เยี่ยมชม 120 เซลล์ที่ยอดเยี่ยม ):

$ echo "5/2 3 5" | ./schlafli_interpreter.py | grep ":"

เอาท์พุท:

120 Vertices:
720 Edges (2 vertices each):
720 Faces (5 vertices each):
120 3-cells (20 vertices each):

ขอบคุณสำหรับการคืนคำถามนี้และคำตอบของคุณน่าประทับใจมาก ฉันชอบธรรมชาติที่ซ้ำซากและดวงดาว ฉันเชื่อมต่อรหัสของคุณกับ OpenGL บางตัวเพื่อวาดรูปวาดโพลิปท็อป (ดูลิงค์ GitHub ด้านบน)
Tony Ruth

14

ทับทิม

พื้นหลัง

polytope ปกติมีสามตระกูลขยายเป็นมิติที่ไม่มีที่สิ้นสุด:

  • simplexes ซึ่งจัตุรมุขเป็นสมาชิก (ฉันมักจะอ้างถึงพวกเขาที่นี่เป็นไฮเพทราเฮดราแม้ว่าคำว่าเริมจะถูกต้องมากขึ้น) สัญลักษณ์ schlafi ของพวกเขาอยู่ในรูปแบบ {3,3,...,3,3}

  • n-cubes ซึ่ง cube เป็นสมาชิก สัญลักษณ์ schlafi เป็นแบบฟอร์ม{4,3,...,3,3}

  • orthoplexes ซึ่งแปดด้านเป็นสมาชิก (ฉันมักจะอ้างถึงพวกเขาที่นี่เป็น hyperoctahedra) สัญลักษณ์ schlafi ของพวกเขาอยู่ในรูปแบบ {3,3,...,3,4}

มีครอบครัวอนันต์เพิ่มเติมอีกหนึ่งแห่งของ polytopes ปกติสัญลักษณ์{m}ของรูปหลายเหลี่ยม 2 มิติซึ่งอาจมีขอบจำนวน m ใด ๆ

นอกจากนี้ยังมีอีกห้ากรณีพิเศษอื่น ๆ ของ polytope ปกติคือ icosahedron 3 มิติ{3,5}และ dodecahedron {5,3}; analogues 4 มิติของพวกเขา 600 เซลล์{3,3,5}และ 120 เซลล์{5,3,3}; และอีกหนึ่งมิติ polytope 4 มิติ 24 เซลล์{3,4,3}(ซึ่งมี analogues ที่ใกล้ที่สุดใน 3 มิติคือ cuboctahedron และคู่ dombecahedron ขนมเปียกปูนของมัน)

ฟังก์ชั่นหลัก

ด้านล่างเป็นpolytopeฟังก์ชั่นหลักที่ตีความสัญลักษณ์ schlafi คาดว่าจะมีอาร์เรย์ของตัวเลขและส่งกลับอาร์เรย์ที่มีกลุ่มของอาร์เรย์ดังนี้

  • อาเรย์ของจุดยอดทั้งหมดแต่ละอันแสดงเป็นอาเรย์ n-element ของพิกัด (โดยที่ n คือจำนวนมิติ)

  • อาเรย์ของขอบทั้งหมดแต่ละอันแสดงเป็น 2 องค์ประกอบของดัชนีจุดสุดยอด

  • อาร์เรย์ของใบหน้าทั้งหมดแต่ละหน้าแสดงเป็นองค์ประกอบ m ของดัชนีจุดยอด (โดยที่ m คือจำนวนจุดยอดต่อหน้า)

และอื่น ๆ ตามความเหมาะสมกับจำนวนมิติ

มันคำนวณ 2d polytopes ของตัวเองเรียกใช้ฟังก์ชันสำหรับตระกูล infinite 3 มิติและใช้ตารางการค้นหาสำหรับกรณีพิเศษห้ากรณี มันคาดว่าจะพบฟังก์ชั่นและตารางที่ประกาศไว้ข้างต้น

include Math

#code in subsequent sections of this answer should be inserted here 

polytope=->schl{
  if schl.size==1                                #if a single digit calculate and return a polygon
    return [(1..schl[0]).map{|i|[sin(PI*2*i/schl[0]),cos(PI*2*i/schl[0])]},(1..schl[0]).map{|i|[i%schl[0],(i+1)%schl[0]]}]  
  elsif  i=[[3,5],[5,3]].index(schl)             #if a 3d special, lookup from tables
    return [[vv,ee,ff],[uu,aa,bb]][i]
  elsif i=[[3,3,5],[5,3,3],[3,4,3]].index(schl)  #if a 4d special. lookup fromm tables
    return [[v,e,f,g],[u,x,y,z],[o,p,q,r]][i]
  elsif schl.size==schl.count(3)                 #if all threes, call tetr for a hypertetrahedron
    return tetr[schl.size+1]
  elsif schl.size-1==schl.count(3)               #if all except one number 3
    return cube[schl.size+1] if schl[0]==4       #and the 1st digit is 4, call cube for a hypercube
    return octa[schl.size+1] if schl[-1]==4      #and the last digit is 4, call octa for a hyperoctahedron
  end
  return "error"                                 #in any other case return an error
}

ฟังก์ชั่นสำหรับจัตุรมุขลูกบาศก์และแปดตระกูล

https://en.wikipedia.org/wiki/Simplex

https://en.wikipedia.org/wiki/5-cell (4d simplex)

http://mathworld.wolfram.com/Simplex.html

คำอธิบายตระกูล Tetrahedron - พิกัด

Simplex / Hyperetrahedron แบบ n-dimensional มี n + 1 คะแนน มันง่ายมากที่จะให้จุดยอดของ n-dimension simplex ใน n + 1 มิติ

ดังนั้น(1,0,0),(0,1,0),(0,0,1)อธิบายสามเหลี่ยม 2d ที่ฝังใน 3 มิติและ(1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)อธิบายจัตุรมุข 3 มิติที่ฝังใน 4 มิติ สิ่งนี้สามารถตรวจสอบได้อย่างง่ายดายโดยการยืนยันว่าระยะทางทั้งหมดระหว่างจุดยอดคือ sqrt (2)

อัลกอริทึมที่ซับซ้อนต่าง ๆ จะได้รับบนอินเทอร์เน็ตสำหรับการค้นหาจุดยอดสำหรับซิมเพล็กซ์ในพื้นที่มิติ ผมพบว่าหนึ่งง่ายอย่างน่าทึ่งในความคิดเห็นจะ Jagy ในคำตอบนี้/mathpro//a/38725 จุดสุดท้ายอยู่บนเส้นp=q=...=x=y=zที่ระยะของ sqrt (2) จากคนอื่น ๆ ดังนั้นสามเหลี่ยมดังกล่าวข้างต้นสามารถแปลงเป็นจัตุรมุขโดยนอกเหนือจากจุดที่ทั้งหรือ(-1/3,-1/3,-1/3) (1,1,1)2 ค่าที่เป็นไปได้เหล่านี้ของพิกัดสำหรับจุดสุดท้ายจะถูกกำหนดโดย(1-(1+n)**0.5)/nและ(1+(1+n)**0.5)/n

ตามที่คำถามบอกว่าขนาดของ n-tope ไม่สำคัญฉันต้องการคูณด้วย n และใช้พิกัด(n,0,0..0)จนถึง(0..0,0,n)จุดสุดท้าย(t,t,..,t,t)ที่ t = 1-(1+n)**0.5เพื่อความเรียบง่าย

เนื่องจากศูนย์กลางของจัตุรมุขนี้ไม่ได้อยู่ที่จุดกำเนิดการแก้ไขพิกัดทั้งหมดจะต้องทำโดยเส้นs.map!{|j|j-((1-(1+n)**0.5)+n)/(1+n)}ที่ค้นหาว่าศูนย์กลางอยู่ไกลจากจุดกำเนิดและลบออก ฉันเก็บสิ่งนี้ไว้เป็นการดำเนินการแยกต่างหาก อย่างไรก็ตามฉันได้ใช้s[i]+=nตำแหน่งที่s[i]=nจะทำเพื่ออ้างอิงถึงความจริงที่ว่าเมื่ออาเรย์เริ่มต้นโดยs=[0]*nเราสามารถใส่ออฟเซ็ตที่ถูกต้องที่นี่แทนและทำการแก้ไขที่กึ่งกลางที่จุดเริ่มต้นแทนที่จะจบ

คำอธิบายตระกูล Tetrahedron - ทอพอโลยีกราฟ

กราฟของ simplex เป็นกราฟที่สมบูรณ์: ทุกจุดยอดจะเชื่อมต่อกันทุกครั้งที่จุดยอดอื่น ๆ หากเรามี n simplex เราสามารถลบจุดสุดยอดใด ๆ เพื่อให้ n-1 simplex ลงไปจนถึงจุดที่เรามีรูปสามเหลี่ยมหรือแม้แต่ขอบ

ดังนั้นเราจึงมีทั้งหมด 2 รายการ ** (n + 1) ไปยังแคตตาล็อกซึ่งแต่ละรายการจะแสดงด้วยเลขฐานสอง ช่วงนี้จากทั้งหมด0เพื่อความว่างเปล่าผ่านหนึ่ง1สำหรับจุดสุดยอดและสอง1s สำหรับขอบถึงถึงทั้งหมด1สำหรับ polytope ที่สมบูรณ์

เราตั้งค่าอาร์เรย์ของอาร์เรย์ที่ว่างเปล่าเพื่อจัดเก็บองค์ประกอบของแต่ละขนาด จากนั้นเราวนรอบจากศูนย์ถึง (2 ** n + 1) เพื่อสร้างเซตย่อยที่เป็นไปได้ของแต่ละจุดและเก็บไว้ในอาร์เรย์ตามขนาดของแต่ละชุดย่อย

เราไม่สนใจในสิ่งที่เล็กกว่าขอบ (จุดยอดหรือศูนย์) หรือในโพลีท็อปที่สมบูรณ์ (เนื่องจากลูกบาศก์ที่สมบูรณ์ไม่ได้ให้ไว้ในตัวอย่างในคำถาม) ดังนั้นเราจึงกลับtg[2..n]ไปลบองค์ประกอบที่ไม่ต้องการเหล่านี้ ก่อนจะกลับมาเราจะทำการ [ทีวี] ที่มีพิกัดจุดยอดเข้าสู่จุดเริ่มต้น

รหัส

tetr=->n{

  #Tetrahedron Family Vertices
  tv=(0..n).map{|i|
    s=[0]*n
    if i==n
      s.map!{(1-(1+n)**0.5)}
    else
      s[i]+=n
    end
    s.map!{|j|j-((1-(1+n)**0.5)+n)/(1+n)}
  s}

  #Tetrahedron Family Graph
  tg=(0..n+1).map{[]}
  (2**(n+1)).times{|i|
    s=[]
    (n+1).times{|j|s<<j if i>>j&1==1}
    tg[s.size]<<s
  }

return [tv]+tg[2..n]}

cube=->n{

  #Cube Family Vertices
  cv=(0..2**n-1).map{|i|s=[];n.times{|j|s<<(i>>j&1)*2-1};s}

  #Cube Family Graph
  cg=(0..n+1).map{[]}
  (3**n).times{|i|                         #for each point
    s=[]
    cv.size.times{|j|                      #and each vertex
      t=true                               #assume vertex goes with point
      n.times{|k|                          #and each pair of opposite sides
        t&&= (i/(3**k)%3-1)*cv[j][k]!=-1   #if the vertex has kingsmove distance >1 from point it does not belong      
      }
      s<<j if t                            #add the vertex if it belongs
    }
    cg[log2(s.size)+1]<<s if s.size > 0
  } 

return [cv]+cg[2..n]}

octa=->n{

  #Octahedron Family Vertices
  ov=(0..n*2-1).map{|i|s=[0]*n;s[i/2]=(-1)**i;s}

  #Octahedron Family Graph
  og=(0..n).map{[]}
  (3**n).times{|i|                         #for each point
    s=[]
    ov.size.times{|j|                      #and each vertex
      n.times{|k|                          #and each pair of opposite sides
        s<<j if (i/(3**k)%3-1)*ov[j][k]==1 #if the vertex is located in the side corresponding to the point, add the vertex to the list      
      }    
    }
    og[s.size]<<s
  } 

return [ov]+og[2..n]}

คำอธิบายตระกูล cube และ octahedron - พิกัด

n-cube มี2**nจุดยอดแต่ละอันแสดงโดยอาร์เรย์ของ n 1s และ-1s (เป็นไปได้ทั้งหมดที่ได้รับอนุญาต) เราวนซ้ำดัชนี0ไป2**n-1ยังรายการของจุดยอดทั้งหมดและสร้างอาร์เรย์สำหรับจุดยอดแต่ละจุดด้วยการวนซ้ำผ่านบิตของ ดัชนีและการเพิ่ม-1หรือ1อาร์เรย์ (น้อยนิดที่สำคัญในการบิตที่สำคัญที่สุด.) ดังนั้นไบนารีจะกลายเป็นจุด1101 4d[1,-1,1,1]

n-แปดหรือ n-orthoplex มี2nจุดพิกัดศูนย์ทั้งหมดยกเว้นหนึ่งซึ่งจะเป็นหรือ1 ลำดับของจุดในอาร์เรย์ที่สร้างขึ้นมี-1 [[1,0,0..],[-1,0,0..],[0,1,0..],[0,-1,0..],[0,0,1..],[0,0,-1..]...]โปรดทราบว่าในขณะที่รูปแปดด้านนั้นเป็นคู่ของลูกบาศก์จุดยอดของรูปแปดด้านจะถูกกำหนดโดยศูนย์กลางของใบหน้าของก้อนที่ล้อมรอบ

คำอธิบายตระกูล cube และ octahedron - ทอพอโลยีกราฟ

แรงบันดาลใจบางอย่างมาจากด้าน Hypercubeและความจริงที่ว่า hyperoctahedron เป็นสองเท่าของ hypercube

สำหรับ n-cube มี3**nรายการที่จะแคตตาล็อก ตัวอย่างเช่น 3 cube มี3**3= 27 องค์ประกอบ สิ่งนี้สามารถเห็นได้จากการศึกษาลูกบาศก์ของรูบิคซึ่งมีศูนย์ 1, 6 ใบหน้า, 12 ขอบและ 8 จุดยอดรวม 27 เราวนซ้ำไปจนถึง -1,0 และ -1 ในทุกมิติที่กำหนด n-cube ของความยาว 2x2x2 .. และกลับจุดยอดทั้งหมดที่ไม่ได้อยู่ฝั่งตรงข้ามของลูกบาศก์ ดังนั้นศูนย์กลางของคิวบ์จะส่งคืนจุดยอดทั้ง 2 ** n และการย้ายหนึ่งหน่วยออกจากศูนย์กลางตามแนวแกนใด ๆ จะลดจำนวนจุดยอดลงครึ่งหนึ่ง

เช่นเดียวกับตระกูลจัตุรมุขเราเริ่มต้นด้วยการสร้างอาร์เรย์ที่ว่างและเติมตามจำนวนจุดยอดต่อองค์ประกอบ โปรดทราบว่าเนื่องจากจำนวนของจุดแตกต่างกันเป็น 2 ** n ในขณะที่เราขึ้นไปถึงขอบใบหน้า, ก้อน ฯลฯ เราใช้แทนที่จะlog2(s.size)+1 s.sizeอีกครั้งเราต้องลบไฮเปอร์คิวบ์ออกและองค์ประกอบทั้งหมดที่มีจุดยอดน้อยกว่า 2 อันก่อนกลับจากฟังก์ชัน

Octahedron / orthoplex เป็นสองเท่าของตระกูล cube ดังนั้นจึงมี3**nไอเท็มแค็ตตาล็อก ที่นี่เราวนซ้ำ-1,0,1สำหรับมิติทั้งหมดและหากพิกัดที่ไม่ใช่ศูนย์ของจุดยอดเท่ากับพิกัดที่สอดคล้องกันของจุดจุดยอดจะถูกเพิ่มเข้าไปในรายการที่สอดคล้องกับจุดนั้น ดังนั้นขอบจึงตรงกับจุดที่มีสองค่าที่ไม่ใช่ศูนย์, สามเหลี่ยมไปยังจุดที่มี 3 ค่าที่ไม่ใช่ศูนย์และ tetrahedron ไปยังจุดที่มี 4 หน้าสัมผัสที่ไม่ใช่ศูนย์ (ในพื้นที่ 4d)

อาร์เรย์ผลลัพธ์ของจุดสุดยอดสำหรับแต่ละจุดจะถูกเก็บไว้ในอาร์เรย์ขนาดใหญ่เช่นเดียวกับกรณีอื่นและเราต้องลบองค์ประกอบใด ๆ ที่มีจุดยอดน้อยกว่า 2 จุดก่อนที่จะกลับมา แต่ในกรณีนี้เราไม่จำเป็นต้องลบพาเรนต์ n-tope ทั้งหมดเนื่องจากอัลกอริทึมไม่ได้บันทึกไว้

การใช้งานของรหัสสำหรับคิวบ์ได้รับการออกแบบให้มีความคล้ายคลึงกันมากที่สุด ขณะนี้มีความสง่างามบางอย่างเป็นไปได้ว่าอัลกอริทึมที่มีประสิทธิภาพมากขึ้นตามหลักการเดียวกันนี้สามารถสร้างขึ้นมาได้

https://en.wikipedia.org/wiki/Hypercube

http://mathworld.wolfram.com/Hypercube.html

https://en.wikipedia.org/wiki/Cross-polytope

http://mathworld.wolfram.com/CrossPolytope.html

รหัสสำหรับการสร้างตารางสำหรับกรณีพิเศษ 3 มิติ

มีการใช้การวางแนวของ icosahedron / dodecahedron โดยใช้แกนสมมาตรห้าเท่าที่ขนานกับมิติสุดท้ายซึ่งใช้สำหรับการติดฉลากที่สอดคล้องกันของชิ้นส่วน การนับจำนวนจุดยอดและใบหน้าสำหรับ icosahedron นั้นเป็นไปตามแผนภาพในการแสดงความคิดเห็นเกี่ยวกับโค้ดและกลับไปหา dodecahedron

ตามhttps://en.wikipedia.org/wiki/Regular_icosahedronละติจูดของจุดยอดที่ไม่มีขั้ว 10 ขั้วของ icosahedron คือ +/- arctan (1/2) พิกัดของ 10 จุดยอดแรกของ icosahedron นั้นคำนวณจาก นี่บนรัศมีสองวง 2 ที่ระยะทาง +/- 2 จากระนาบ xy สิ่งนี้ทำให้รัศมีโดยรวมของ circumsphere sqrt (5) ดังนั้นจุดยอด 2 อันสุดท้ายอยู่ที่ (0,0, + / - - sqrt (2))

พิกัดของจุดยอดของทรงสิบสองเหลี่ยมคำนวณโดยการหาพิกัดของจุดยอดสามอันที่ล้อมรอบพวกมัน

=begin
TABLE NAMES      vertices     edges      faces
icosahedron      vv           ee         ff
dodecahedron     uu           aa         bb 

    10
    / \   / \   / \   / \   / \
   /10 \ /12 \ /14 \ /16 \ /18 \
   -----1-----3-----5-----7-----9
   \ 0 / \ 2 / \ 4 / \ 6 / \ 8 / \
    \ / 1 \ / 3 \ / 5 \ / 7 \ / 9 \
     0-----2-----4-----6-----8-----
      \11 / \13 / \15 / \17 / \19 /
       \ /   \ /   \ /   \ /   \ / 
       11
=end

vv=[];ee=[];ff=[]
10.times{|i|
  vv[i]=[2*sin(PI/5*i),2*cos(PI/5*i),(-1)**i]
  ee[i]=[i,(i+1)%10];ee[i+10]=[i,(i+2)%10];ee[i+20]=[i,11-i%2]
  ff[i]=[(i-1)%10,i,(i+1)%10];ff[i+10]=[(i-1)%10,10+i%2,(i+1)%10]

}
vv+=[[0,0,-5**0.5],[0,0,5**0.5]]

uu=[];aa=[];bb=[]
10.times{|i|
  uu[i]=(0..2).map{|j|vv[ff[i][0]][j]+vv[ff[i][1]][j]+vv[ff[i][2]][j]}
  uu[i+10]=(0..2).map{|j|vv[ff[i+10][0]][j]+vv[ff[i+10][1]][j]+vv[ff[i+10][2]][j]}
  aa[i]=[i,(i+1)%10];aa[i+10]=[i,(i+10)%10];aa[i+20]=[(i-1)%10+10,(i+1)%10+10]
  bb[i]=[(i-1)%10+10,(i-1)%10,i,(i+1)%10,(i+1)%10+10] 
}
bb+=[[10,12,14,16,18],[11,13,15,17,19]]

รหัสสำหรับการสร้างตารางสำหรับกรณีพิเศษ 4d

นี่เป็นบิตของการแฮ็ก รหัสนี้ใช้เวลาสองสามวินาทีในการเรียกใช้ มันจะดีกว่าที่จะเก็บผลลัพธ์ในไฟล์และโหลดตามที่ต้องการ

รายการ 120 พิกัดจุดสุดยอดสำหรับ 600cell คือจากhttp://mathworld.wolfram.com/600-Cell.html พิกัด 24 จุดยอดที่ไม่มีอัตราส่วนทองคำในรูปจุดยอดของเซลล์ 24 เซลล์ Wikipedia มีรูปแบบเหมือนกัน แต่มีข้อผิดพลาดในระดับสัมพัทธ์ของ 24 พิกัดเหล่านี้และอีก 96

#TABLE NAMES                           vertices     edges      faces   cells
#600 cell (analogue of icosahedron)    v            e          f       g
#120 cell (analogue of dodecahedron)   u            x          y       z 
#24 cell                               o            p          q       r

#600-CELL

# 120 vertices of 600cell. First 24 are also vertices of 24-cell

v=[[2,0,0,0],[0,2,0,0],[0,0,2,0],[0,0,0,2],[-2,0,0,0],[0,-2,0,0],[0,0,-2,0],[0,0,0,-2]]+

(0..15).map{|j|[(-1)**(j/8),(-1)**(j/4),(-1)**(j/2),(-1)**j]}+

(0..95).map{|i|j=i/12
   a,b,c,d=1.618*(-1)**(j/4),(-1)**(j/2),0.618*(-1)**j,0
   h=[[a,b,c,d],[b,a,d,c],[c,d,a,b],[d,c,b,a]][i%12/3]
   (i%3).times{h[0],h[1],h[2]=h[1],h[2],h[0]}
h}

#720 edges of 600cell. Identified by minimum distance of 2/phi between them

e=[]
120.times{|i|120.times{|j|
  e<<[i,j]  if i<j && ((v[i][0]-v[j][0])**2+(v[i][1]-v[j][1])**2+(v[i][2]-v[j][2])**2+(v[i][3]-v[j][3])**2)**0.5<1.3  
}}

#1200 faces of 600cell. 
#If 2 edges share a common vertex and the other 2 vertices form an edge in the list, it is a valid triangle.

f=[]
720.times{|i|720.times{|j|
  f<< [e[i][0],e[i][1],e[j][1]] if i<j && e[i][0]==e[j][0] && e.index([e[i][1],e[j][1]])
}}

#600 cells of 600cell.
#If 2 triangles share a common edge and the other 2 vertices form an edge in the list, it is a valid tetrahedron.

g=[]
1200.times{|i|1200.times{|j|
  g<< [f[i][0],f[i][1],f[i][2],f[j][2]] if i<j && f[i][0]==f[j][0] && f[i][1]==f[j][1] && e.index([f[i][2],f[j][2]])

}}

#120 CELL (dual of 600 cell)

#600 vertices of 120cell, correspond to the centres of the cells of the 600cell
u=g.map{|i|s=[0,0,0,0];i.each{|j|4.times{|k|s[k]+=v[j][k]/4.0}};s}

#1200 edges of 120cell at centres of faces of 600-cell. Search for pairs of tetrahedra with common face
x=f.map{|i|s=[];600.times{|j|s<<j if i==(i & g[j])};s}

#720 pentagonal faces, surrounding edges of 600-cell. Search for sets of 5 tetrahedra with common edge
y=e.map{|i|s=[];600.times{|j|s<<j if i==(i & g[j])};s}

#120 dodecahedral cells surrounding vertices of 600-cell. Search for sets of 20 tetrahedra with common vertex
z=(0..119).map{|i|s=[];600.times{|j|s<<j if [i]==([i] & g[j])};s}


#24-CELL
#24 vertices, a subset of the 600cell
o=v[0..23]

#96 edges, length 2, found by minimum distances between vertices
p=[]
24.times{|i|24.times{|j|
  p<<[i,j]  if i<j && ((v[i][0]-v[j][0])**2+(v[i][1]-v[j][1])**2+(v[i][2]-v[j][2])**2+(v[i][3]-v[j][3])**2)**0.5<2.1  
}}

#96 triangles
#If 2 edges share a common vertex and the other 2 vertices form an edge in the list, it is a valid triangle.
q=[]
96.times{|i|96.times{|j|
  q<< [p[i][0],p[i][1],p[j][1]] if i<j && p[i][0]==p[j][0] && p.index([p[i][1],p[j][1]])
}}


#24 cells. Calculates the centre of the cell and the 6 vertices nearest it
r=(0..23).map{|i|a,b=(-1)**i,(-1)**(i/2)
    c=[[a,b,0,0],[a,0,b,0],[a,0,0,b],[0,a,b,0],[0,a,0,b],[0,0,a,b]][i/4]
    s=[]
    24.times{|j|t=v[j]
    s<<j if (c[0]-t[0])**2+(c[1]-t[1])**2+(c[2]-t[2])**2+(c[3]-t[3])**2<=2 
    }
s}

https://en.wikipedia.org/wiki/600-cell

http://mathworld.wolfram.com/600-Cell.html

https://en.wikipedia.org/wiki/120-cell

http://mathworld.wolfram.com/120-Cell.html

https://en.wikipedia.org/wiki/24-cell

http://mathworld.wolfram.com/24-Cell.html

ตัวอย่างการใช้งานและเอาท์พุท

cell24 = polytope[[3,4,3]]

puts "vertices"
cell24[0].each{|i|p i}
puts "edges"
cell24[1].each{|i|p i}
puts "faces"
cell24[2].each{|i|p i}
puts "cells"
cell24[3].each{|i|p i}

vertices
[2, 0, 0, 0]
[0, 2, 0, 0]
[0, 0, 2, 0]
[0, 0, 0, 2]
[-2, 0, 0, 0]
[0, -2, 0, 0]
[0, 0, -2, 0]
[0, 0, 0, -2]
[1, 1, 1, 1]
[1, 1, 1, -1]
[1, 1, -1, 1]
[1, 1, -1, -1]
[1, -1, 1, 1]
[1, -1, 1, -1]
[1, -1, -1, 1]
[1, -1, -1, -1]
[-1, 1, 1, 1]
[-1, 1, 1, -1]
[-1, 1, -1, 1]
[-1, 1, -1, -1]
[-1, -1, 1, 1]
[-1, -1, 1, -1]
[-1, -1, -1, 1]
[-1, -1, -1, -1]
edges
[0, 8]
[0, 9]
[0, 10]
[0, 11]
[0, 12]
[0, 13]
[0, 14]
[0, 15]
[1, 8]
[1, 9]
[1, 10]
[1, 11]
[1, 16]
[1, 17]
[1, 18]
[1, 19]
[2, 8]
[2, 9]
[2, 12]
[2, 13]
[2, 16]
[2, 17]
[2, 20]
[2, 21]
[3, 8]
[3, 10]
[3, 12]
[3, 14]
[3, 16]
[3, 18]
[3, 20]
[3, 22]
[4, 16]
[4, 17]
[4, 18]
[4, 19]
[4, 20]
[4, 21]
[4, 22]
[4, 23]
[5, 12]
[5, 13]
[5, 14]
[5, 15]
[5, 20]
[5, 21]
[5, 22]
[5, 23]
[6, 10]
[6, 11]
[6, 14]
[6, 15]
[6, 18]
[6, 19]
[6, 22]
[6, 23]
[7, 9]
[7, 11]
[7, 13]
[7, 15]
[7, 17]
[7, 19]
[7, 21]
[7, 23]
[8, 9]
[8, 10]
[8, 12]
[8, 16]
[9, 11]
[9, 13]
[9, 17]
[10, 11]
[10, 14]
[10, 18]
[11, 15]
[11, 19]
[12, 13]
[12, 14]
[12, 20]
[13, 15]
[13, 21]
[14, 15]
[14, 22]
[15, 23]
[16, 17]
[16, 18]
[16, 20]
[17, 19]
[17, 21]
[18, 19]
[18, 22]
[19, 23]
[20, 21]
[20, 22]
[21, 23]
[22, 23]
faces
[0, 8, 9]
[0, 8, 10]
[0, 8, 12]
[0, 9, 11]
[0, 9, 13]
[0, 10, 11]
[0, 10, 14]
[0, 11, 15]
[0, 12, 13]
[0, 12, 14]
[0, 13, 15]
[0, 14, 15]
[1, 8, 9]
[1, 8, 10]
[1, 8, 16]
[1, 9, 11]
[1, 9, 17]
[1, 10, 11]
[1, 10, 18]
[1, 11, 19]
[1, 16, 17]
[1, 16, 18]
[1, 17, 19]
[1, 18, 19]
[2, 8, 9]
[2, 8, 12]
[2, 8, 16]
[2, 9, 13]
[2, 9, 17]
[2, 12, 13]
[2, 12, 20]
[2, 13, 21]
[2, 16, 17]
[2, 16, 20]
[2, 17, 21]
[2, 20, 21]
[3, 8, 10]
[3, 8, 12]
[3, 8, 16]
[3, 10, 14]
[3, 10, 18]
[3, 12, 14]
[3, 12, 20]
[3, 14, 22]
[3, 16, 18]
[3, 16, 20]
[3, 18, 22]
[3, 20, 22]
[4, 16, 17]
[4, 16, 18]
[4, 16, 20]
[4, 17, 19]
[4, 17, 21]
[4, 18, 19]
[4, 18, 22]
[4, 19, 23]
[4, 20, 21]
[4, 20, 22]
[4, 21, 23]
[4, 22, 23]
[5, 12, 13]
[5, 12, 14]
[5, 12, 20]
[5, 13, 15]
[5, 13, 21]
[5, 14, 15]
[5, 14, 22]
[5, 15, 23]
[5, 20, 21]
[5, 20, 22]
[5, 21, 23]
[5, 22, 23]
[6, 10, 11]
[6, 10, 14]
[6, 10, 18]
[6, 11, 15]
[6, 11, 19]
[6, 14, 15]
[6, 14, 22]
[6, 15, 23]
[6, 18, 19]
[6, 18, 22]
[6, 19, 23]
[6, 22, 23]
[7, 9, 11]
[7, 9, 13]
[7, 9, 17]
[7, 11, 15]
[7, 11, 19]
[7, 13, 15]
[7, 13, 21]
[7, 15, 23]
[7, 17, 19]
[7, 17, 21]
[7, 19, 23]
[7, 21, 23]
cells
[0, 1, 8, 9, 10, 11]
[1, 4, 16, 17, 18, 19]
[0, 5, 12, 13, 14, 15]
[4, 5, 20, 21, 22, 23]
[0, 2, 8, 9, 12, 13]
[2, 4, 16, 17, 20, 21]
[0, 6, 10, 11, 14, 15]
[4, 6, 18, 19, 22, 23]
[0, 3, 8, 10, 12, 14]
[3, 4, 16, 18, 20, 22]
[0, 7, 9, 11, 13, 15]
[4, 7, 17, 19, 21, 23]
[1, 2, 8, 9, 16, 17]
[2, 5, 12, 13, 20, 21]
[1, 6, 10, 11, 18, 19]
[5, 6, 14, 15, 22, 23]
[1, 3, 8, 10, 16, 18]
[3, 5, 12, 14, 20, 22]
[1, 7, 9, 11, 17, 19]
[5, 7, 13, 15, 21, 23]
[2, 3, 8, 12, 16, 20]
[3, 6, 10, 14, 18, 22]
[2, 7, 9, 13, 17, 21]
[6, 7, 11, 15, 19, 23]

1
ว้าวนี่เป็นคำตอบที่ยอดเยี่ยม !! ฉันประหลาดใจมากที่คุณสามารถทำสิ่งนี้ได้ใน ~ 200 บรรทัด ฉันวิ่งลูกบาศก์จัตุรมุข 600 เซลล์และอีกไม่กี่พวกเขาดูดี เป็นการยากที่จะตรวจสอบผลลัพธ์เนื่องจากมีจำนวนมาก มันค่อนข้างง่ายสำหรับผลลัพธ์ที่จะยาวกว่าโปรแกรม แต่ฉันจะใช้คำของคุณสำหรับมัน ฉันจะลองโหลดสิ่งนี้ลงใน openGL และดูเพลโตโทนิคของแข็งซึ่งควรจะตรงไปตรงมานับตั้งแต่ใบหน้าทั้งหมดมีอยู่ในรายการ ฉันคิดว่าการเพิ่ม tesselations ในพื้นที่ราบอาจเป็นเรื่องง่ายและฉันก็อาจลองทำเช่นกัน
Tony Ruth

@TonyRuth ที่สำคัญคือการหาอัลกอริทึมที่ดีที่สุด Less Lines = ห้องน้อยลงสำหรับข้อผิดพลาด สิ่งแรกที่ฉันทำคือตรวจสอบสิ่งที่มีอยู่นอกเหนือจากตระกูล 3 มิติที่ไม่มีที่สิ้นสุดและนั่นคือตอนที่ฉันตัดสินใจตอบ ความเห็นของ Jagy จะมาจากสวรรค์หรือไม่ (ฉันคิดเกี่ยวกับวิธีการแก้ปัญหาแบบนั้นเพราะวิธีของวิกิพีเดียดูยาก) ดังนั้นพิกัดที่ไม่ใช่จำนวนเต็มจึงถูกเก็บไว้ให้น้อยที่สุด ฉันต้องการทำให้เสร็จก่อนที่เงินรางวัลจะหมดอายุดังนั้นการตรวจสอบยังไม่ละเอียดมากนักและฉันยังไม่ได้วางแผน แจ้งให้เราทราบถึงข้อผิดพลาดใด ๆ - ฉันแก้ไข 24cell เมื่อไม่กี่ชั่วโมงที่ผ่านมา
เลเวลริเวอร์เซนต์

@TonyRuth vertices ใบหน้าอยู่ในลำดับไม่เฉพาะ (พวกเขาไม่ไปรอบใบหน้าในความรู้สึกตามเข็มนาฬิกาหรืออะไร) สำหรับขนาดที่สูงขึ้นไม่มีคำสั่งมาตรฐาน ไฮเปอร์คิวบ์มีใบหน้าที่เรียงตามลำดับตัวเลขดังนั้นจุดยอดที่ 2 และ 3 นั้นตรงกันข้ามกับแนวทแยงมุม (คุณจะต้องสลับจุดยอดที่ 1 และ 2 หรือ 3 และที่ 4 หากคุณต้องการให้อยู่ในความรู้สึกตามเข็มนาฬิกา / ทวนเข็มนาฬิกา) dodecahedron ควรมีใบหน้า ตามเข็มนาฬิกา / ทวนเข็มนาฬิกาลำดับ แต่ 120 เซลล์จะมีจุดยอดใบหน้าในคำสั่งซื้อใด ๆ และทั้งหมด
เลเวลริเวอร์เซนต์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.