Sum the Vertex Connections

14

1

Let's say you have a positive integer N. First, build a regular polygon, that has N vertices, with the distance between neighbouring vertices being 1. Then connect lines from every vertex, to every other vertex. Lastly, calculate the length of all lines summed up together.

Example

Given the input N = 6, build a hexagon with lines connecting every vertex with the other vertices.

Hexagon

As you can see, there are a total of 6 border lines (length=1), 3 lines that have double the border length (length=2) and 6 other lines that we, by using the Pythagoras Theorem, can calculate the length for, which is

If we add the lengths of the lines together we get (6 * 1) + (3 * 2) + (6 * 1.732) = 22.392.

Additional Information

As structures with 2 or less vertices are not being considered polygons, output 0 (or NaN, since distance between a single vertex doesn't make much sense) for N = 1, since a single vertice cannot be connected to other vertices, and 1 for N = 2, since two vertices are connected by a single line.

Input

An integer N, in any reasonable format.

Output

The length of all the lines summed up together, accurate to at least 3 decimal places, either as a function return or directly printed to stdout.

Rules

  • Standard loopholes are forbidden.
  • This is , so the shortest code in bytes, in any language, wins.

Good luck!

Test Cases

(Input) -> (Output)
1 -> 0 or NaN
2 -> 1
3 -> 3
5 -> 13.091
6 -> 22.392

Ian H.

Posted 2017-10-23T18:31:15.110

Reputation: 2 431

1Must we really handle 1? My current entry would return nan rather than zero for example, and would just require special casing for it. – Jonathan Allan – 2017-10-23T19:51:40.183

1@JonathanAllan I thought about it after seeing your answer, nan is fine too, as distance between a single vertex doesn't make much sense anyways. – Ian H. – 2017-10-23T19:54:31.730

6You should probably allow errors to be thrown too for n=1 I think. – Jonathan Allan – 2017-10-23T20:03:44.510

It's hard to tell what 3 decimal places of accuracy means without an upper bound for N, since outputs get larger and floats get less precise. – xnor – 2017-10-23T20:16:43.360

@xnor As long as it is precise up to 3 decimal places for any reasonable input N, its fine is the result is less precise for huge numbers. – Ian H. – 2017-10-23T20:26:42.107

@IanH. I'm looking to express pi as a decimal because it may be shorter than importing a library. How many digits should I use? – xnor – 2017-10-23T20:29:10.130

@xnor Depends on how many decimal places your result will have. I don't know your algorithm, but lets say atleast 3 decimal places up to N = 100. – Ian H. – 2017-10-23T20:31:48.437

Answers

13

Python 3 (with sympy),  61 60 58 54  48 bytes

-6 (maybe even -10 if we do not need to handle n=1) thanks to xnor (further trigonometric simplification plus further golfing to handle edge case of 1 and save parentheses by moving a (now unnecessary) float cast).

Hopefully beatable with no 3rd party libraries? Yes!! but Lets get things rolling...

lambda n:1%n*n/2/(1-cos(pi/n))
from math import*

Try it online!

This uses a formula for the sum of the lengths if a polygon is inscribed inside a unit circle, n*cot(pi/2/n)/2 and adjusts the result to one for the side length being one by dividing by the sin of that cord length sin(pi/n).

The first formula is acquired by considering the n-1 cord lengths of all the diagonals emanating from one corner which are of lengths sin(pi/n) (again), sin(2*pi/n), ..., sin((n-1)pi/n). The sum of this is cot(pi/2/n), there are n corners so we multiply by n, but then we've double counted all the cords, so we divide by two.

The resulting n*cot(pi/2/n)/2/sin(pi/n) was then simplified by xnor to n/2/(1-cos(pi/n)) (holding for n>1)

...this (so long as the accuracy is acceptable) now no longer requires sympy over the built-in math module (math.pi=3.141592653589793).

Jonathan Allan

Posted 2017-10-23T18:31:15.110

Reputation: 67 804

2yes! saved 11 bytes. cool formula! – J42161217 – 2017-10-23T19:57:57.443

1It looks like the formula simplifies to n/2/(1-cos(pi/n)). – xnor – 2017-10-23T20:11:52.300

Good spot @xnor (so long as we may output 0.25 for n=1 - but special casing may be shorter too...) – Jonathan Allan – 2017-10-23T20:17:41.530

@JonathanAllan Huh, weird that 1/4 is the result for n=1. It can be patched with 1%n*. Also, parens can be saved by moving the float inside to float(1-cos(pi/n)). I don't know sympy much, but maybe there's an arithmetic way to force a float. – xnor – 2017-10-23T20:24:14.383

@xnor Thanks! (I should have noticed the float move). sympy outputs an expression - e.g. for n=6 no cast results in an expression with a representation 3.0/(-sqrt(3)/2 + 1) - there may well be a shorter way but I don't know it yet. – Jonathan Allan – 2017-10-23T20:34:49.290

@JonathanAllan What about just using import math? It should just give floats. – xnor – 2017-10-23T20:45:08.537

^ – Halvard Hummel – 2017-10-23T20:48:56.197

@xnor Ah, I was already on it - thanks though! (sympy was for cot). – Jonathan Allan – 2017-10-23T20:50:12.127

7

Python, 34 bytes

lambda n:1%n*n/abs(1-1j**(2/n))**2

Try it online!

Uses the formula n/2/(1-cos(pi/n)) simplified from Jonathan Allan. Neil saved 10 bytes by noting that Python can compute roots of unity as fractional powers of 1j.

Python without imports doesn't have built-in trigonometric functions, pi, or e. To make n=1 give 0 rather than 0.25, we prepend 1%n*.

A longer version using only natural-number powers:

lambda n:1%n*n/abs(1-(1+1e-8j/n)**314159265)**2

Try it online!

xnor

Posted 2017-10-23T18:31:15.110

Reputation: 115 687

1Cool as a cucumber. – Jonathan Allan – 2017-10-23T20:57:34.143

37 bytes: lambda n:1%n*n/(1-(1j**(2/n)).real)/2 – Neil – 2017-10-23T21:24:03.093

@Neil Wow, Python can just compute roots of unity. – xnor – 2017-10-23T21:29:10.257

Well, that was the easy bit. I don't know what abs() does though. – Neil – 2017-10-23T21:43:43.333

@Neil it gets the absolute value, hence the norm, i.e. the distance from the origin. – Jonathan Allan – 2017-10-23T21:44:37.337

@Neil I'm using the fact that when z is a unit vector, abs(1-z)**2 == 2*(1-z.real). – xnor – 2017-10-23T21:47:21.680

I see now, because abs(1-z)**2 == 1 - 2*z.real + z.real**2 + z.imag**2. – Neil – 2017-10-23T23:00:29.080

I've added a Python tip: https://codegolf.stackexchange.com/a/146172 although while writing that I noticed that the code only works in Python 3 now because it uses 2/n.

– Neil – 2017-10-24T08:47:10.197

6

MATL, 16 15 bytes

t:=ZF&-|Rst2)/s

