13
\$\begingroup\$

Definition

An "integer triangle" is one with integer coordinates. For example the following triangle is an integer triangle:

(0, 0), (0, 1), (1, 2) with perimeter 1 + sqrt(2) + sqrt(5) ≈ 4.650.

Task

The goal of this challenge is to count all integer triangles (up to congruence) with perimeter less than n.

Input and Output

The argument will be given as an integer, and the output should be the number of triangles with perimeter strictly less than the argument.

Examples

The smallest integer triangle by perimeter is congruent to

(0, 0), (0, 1), (1, 0) which has perimeter 2 + sqrt(2) ≈ 3.414

The next smallest are:

(0, 0), (0, 1), (1, 2) with perimeter 1 + sqrt(2) + sqrt(5) ≈ 4.650,
(0, 0), (0, 2), (1, 1) with perimeter 2 + 2sqrt(2)          ≈ 4.828,
(0, 0), (0, 2), (1, 0) with perimeter 3 + sqrt(5)           ≈ 5.236, and
(0, 0), (1, 2), (2, 1) with perimeter sqrt(2) + 2sqrt(5)    ≈ 5.886

Test cases:

a(1) = 0
a(2) = 0
a(3) = 0
a(4) = 1
a(5) = 3
a(6) = 5
a(7) = 11
a(8) = 18
a(9) = 29
a(10) = 44
a(12) = 94
a(20) = 738
a(30) = 3756
a(40) = 11875

I have coordinates for each of the triangles in this Gist.

Warnings

Notice that two non-congruent triangles can have the same perimeter:

(0, 0), (0, 3), (3, 0) and (0, 0), (0, 1), (3, 4) both have perimeter 6 + 3sqrt(2).

Also keep in mind that the inequality is strict; the 3-4-5 pythagorean triangle should be counted by a(13), not a(12).

Scoring

This is —the shortest code wins!

\$\endgroup\$
14
  • 4
    \$\begingroup\$ Congratulations on finding an easily-described sequence not in OEIS. \$\endgroup\$ Commented Jan 12, 2018 at 19:06
  • 1
    \$\begingroup\$ I have a draft for a related sequence submitted to the OEIS. \$\endgroup\$ Commented Jan 12, 2018 at 19:09
  • 1
    \$\begingroup\$ (0, 0), (0, 1), (1, 0) has perimeter 2 + sqrt(2) ≈ 3.14 \$\endgroup\$
    – gggg
    Commented Jan 12, 2018 at 20:10
  • 1
    \$\begingroup\$ Yep, degenerate triangles like (0,0), (1,1), (2,2) aren’t counted. \$\endgroup\$ Commented Jan 12, 2018 at 20:59
  • 1
    \$\begingroup\$ Can the input be an integer value in a floating-point type, or does it have to also be of an integral type? \$\endgroup\$
    – Οurous
    Commented Jan 12, 2018 at 23:29

5 Answers 5

7
\$\begingroup\$

Jelly, 28 27 25 23 bytes

pḶŒcÆḊÐfḅı;I$€AṢ€QS€<¹S

Try it online!

How it works

pḶŒcÆḊÐfḅı;I$€AṢ€QS€<¹S  Main link. Argument: n

 Ḷ                       Unlength; yield [0,...,n-1].
p                        Take the Cartesian product of [1,...,n] and [0,...,n-1].
  Œc                     Take all combinations of the resulting pairs.
                         The result are of the form [[a, b], [c, d]].
    ÆḊÐf                 Filter by determinant; keep only pairs of pairs for which
                         the determinant (ad - bc) is non-zero, i.e., those such
                         that [0, 0], [a, b], and [c, d] are not collinear.
        ḅı               Convert each pair [a, b] from base i (imaginary unit) to
                         integer, mapping it to ai + b.
             €           For each pair of complex numbers [p, q]: 
          ;I$              append their forward differences, yielding [p, q, p-q].
              A          Take the absolute value of each resulting complex number.
               Ṣ€        Sort each resulting array of side lengths.
                 Q       Unique; remove duplicates.
                  S€     Take the sum of each array, computing the perimeters.
                    <¹   Compare them with n.
                      S  Take the sum of the resulting Booleans.
