Smallest enclosing circle problem: Difference between revisions

Realize in F#
m (→‎{{header|Phix}}: syntax coloured, made p2js compatible)
(Realize in F#)
(3 intermediate revisions by 3 users not shown)
Line 16:
{{trans|Go}}
 
<langsyntaxhighlight lang="11l">T Point = (Float, Float)
 
T Circle
Line 92:
 
L(test) Tests
print(welzl(test))</langsyntaxhighlight>
 
{{out}}
Line 100:
</pre>
 
=={{header|F_Sharp|F#}}==
This task uses [https://rosettacode.org/wiki/Centre_and_radius_of_a_circle_passing_through_3_points_in_a_plane#F# Centre and radius of a circle passing through 3 points in a plane (F#)]
<syntaxhighlight lang="fsharp">
// Smallest enclosing circle problem. Nigel Galloway: February 22nd., 2024
let mcc points=
let fN g=points|>List.map(fun n->(n,d g n))|>List.maxBy snd
let P1,P2=Seq.allPairs points points|>Seq.maxBy(fun(n,g)->d n g)
let c1,r1=let ((nx,ny) as n),((gx,gy) as g)=P1,P2 in (((nx+gx)/2.0,(ny+gy)/2.0),(d n g)/2.0)
match fN c1 with (_,d) when d=r1->(c1,r1)
|(P3,_)->let c2,r2=circ P1 P2 P3
match fN c2 with (_,d) when d=r2->(c2,r2)
|(P4,_)->[circ P1 P3 P4;circ P2 P3 P4]|>List.minBy snd
 
let testMCC n=let centre,radius=mcc n in printfn "Minimum Covering Circle is centred at %A with a radius of %f" centre radius
testMCC [(0.0, 0.0);(0.0, 1.0);(1.0, 0.0)]
testMCC [(5.0, -2.0);(-3.0, -2.0);(-2.0, 5.0);(1.0, 6.0);(0.0, 2.0)]
testMCC [(15.85,6.05);(29.82,22.11);(4.84,20.32);(25.47,29.46);(33.65,17.31);(7.30,10.43);(28.15,6.67);(20.85,11.47);(22.83,2.07);(26.28,23.15);(14.39,30.24);(30.24,25.23)]
testMCC [(15.85,6.05);(29.82,22.11);(4.84,20.32);(25.47,29.46);(33.65,17.31);(7.30,10.43);(28.15,6.67);(20.85,11.47);(22.83,2.08);(26.28,23.15);(14.39,30.24);(30.24,25.23)]
</syntaxhighlight>
{{out}}
<pre>
Minimum Covering Circle is centred at (0.5, 0.5) with a radius of 0.707107
Minimum Covering Circle is centred at (1.0, 1.0) with a radius of 5.000000
Minimum Covering Circle is centred at (18.97851566, 16.2654108) with a radius of 14.708624
Minimum Covering Circle is centred at (18.97952365, 16.27401209) with a radius of 14.707010
</pre>
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 230 ⟶ 256:
fmt.Println(welzl(test))
}
}</langsyntaxhighlight>
 
{{out}}
Line 236 ⟶ 262:
{(0.500000, 0.500000), 0.707107}
{(1.000000, 1.000000), 5.000000}
</pre>
 
=={{header|jq}}==
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
 
'''Adapted from [[#Wren|Wren]]'''
 
In the following, a Point (x,y) is represented by a JSON array [x,y],
and a Circle by a JSON object of the form {center, radius}.
<syntaxhighlight lang="jq">
# Vector sum of the input array of Points
def sum: transpose | map(add);
 
# The square of the distance between two points
def distSq:
def sq: . * .;
. as [$a, $b]
| (($a[0] - $b[0]) | sq) +(($a[1] - $b[1]) | sq) ;
 
# The distance between two points
def distance:
distSq | sqrt;
 
# Does the input Circle contain the point $p?
def contains($p):
([.center, $p] | distSq) <= .radius * .radius;
 
# Does the input Circle contain the given array of points?
def encloses($ps):
. as $c
| all($ps[]; . as $p | $c | contains($p));
 
# The center of a circle defined by 3 points
def getCircleCenter(bx; by; cx; cy):
(bx*bx + by*by) as $b
| (cx*cx + cy*cy) as $c
| (bx*cy - by*cx) as $d
| [(cy*$b - by*$c) / (2 * $d), (bx*$c - cx*$b) / (2 * $d)];
 
# The (smallest) circle that intersects 1, 2 or 3 distinct points
def Circle:
if length == 1 then {center: .[0], radius: 0}
elif length == 2
then {center: (sum | map(./2)),
radius: (distance/2) }
 
elif length == 3
then . as [$a, $b, $c]
| ([getCircleCenter($b[0] - $a[0];
$b[1] - $a[1];
$c[0] - $a[0];
$c[1] - $a[1]), $a] | sum) as $i
| {center: $i, radius: ([$i, $a]|distance)}
else "Circle/0 expects an input array of from 1 to 3 Points" | error
end;
# The smallest enclosing circle for n <= 3
def secTrivial:
. as $rs
| length as $length
| if $length > 3 then "Internal error: secTrivial given more than 3 points." | error
elif $length == 0 then [[0, 0]] | Circle
elif $length <= 2 then Circle
else first(
range(0; 2) as $i
| range($i+1; 3) as $j
| ([$rs[$i], $rs[$j]] | Circle)
| select(encloses($rs)) )
// Circle
end;
 
# Use the Welzl algorithm to find the SEC of the incoming array of points
def welzl:
# Helper function:
# $rs is an array of points on the boundary;
# $n keeps track of how many points remain:
def welzl_($rs; $n):
if $n == 0 or ($rs|length) == 3
then $rs | secTrivial
else 0 as $idx # or Rand($n)
| .[$idx] as $p
| .[$idx] = .[$n-1]
| .[$n-1] = $p
| welzl_($rs; $n-1) as $d
| if ($d | contains($p)) then $d
else welzl_($rs + [$p]; $n-1)
end
end ;
welzl_([]; length);
 
def tests:
[ [0, 0], [0, 1], [1, 0] ],
[ [5, -2], [-3, -2], [-2, 5], [1, 6], [0, 2] ]
;
 
tests
| welzl
| "Circle(\(.center), \(.radius))"
</syntaxhighlight>
{{output}}
<pre>
Circle([0.5,0.5], 0.7071067811865476)
Circle([1,1], 5)
</pre>
 
=={{header|Julia}}==
N-dimensional solution using the Welzl algorithm. Derived from the BoundingSphere.jl module at https://github.com/JuliaFEM. See also Bernd Gärtner's paper at people.inf.ethz.ch/gaertner/subdir/texts/own_work/esa99_final.pdf.
<langsyntaxhighlight lang="julia">import Base.pop!, Base.push!, Base.length, Base.*
using LinearAlgebra, Random
 
Line 411 ⟶ 542:
 
testwelzl()
</langsyntaxhighlight>{{out}}
<pre>
For points: [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0]]
Line 431 ⟶ 562:
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">f=BoundingRegion[#,"MinBall"]&;
f[{{0,0},{0,1},{1,0}}]
f[{{5,-2},{-3,-2},{-2,5},{1,6},{0,2}}]
f[{{2,4,-1},{1,5,-3},{8,-4,1},{3,9,-5}}]
f[{{-0.6400900432782123`,2.643703255134232`,0.4016122094706093`,1.8959601399652273`,-1.1624046608380516`},{0.5632393652621324`,-0.015981105190064373`,-2.193725940351997`,-0.9094586577358262`,0.7165036664470906`},{-1.7704367632976061`,0.2518283698686299`,-1.3810444289625348`,-0.597516704360172`,1.089645656962647`},{1.3448578652803103`,-0.18140877132223002`,-0.4288734015080915`,1.53271973321691`,0.41896461833399573`},{0.2132336397213029`,0.07659442168765788`,0.148636431531099`,2.3386893481333795`,-2.3000459709300927`},{0.6023153188617328`,0.3051735340025314`,1.0732600437151525`,1.1148388039984898`,0.047605838564167786`},{1.3655523661720959`,0.5461416420929995`,-0.09321951900362889`,-1.004771137760985`,1.6532914656050117`},{-0.14974382165751837`,-0.5375672589202939`,-0.15845596754003466`,-0.2750720340454088`,-0.441247015836271`}}]</langsyntaxhighlight>
{{out}}
<pre>Ball[{0.5,0.5},0.707107]
Line 445 ⟶ 576:
{{trans|Go}}
{{trans|Wren}}
<langsyntaxhighlight Nimlang="nim">import math, random, strutils
 
type
Line 546 ⟶ 677:
 
for test in Tests:
echo welzl(test)</langsyntaxhighlight>
 
{{out}}
Line 554 ⟶ 685:
=={{header|Phix}}==
Based on the same code as Wren, and likewise limited to 2D circles - I believe (but cannot prove) the main barrier to coping with more than two dimensions lies wholly within the circle_from3() routine.
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">type</span> <span style="color: #000000;">point</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #004600;">true</span> <span style="color: #008080;">end</span> <span style="color: #008080;">type</span>
Line 619 ⟶ 750:
<span style="color: #0000FF;">{{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{-</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}}}</span>
<span style="color: #7060A8;">papply</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">,</span><span style="color: #000000;">welzl</span><span style="color: #0000FF;">)</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 629 ⟶ 760:
{{trans|Python}}
Uses the last test from Julia, however, since that's given more accurately.
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">inf</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1e300</span><span style="color: #0000FF;">*</span><span style="color: #000000;">1e300</span><span style="color: #0000FF;">,</span>
Line 784 ⟶ 915:
<span style="color: #0000FF;">{-</span><span style="color: #000000;">0.14974382165751837</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">0.5375672589202939</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">0.15845596754003466</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">0.2750720340454088</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">0.441247015836271</span><span style="color: #0000FF;">}}}</span>
<span style="color: #7060A8;">papply</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">,</span><span style="color: #000000;">welzl</span><span style="color: #0000FF;">)</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 810 ⟶ 941:
=={{header|Python}}==
{{trans|Julia}}
<langsyntaxhighlight lang="python">import numpy as np
 