Try it online! Or verify all test cases.

This uses a commit which introduced the FFT (Fast Fourier Transform) function, and which predates the challenge by 8 days.

Explanation

The code uses this trick (adapted to MATL) to generate the roots of unity. These give the positions of the vertices as complex numbers, except that the distance between consecutive vertices is not normalized to 1. To solve that, after computing all pairwise distances, the program divides them by the distance between consecutive vertices.

t       % Implicit input, n. Duplicate
:       % Range: [1 2 ... n-1 n]
=       % Isequal, element-wise. Gives [0 0 ... 0 1]
ZF      % FFT. Gives the n complex n-th roots of unity
&-|     % Matrix of pairwise absolute differences
R       % Upper triangular matrix. This avoids counting each line twice.
s       % Sum of each column. The second entry gives the distance between
        % consecutive vertices
t2)/    % Divide all entries by the second entry
s       % Sum. Implicit display

Luis Mendo

Posted 2017-10-23T18:31:15.110

Reputation: 87 464

1this is beautiful – Jonah – 2017-10-26T10:47:13.717

@Jonah Complex numbers FTW :-) – Luis Mendo – 2017-10-26T11:17:23.960

5

Grasshopper, 25 primitives (11 components, 14 wires)

I read a meta post about programs in GH and LabVIEW, and follow similar instructions to measure a visual language.

