[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[QUIZ] The Smallest Circle (#157

Matthew Moss

2/15/2008 1:20:00 PM

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at <http://
matthew.moss.googlepages.com/home>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone
on Ruby Talk follow the discussion. Please reply to the original
quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=-=-=-

The Smallest Circle
by Matthew Moss

Your task this week sounds simple enough, but may be more difficult
than it first appears. Given a set of points on a plane, your goal is
to find the smallest circle that encloses those points.

You are to provide a function, *encircle*, that takes an array of
points and returns the smallest circle surrounding those points.
Start with the following base code and extend as needed to solve the
problem:

class Point < Struct.new(:x, :y)
def self.random
Point.new(rand, rand)
end

def to_s
"(#{x}, #{y})"
end
end

class Circle < Struct.new(:center, :radius)
def to_s
"{center:#{center}, radius:#{radius}}"
end
end

def encircle(points) # takes array of Point objects
# returns a Circle object
end


I will be running several tests on the submitted solutions, with
various point sets, to see how well they perform at this task. I
recommend you you test your algorithm with a variety of sample sets,
from small sets consisting of just 1-5 points, up to medium and
larger sets, containing a few thousand points.

To generate an array of random points, start with the above code and
add:

def generate_samples(n)
(1..n).map { Point.random }
end


And then you may test your implementation like this:

# encircle 10 random points
puts encircle( generate_samples(10) )


As mentioned, this one may be more difficult than it seems. Feel free
to estimate the smallest circle, if you get stuck on getting the
exact solution.

53 Answers

Horea Raducan

2/15/2008 6:06:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

If one of the points is on the enclosing circle, is that a valid solution ?

Lionel Bouton

2/15/2008 6:27:00 PM

0

Horea Raducan wrote:
> If one of the points is on the enclosing circle, is that a valid solution ?
>
>
I wouldn't care about such details :
the points are defined by floating point coordinates : I'd say that
defining a circle with a center and a radius in floating point which
passes exactly through such points is most often impossible.
There are obvious exceptions like circles with zero radius and some
values where there's no approximation in the computations but these
cases aren't likely to matter here.

Lionel

Matthew Moss

2/15/2008 6:59:00 PM

0

On Feb 15, 1:06 pm, "Horea Raducan" <hradu...@gmail.com> wrote:
> If one of the points is on the enclosing circle, is that a valid solution ?

Yes, points on the circle are considered enclosed.

Which also means that for an input set of one point, your function
should return a circle with that point as its center and a zero
radius.

Alex Shulgin

2/16/2008 1:10:00 PM

0

On Feb 15, 3:19 pm, Matthew D Moss <matthew.m...@gmail.com> wrote:
>
> The Smallest Circle
> by Matthew Moss
>
> Your task this week sounds simple enough, but may be more difficult
> than it first appears. Given a set of points on a plane, your goal is
> to find the smallest circle that encloses those points.
>
> You are to provide a function, *encircle*, that takes an array of
> points and returns the smallest circle surrounding those points.
> Start with the following base code and extend as needed to solve the
> problem:
>
> class Point < Struct.new(:x, :y)
> def self.random
> Point.new(rand, rand)
> end

May I propose a bit refined random method?

class Point < Struct.new(:x, :y)
def self.random
Point.new(0.5 - rand, 0.5 - rand)
end

This should give us negative coordinates as well. :-)

--
Cheers and welcome new quizmasters!
Alex

John Joyce

2/16/2008 9:21:00 PM

0

Interesting, the numbering is continuing from Ruby Quiz ?
Not starting at 1???

SUGGESTION: I don't have time to do this quiz, but it looks like fun.
I for one would encourage anybody to do it with some visual
representation! (suggested libs: RMagick, Gosu, Rubygame, Ruby/SDL,
etc...)
An audio representation could be interesting as well (perhaps a sort
of sonar?)

Todd Benson

2/16/2008 11:22:00 PM

0

On Feb 16, 2008 3:21 PM, John Joyce <dangerwillrobinsondanger@gmail.com> wrote:
> Interesting, the numbering is continuing from Ruby Quiz ?
> Not starting at 1???
>
> SUGGESTION: I don't have time to do this quiz, but it looks like fun.

I also would love to do this one, but am on vacation :)

I hope there's someone out there that supplies a multidimensional
solution (something that gives the user a choice of the dimensional
space; 3-D, 4-D, etc).

> I for one would encourage anybody to do it with some visual
> representation! (suggested libs: RMagick, Gosu, Rubygame, Ruby/SDL,
> etc...)
> An audio representation could be interesting as well (perhaps a sort
> of sonar?)

Those would be pretty interesting.

Todd

Matthew Moss

2/17/2008 3:24:00 AM

0

> May I propose a bit refined random method?
>
> =A0 =A0 =A0class Point < Struct.new(:x, :y)
> =A0 =A0 =A0 =A0 =A0def self.random
> =A0 =A0 =A0 =A0 =A0 =A0 =A0Point.new(0.5 - rand, 0.5 - rand)
> =A0 =A0 =A0 =A0 =A0end
>
> This should give us negative coordinates as well. :-)