\$\endgroup\$
0
4
\$\begingroup\$

Jelly,  38  33 bytes

-1 thanks to Erik the Outgolfer (invert SP¬+÷/E$ by using SẠ>÷/E$ and use ÇÐf rather than ÇÐḟ) -1 thanks to Mr. Xcoder (no need to flatten prior to the sort)
-2 thanks to Mr. Xcoder (S<¥Ðf³L -> S€<³S)
-1 stealing a trick from an earlier revision of Dennis's answer (ṗ2’Œc -> p`⁺’ - more redundant cases but golfier!)

SẠ>÷/E$
p`⁺’ÇÐfµ_/ṭ⁸²S€Ṣµ€Q½S€<³S

A full program taking an integer and printing the result.

Try it online! (too slow to complete test cases 20+ in under 60s)

How?

SẠ>÷/E$ - Link 1, straightLineFromOrigin?: coordinates       i.e. [[a,b],[c,d]]
S       - sum                                                     [a+c,b+d]
 Ạ       - all? (0 if either of a+c or b+d are 0 otherwise 1)      all([a+c,b+d])
      $ - last two links as a monad:
   ÷/   -   reduce by division                                    [a÷c,b÷d]
     E  -   all equal?  (i.e. 1 if on a non-axial straight line)  a÷c==b÷d 
  >     - greater than? (i.e. 1 if not on any line, 0 otherwise)  all([a+c,b+d])>(a÷c==b÷d)

p`⁺’ÇÐḟµ_/ṭ⁸²S€Ṣµ€Q½S€<³S - Main link: integer, n
p`                        - Cartesian product of implicit range(n) with itself
  ⁺                       - repeat (Cartesian product of that result with itself)
   ’                      - decrement (vectorises)
                          -  - i.e. all non-negative lattice point pairs up to x,y=n-1
     Ðf                   - filter keep only if:
    Ç                     -   call last link (1) as a monad
       µ         µ€       - monadic chain for €ach:
        _/                -   reduce with subtraction i.e. [a-c,b-d]
           ⁸              -   chain's left argument, [[a,b],[c,d]]
          ṭ               -   tack                   [[a,b],[c,d],[c-a,d-b]]
            ²             -   square (vectorises)    [[a²,b²],[c²,d²],[(c-a)²,(d-b)²]]
             S€           -   sum €ach               [[a²+b²],[c²+d²],[(c-a)²+(d-b)²]]
                          -    - i.e. the squares of the triangle's edge lengths
               Ṣ          -   sort
                  Q       - de-duplicate (get one of each congruent set of triangles)
                   ½      - square root (vectorises)  - get sides from squares of sides
                    S€    - sum €ach
                       ³  - program's 3rd argument, n
                      <   - less than?
                        S -   sum (number of such triangles)
                          - implicit print
\$\endgroup\$
7
  • \$\begingroup\$ Explanation corrections: [(a+c)×(b+d)] -> (a+c)×(b+d), [c÷a,d÷b] -> [a÷c,b÷d], c÷a==d÷b -> a÷c==b÷d, " c÷a==d÷b -> " a÷c==b÷d. Function. \$\endgroup\$ Commented Jan 13, 2018 at 16:30
  • \$\begingroup\$ Also, nice abuse of nan. \$\endgroup\$ Commented Jan 13, 2018 at 16:31
  • \$\begingroup\$ Thanks. Unfortunately it still needs the SP¬ and does not actually abuse the divide by zero results (I guess that could be explicit with an actual or) \$\endgroup\$ Commented Jan 13, 2018 at 16:41
  • 1
    \$\begingroup\$ Actually, you can replace ¬+ with <. (EDIT: you don't need to replace P with , as you're only using non-negative coordinates.) \$\endgroup\$ Commented Jan 13, 2018 at 16:47
  • \$\begingroup\$ That does not work (7 returns 21 for example) \$\endgroup\$ Commented Jan 13, 2018 at 17:03
3
\$\begingroup\$

JavaScript (ES7), 157 bytes

f=(n,i=n**4,o={})=>i--&&([p,P,q,Q]=[0,1,2,3].map(k=>i/n**k%n|0),!o[k=[a=(H=Math.hypot)(p,P),b=H(p-q,P-Q),c=H(q,Q)].sort()]&a+b+c<n&&(o[k]=P*q!=p*Q))+f(n,i,o)

Test cases

Only small values can be computed with the default stack size of most JS engines.

f=(n,i=n**4,o={})=>i--&&([p,P,q,Q]=[0,1,2,3].map(k=>i/n**k%n|0),!o[k=[a=(H=Math.hypot)(p,P),b=H(p-q,P-Q),c=H(q,Q)].sort()]&a+b+c<n&&(o[k]=P*q!=p*Q))+f(n,i,o)

;[
  1,  // 0
  2,  // 0
  3,  // 0
  4,  // 1
  5,  // 3
  6,  // 5
  7,  // 11
  8,  // 18
  9   // 29
]
.forEach(n => console.log('a(' + n + ') = ' + f(n)))


Non-recursive version, 165 bytes

n=>[...Array(n**4)].reduce((x,_,i,o)=>x+=!o[[p,P,q,Q]=[0,1,2,3].map(k=>i/n**k%n|0),k=[a=(H=Math.hypot)(p,P),b=H(p-q,P-Q),c=H(q,Q)].sort()]&(o[k]=P*q!=p*Q)&a+b+c<n,0)

Test cases

This version also works for a(30) and a(40), but that would take too much time for the snippet.

let f =

n=>[...Array(n**4)].reduce((x,_,i,o)=>x+=!o[[p,P,q,Q]=[0,1,2,3].map(k=>i/n**k%n|0),k=[a=(H=Math.hypot)(p,P),b=H(p-q,P-Q),c=H(q,Q)].sort()]&(o[k]=P*q!=p*Q)&a+b+c<n,0)

;[
  1,  // 0
  2,  // 0
  3,  // 0
  4,  // 1
  5,  // 3
  6,  // 5
  7,  // 11
  8,  // 18
  9,  // 29
  10, // 44
  12, // 94
  20  // 738
]
.forEach(n => console.log('a(' + n + ') = ' + f(n)))

\$\endgroup\$
2
\$\begingroup\$

Julia 0.6, 135 bytes

Iterate over possible non-origin points to make up the triangle, represent them as complex numbers, sort the square lengths and keep them in a set to check for congruence. Avoids colinear points by checking that the angle between their complex numbers is nonzero. Then it returns the length of the set. It's shorter to use the lengths directly, but you get the wrong answer for a(40). The solution is too slow to reach run a(40) because of a deprecation warning, so I have a link to a faster version as well.

n->(q=Set();for x=0:n,y=1:n,a=1:n,b=0:n
r=x+y*im
t=a+b*im
g=sort(abs2.([r,t,r-t]))
sum(√g)<n&&angle(r/t)>0&&push!(q,g)
end;length(q))

Try it online!

Faster, longer version with deprecation avoided. Try it online! Uses sqrt.(g) in place of deprecated √g for elementwise square root.

\$\endgroup\$
1
\$\begingroup\$

Clean, 227 ... 143 bytes

import StdEnv
@n#l=[0.0..n]
=sum[1\\p<-removeDup[sort(map(sqrt o\[u,v]=u*u+v*v)[[a-i,b-j],[a,b],[i,j]])\\a<-l,b<-l,i<-l,j<-l|a*j<>i*b]|sum p<n]

Try it online!

Detects congruent triangles via comparing the three values which sum to make the perimeter, and colinear points by verifying that the two smallest such values do not sum to the third.

Here's a version that uses a faster, more memory-heavy, approach: Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ If I change to Start = @ 12.0 I don't get any output, am I doing something wrong? \$\endgroup\$
    – gggg
    Commented Jan 13, 2018 at 0:17
  • 1
    \$\begingroup\$ @gggg test to your heart's content now \$\endgroup\$
    – Οurous
    Commented Jan 13, 2018 at 0:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.