class ProjectorStack:
Line 969 ⟶ 1,100:
print(" Center is at: ", nsphere.center)
print(" Radius is: ", np.sqrt(nsphere.sqradius), "\n")
</langsyntaxhighlight>{{out}}
<pre>
For points: [[0. 0.]
Line 1,006 ⟶ 1,137:
=={{header|Raku}}==
{{trans|Go}}
<syntaxhighlight lang="raku" perl6line>class P { has ($.x, $.y) is rw; # Point
method gist { "({$.x~", "~$.y})" }
}
Line 1,072 ⟶ 1,203:
}
 
say "Solution for smallest circle enclosing {$_.gist} :\n", welzl $_ for @tests;</langsyntaxhighlight>
{{out}}
<pre>Solution for smallest circle enclosing ((0, 0) (0, 1) (1, 0)) :
Line 1,084 ⟶ 1,215:
 
It is based on Welzl's algorithm and follows closely the C++ code [https://www.geeksforgeeks.org/minimum-enclosing-circle-set-2-welzls-algorithm/?ref=rp here].
<langsyntaxhighlight ecmascriptlang="wren">import "random" for Random
 
var Rand = Random.new()
Line 1,200 ⟶ 1,331:
]
 
for (test in tests) System.print(Circle.welzl(test))</langsyntaxhighlight>
 
{{out}}
2,172

edits