Sure, but your algorithm should work with any set of random points,
whether they fit in the unit square from 0 to 1, -0.5 to 0.5, or
coordinates outside the unit square.

Bill Kelly

2/17/2008 7:00:00 AM

0


From: "John Joyce" <dangerwillrobinsondanger@gmail.com>
>
> SUGGESTION: I don't have time to do this quiz, but it looks like fun.
> I for one would encourage anybody to do it with some visual
> representation! (suggested libs: RMagick, Gosu, Rubygame, Ruby/SDL,
> etc...)

Here's an OpenGL/GLUT-based visualizer for the quiz:

http://tastyspleen.net/~billk/ruby/quiz/157-smallest-circle/157_smallest_circle_visual...

The visualizer is designed to run with any quiz solution that
provides the encircle() and generate_samples(n) methods at
outer scope.


A screenshot for those curious, but not curious enough to actually
try installing ruby OpenGL bindings ... <grin>

http://tastyspleen.net/~billk/ruby/quiz/157-smallest-circle/1...


NOTE: I've only tried this program on ruby 1.8.4 so far... I have
no idea if it might run on 1.9 ...

Also... I believe I'm using yoshi's opengl-0.32f bindings. I haven't
tried it with the very latest ruby/OpenGL bindings on rubyforge.


Regards,

Bill



Alex Shulgin

2/17/2008 8:58:00 AM

0

On Feb 17, 8:59 am, Bill Kelly <bi...@cts.com> wrote:
> From: "John Joyce" <dangerwillrobinsondan...@gmail.com>
>
>
>
> > SUGGESTION: I don't have time to do this quiz, but it looks like fun.
> > I for one would encourage anybody to do it with some visual
> > representation! (suggested libs: RMagick, Gosu, Rubygame, Ruby/SDL,
> > etc...)
>
> Here's an OpenGL/GLUT-based visualizer for the quiz:
>
> http://tastyspleen.net/~billk/ruby/quiz/157-smallest-circle......

I'm trying to utilize gnuplot for visualization. With any luck I can
post the visual part without spoiling the quiz. ;)

Anyone interested?

--
Alex

Frank Fischer

2/17/2008 3:00:00 PM

0

Hi,

here's my solution of this nice quiz. It's heavily inspired by the last
week's quiz, i.e. solving a non-linear equation. This time the program
solves the non-smooth convex optimization problem

min{max{|p_i-x|^2: p_i the given points}: x in R^k},

where k=1,2,3,... (dimension), using a simple subgradient algorithm.
Therefore, it works for an arbitrary number of points
(up to 10000 in about 40s on my 5 year old notebook) and an
arbitrary dimension (number of coordinates) of the points. The solutions
are usually a good approximation of the optimal ones.


================================================================
# extends point-class with an arbitrary dimension
# and simple vector-operations
class Point
def initialize( *coords )
@coords = coords.map{|x| x.to_f}
end

def size
@coords.size
end

def []( index )
@coords[index]
end

def []= ( index, x )
@coords[index] = x
end

def self.random( n = 2 )
Point.new( *(1..n).map{ 0.5 - rand } )
end

def +(p)
return Point.new( *(0...size).map{|i| @coords[i] + p[i]} )
end

def -(p)
return Point.new( *(0...size).map{|i| @coords[i] - p[i]} )
end

def *(a)
return Point.new( *@coords.map{|x| x * a} )
end

def /(a)
return Point.new( *@coords.map{|x| x / a} )
end

# calculate the inner product if this point with p
def ip(p)
(0...size).inject(0) { |sum, i| sum + @coords[i] * p[i] }
end

def to_s
"(#{@coords.join(', ')})"
end
end

class Circle < Struct.new(:center, :radius)
def to_s
"{center:#{center}, radius:#{radius}}"
end
end

def generate_samples(n, dim = 2)
(1..n).map { Point.random(dim) }
end


# calculate value and subgradient of
# f(x,y) = max{(x-x_i)^2 + (y-y_i)^2: (x_i,y_i) in points}
def evaluate( m, points )
y_big = nil
grad = nil
points.each do |p|
d = (m - p)
y = d.ip( d ) # y = sum (m_i-p_i)^2
if y_big.nil? or y > y_big
y_big = y
grad = d*2
end
end

return [y_big, grad]
end

# perform simple subgradient algorithm
# with given starting-point and number of iterations
def encircle( points,
x_start = Point.new( *([0]*points[0].size) ),
max_iter = 100 )
x = x_start
y, g = nil, nil

for k in 1..max_iter do
y, g = evaluate( x, points )
x = x - g/k
end

return Circle.new(x, Math.sqrt(y))
end

puts encircle( generate_samples(10000, 3) )
================================================================

Bye,
Frank