Smallest Integer Disk

Brachylog v2, 19 bytes


Try it online!

This program was easy to write ­– Brachylog's almost perfect for this sort of problem – but hard to golf. It wouldn't surprise me if there was a byte saving somewhere here, as few things I did seemed to have any effect (and it contains nested map instructions, normally a sign that you should be using member/findall, but I can't see a way to do it).

This is a function submission. Input is from the left argument to the function in the format [[x,y],[x,y],…], output from the right argument in the form [r,[[x,y]]]. (If you want to try negative numbers in the input, note that Brachylog uses _ for the minus sign, not -. This is confusing because the function → full program wrapper that Brachylog ships with, requested using the command-line argument Z, will present negative numbers in the output with a regular minus sign.)


;A                   Append something
  z                    to every element of the input
   {       }ᵐ        such that for each resulting element:
     -                 Subtracting
    \ ᵐ                  corresponding elements {of the (input, appended) element}
       ~√              and un-squarerooting
         ᵐ               {the result of} each {subtraction}
          +            and summing {the resulting square numbers}
             ≤       {lets us find} a number at least as large as
              ᵛ        every element {of the list of sums}
               √     which can be square-rooted;
                ;A   append the same list as initially to it.
                  ≜  Find the first integer solution to the above, lexicographically.

This is interesting in that we're asking Brachylog to find a value of certain properties (in this case, the radius of a disk centred at point A that fits all the input points), but hardly placing any requirements on it (all we require is that the radius is a number). However, Brachylog will internally calculate the radius in question symbolically rather than trying to use concrete numbers, so when the final is reached, it accomplishes two things at once: first, it ensures that only integers are used for the coordinates of A and for the radius (forcing the squared radius to be a square number, and explaining the use of ≤ᵛ to find a "maximum or greater"); second, it finds the smallest possible viable radius (as the radius comes first in the output).

One thing that isn't specified in the program at all is that all the points are measured against the same centre of a disk; as written, there are no constraints that we don't use a different centre for each point. However, the tiebreak order (which in this case is set by the third , and which as a structure constraint will be evaluated before the value constraint implied by ) wants A to be as short as possible (i.e. a single element, so we use the same centre each time; it tries a zero-length A first but that obviously doesn't work, so it tries a singleton list next). As a result, we end up getting a useful constraint (that we only have one disk) "for free".

This solution happens to generalise to any number of dimensions, with no changes to the source code; there are no assumptions here that things are two-dimensional. So if you happen to need the smallest integer sphere, you can have that too.

Jelly, 25 24 22 21 20 18 bytes


Thanks to @EriktheOutgolfer for letting me know about ), saving 1 byte.

Thanks to @Dennis for saving 2 bytes.

Try it online!


«/r»/Œpµ³_²§½ṀĊ,)Ṃ      Main link. Arg: points
                        e.g. [[1,4],[3,2],[3,1]]
«/                      Find minimums by coordinate
                        e.g. [1,1]
   »/                   Find maximums by coordinate
                        e.g. [3,4]
  r                     Inclusive ranges by coordinate
                        e.g. [[1,2,3],[1,2,3,4]]
     Œp                 Cartesian product of the x and y ranges
                        e.g. [[1,1],[1,2],[1,3],[1,4],...,[3,4]]
       µ                    Chain, arg: center
                            e.g. [1,3]
        ³                   Get the original points
                            e.g. [[1,4],[3,2],[3,1]]
         _                  Subtract the center from each
                            e.g. [[0,1],[2,-1],[2,-2]]
          ²                 Square each number
                            e.g. [[0,1],[4,1],[4,4]]
           §                Sum each sublist
                            e.g. [1,5,8]
            ½               Square root of each number
                            e.g. [1,2.24,2.83]
             Ṁ              Find the maximum
                            e.g. 2.83
              Ċ             Round up
                            e.g. 3
               ,            Pair with the center point
                            e.g. [3,[1,3]]
                )       Do the above for all points
                        e.g. [[3,[1,1]],[3,[1,2]],[3,[1,3]],...,[3,[3,4]]]
                 Ṃ      Find the lexicographically smallest pair
                        e.g. [3,[1,1]]

Perl 6, 81 bytes

{min [X]([Z]($^p)>>.minmax).map:{${(@_ Z-$_)>>².sum**.5}).max.ceiling,$_}}

Try it online!

Takes a list of points as 2-element lists ((X1, Y1), (X2, Y2), ...). Returns a list (R, (X, Y)). Uses the same approach as Pietu1998's Jelly answer:

[X]([Z]($^p)>>.minmax)  # All possible centers within the bounding box
.map:{ ... }            # mapped to
${(@_ Z-$_)>>².sum**.5}).max  # maximum distance from any point
.ceiling                # rounded up,
,$_                     # paired with center.
min                     # Find minimum by distance.

The minmax method is useful here as it returns a Range. The Cartesian product of ranges directly yields all points with integer coordinates.