grasshopper program

Print <null> for N = 0, 1, 2,because Polygon Primitive cannot generate a polygon with 2 or fewer edges and you will get an empty list of lines.

Components from left to right:

  • Side count slider: input
  • Polygon Primitive: draw a polygon on canvas
  • Explode: Explode a polyline into segements and vertices
  • Cross reference: build holistic cross reference between all vertices
  • Line: draw a line between all pairs
  • Delete Duplicate Lines
  • Length of curve
  • (upper) Sum
  • (lower) Division: because Polygon Primitive draws polygon based on radius, we need to scale the shape
  • Multipication
  • Panel: output

rhino screenshot

Keyu Gan

Posted 2017-10-23T18:31:15.110

Reputation: 2 028

4

Mathematica, 26 bytes

uses @Jonathan Allan's formula

N@Cot[Pi/2/#]/2Csc[Pi/#]#&   

Try it online!

-1 byte junghwan min

J42161217

Posted 2017-10-23T18:31:15.110

Reputation: 15 931

-1 byte: N@Cot[Pi/2/#]/2Csc[Pi/#]#& since 1/sin(x) = csc(x) – JungHwan Min – 2017-10-23T21:02:23.130

2.5Csc[x=Pi/#]Cot[x/2]#& – Misha Lavrov – 2017-10-24T00:50:01.610

2

Haskell, 27 bytes

f 1=0
f n=n/2/(1-cos(pi/n))

Try it online!

I just dove into Haskell, so this turns out to be a fair beginner golf (that is, copying the formula from other answers).

I've also tried hard to put $ somewhere but the compiler keeps yelling at me, so this is the best I've got. :P

totallyhuman

Posted 2017-10-23T18:31:15.110

Reputation: 15 378

2

Jelly, 13 12 11 bytes

Uses Jonathan Allan's formula (and thanks to him for saving 2 bytes)

ØP÷ÆẠCḤɓ’ȧ÷

Try it online!

I've always been pretty fascinated with Jelly, but haven't used it much, so this might not be the simplest form.

Jeffmagma

Posted 2017-10-23T18:31:15.110

Reputation: 145

Save a byte by using "argument swapping dyadic chain separation", ɓ, to inline your helper link like so: ØP÷ÆẠCḤɓn1×÷ – Jonathan Allan – 2017-10-24T19:45:39.233

@JonathanAllan oh thanks, I'm still a beginner and knew there probably was a better way than having a new chain but didn't know how to do it – Jeffmagma – 2017-10-24T20:48:36.523

Oh, we can save another by using decrement, , and logical-and, ȧ: ØP÷ÆẠCḤɓ’ȧ÷ :) – Jonathan Allan – 2017-10-24T20:59:32.593

oh wow thanks I hadn't thought of that – Jeffmagma – 2017-10-24T21:07:17.120

1

Javascript (ES6), 36 bytes

n=>1%n*n/2/(1-Math.cos(Math.PI/n))

Port of @JonathanAllan's Python 3 answer

f=n=>1%n*n/2/(1-Math.cos(Math.PI/n))
<input id=i type=number oninput="o.innerText=f(i.value)" /><pre id=o>

Herman L

Posted 2017-10-23T18:31:15.110

Reputation: 3 611