Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Challenge: Set-Based Mandelbrot Set Generator

Author  Topic 

Onamuji
Aged Yak Warrior

504 Posts

Posted - 2002-09-04 : 21:42:57
Ok so I'm bored and I came up with this wacky idea to convert my C++ program that generates Mandlebrot sets (wrote it for a chaos theory class back in college) into T-SQL, just for kicks to see if I could do it set-based rather than using loops. So here's what I have so far:

SET NOCOUNT ON

IF ISNULL(OBJECTPROPERTY(OBJECT_ID(N'MBS_Sequences'), N'IsTable'), 0) = 0
BEGIN
CREATE TABLE MBS_Sequences (Value INT NOT NULL PRIMARY KEY)
WHILE (SELECT ISNULL(MAX(Value), -1) FROM MBS_Sequences) < 8192
INSERT INTO MBS_Sequences SELECT ISNULL(MAX(Value), -1) + 1 FROM MBS_Sequences
END

IF OBJECTPROPERTY(OBJECT_ID(N'MBS_Calculate'), N'IsProcedure') = 1 DROP PROCEDURE MBS_Calculate
GO

CREATE PROCEDURE MBS_Calculate
(
@OffsetX DECIMAL(38, 10),
@OffsetY DECIMAL(38, 10),
@ScalePercent DECIMAL(38, 10),
@EscapeValue DECIMAL(38, 10),
@Iterations INT,
@Width INT,
@Height INT
) AS
SET NOCOUNT ON

DECLARE @x INT, @y INT, @i INT, @CX DECIMAL(38, 10), @CY DECIMAL(38, 10), @X1 DECIMAL(38, 10), @X2 DECIMAL(38, 10), @Y1 DECIMAL(38, 10), @Y2 DECIMAL(38, 10), @Value DECIMAL(38, 10)

CREATE TABLE #Mandlebrot (X INT, Y INT, I INT)

SET @x = 0
WHILE @x < @Width
BEGIN
SET @y = 0
WHILE @y < @Height
BEGIN
SET @CX = (CAST(@x AS DECIMAL(38, 10)) - @OffsetX) / @ScalePercent
SET @CY = (@OffsetY - CAST(@y AS DECIMAL(38, 10))) / @ScalePercent
SET @X1 = @CX
SET @Y1 = @CY

SET @i = 0
WHILE @i < @Iterations AND @i <> -1
BEGIN
SET @X2 = POWER(@X1, 2) - POWER(@Y1, 2) + @CX
SET @Y2 = 2.0 * @X1 * @Y1 + @CY
SET @Value = POWER(@X2, 2) + POWER(@Y2, 2)
SET @X1 = @X2
SET @Y1 = @Y2

IF @Value > @EscapeValue
BEGIN
INSERT INTO #Mandlebrot (X, Y, I) VALUES (@x, @y, @i + 1)
SET @i = -1
END
ELSE
SET @i = @i + 1
END

SET @Value = POWER(@X2, 2) + POWER(@Y2, 2)
IF @Value < @EscapeValue INSERT INTO #Mandlebrot (X, Y, I) VALUES (@x, @y, 0)

SET @y = @y + 1
END

SET @x = @x + 1
END

SELECT * FROM #Mandlebrot WHERE I > 1
/*
-- Generic Algorithm
for x = 0; x < @Width
for y = 0; y < @Height
cy = (@OffsetY - y.Value) / @ScalePercent
cx = (x.Value - @OffsetX) / @ScalePercent
x = cx
y = cy

for each k.Value
x1 = x * x - y * y + cx
y1 = 2.0 * x * y + cy
r = x1 * x1 + y1 * y1
x = x1
y = y1

if r > @EscapeValue then k.Value + 1 for x,y
end

if (x1 * x1 + y1 * y1) < @EscapeValue then -1
end
end

-- I was thinking something like
SELECT x.Value AS x, y.Value AS y, CASE ... SOMETHING ... END AS i
FROM (SELECT Value FROM MBS_Sequences WHERE Value BETWEEN 0 AND @Width - 1) AS x,
(SELECT Value FROM MBS_Sequences WHERE Value BETWEEN 0 AND @Height - 1) AS y,
(SELECT Value FROM MBS_Sequences WHERE Value BETWEEN 0 AND @Iterations - 1) AS i,

-- But I couldn't figure out how to sum X1 and X2 when looping through i
*/
GO

EXEC MBS_Calculate 250, 200, 100, 4.0, 100, 320, 240

That will work ... it generates the correct values except its super slow for one but it will probably be slow no matter what ... I just want to see a set-based version of it... I think this would be a great reader challenge If you want to see the C++ code for it and/or the program just email me. Good luck all... I'm gonna be up all night working on this



Edited by - onamuji on 09/06/2002 12:16:50

Arnold Fribble
Yak-finder General

1961 Posts

Posted - 2002-09-05 : 15:40:31
I don't think you can make it completely set-based because you fundamentally cannot replace the recurrence z -> z^2 + c with something that doesn't require a loop.
You can use a UDF to return the count for a point:

CREATE FUNCTION MandPoint(@cx float, @cy float, @imax int)
RETURNS INT
AS
BEGIN
DECLARE @i int, @x float, @y float, @t float
SET @i = 0
SET @x = 0.0
SET @y = 0.0
WHILE @i < @imax BEGIN
SET @t = @x*@x - @y*@y + @cx
SET @y = 2*@x*@y + @cy
SET @x = @t
IF (@x*@x + @y*@y) > 4.0 BREAK
SET @i = @i + 1
END
RETURN CASE WHEN @i = @imax THEN -1 ELSE @i END
END

 
and write the rest in a set-based way generating the x and y coordinates from tally tables, but that's about it.



Edited by - Arnold Fribble on 09/05/2002 15:50:33
Go to Top of Page

Onamuji
Aged Yak Warrior

504 Posts

Posted - 2002-09-06 : 10:13:02
That's such a bummer ... I'm 60% sure it can be done with multiple UPDATE's and SELECT statements

Go to Top of Page

Arnold Fribble
Yak-finder General

1961 Posts

Posted - 2002-09-06 : 10:30:32
Yes, ok, you could generate a temporary table with xpoints*ypoints*maxit rows so that all the rows for a point are 'consecutive' (in the sense that UPDATE sees them together), and use an UPDATE with a few variables to construct each Z(i), and then get the largest iteration for each point. But I wouldn't consider this use of UPDATE to be set-based. And the size of the temporary table will be truly huge!


Go to Top of Page
   

- Advertisement -