Skip to content

Commit

Permalink
Unit tests for computation of complex numbers
Browse files Browse the repository at this point in the history
Added a mock class that exposes some of the private functions of the
Mandelcruncher class. This way we can write better unit tests.

New jupyther notebook to calculate the values needed for the complex
number unit tests.
  • Loading branch information
crapp committed Feb 21, 2016
1 parent bff97e3 commit 288b473
Show file tree
Hide file tree
Showing 8 changed files with 475 additions and 7 deletions.
153 changes: 153 additions & 0 deletions notebook/MandelbrotEscapeTime.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 122,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import math\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# set start values\n",
"zstart = np.complex(-2.5,-1.5)\n",
"zend = np.complex(1.0, 1.5)\n",
"\n",
"bailout = np.int(100)\n",
"\n",
"image_width = np.int(50)\n",
"image_height = np.int(50)\n"
]
},
{
"cell_type": "code",
"execution_count": 124,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def calc_complex_pos(xpos, ypos):\n",
" print (zstart + np.complex(xpos * ((zend.real - zstart.real) / image_width), ypos * ((zend.imag - zstart.imag) / image_height)))"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# calc_complex_pos(8, 11)"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# basic mandelbrot escape time algorithm. using a similar approach than in c++ so this is not very pythonic\n",
"def mandelcalc (xpos, ypos, print_mandel=False):\n",
" c = zstart + np.complex(xpos * ((zend.real - zstart.real) / image_width),\n",
" ypos * ((zend.imag - zstart.imag) / image_height))\n",
" z = np.complex(0.0, 0.0)\n",
" print(\"zO \" + str(c))\n",
" # using an extra iterations variable here because this is essentially what we are doing in c++ as well. \n",
" # I am not so sure if this is a good idea though. Having lookedd at a lot of pseudo code for mandelbrot iterations\n",
" # and are versions that support both approaches. \n",
" iterations = 0\n",
" for i in range(bailout):\n",
" z = z*z + c\n",
" if ( abs(z) >= 2.0):\n",
" # print(\"zE \" + str(z))\n",
" break\n",
" iterations += 1\n",
" # print(str(iterations) + \", \", end=\"\",flush=True) # this generates a nice list that we can use with c++ \n",
" print(str(xpos) + \"/\" + str(ypos) + \" Escape time: \" + str(iterations) + \" - Z \" + str(z))\n",
" # print(\"Z: \" + str(z))\n",
" if (print_mandel):\n",
" # easy print ascii mandel\n",
" if (i == bailout):\n",
" print(\"*\", end=\"\",flush=True)\n",
" else:\n",
" print(\".\", end=\"\",flush=True)"
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def continuous_index (its, z):\n",
" print (\"Continuous index \" + str(its + 1 - (math.log(2) / abs(z)) / math.log(2.0)))"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"zO (0.3700000000000001+0.11999999999999988j)\n",
"41/27 Escape time: 55 - Z (2.3637850846657784-2.264372597523388j)\n",
"Continuous index 55.69450318630743\n"
]
}
],
"source": [
"# calculate all complex numbers for the whole range\n",
"for y in range(image_height):\n",
" for x in range(image_width):\n",
" #mandelcalc(x, y)\n",
" pass\n",
" #print(\"\")\n",
"mandelcalc(41, 27)\n",
"continuous_index(55, np.complex(2.3637850846657784, -2.264372597523388))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.1"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
2 changes: 2 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ int main(int argc, char *argv[])
std::cout << "+ Image " << std::to_string(params->xrange) << "x"
<< std::to_string(params->yrange) << std::endl;

// TODO: Using a two dimensional vector is unnecessary. Have a look at
// test_computation.cpp for a better solution.
// create the buffer that holds our data
constants::mandelbuff mandelbuffer;
mandelbuffer.assign(params->yrange, std::vector<constants::Iterations>());
Expand Down
11 changes: 7 additions & 4 deletions src/mandelcruncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,29 @@ Mandelcruncher::Mandelcruncher(constants::mandelbuff &buff,
: buff(buff), params(params)
{
}
Mandelcruncher::~Mandelcruncher() {}
std::tuple<unsigned int, double, double> Mandelcruncher::crunch_mandel_complex(
double x, double y, unsigned int bailout)
double x, double y, unsigned int bailout) const
{
// The Mandelbrot Set algorithm derived from pseudo code
// std::cout << "Calculating [" << x << "/" << y << "]" << std::endl;
unsigned int iterations = 0;
double x0 = x;
double y0 = y;
// std::cout << "zO(" << x << ", " << y << ")" << std::endl;
while (x * x + y * y <= 4.0 && iterations < bailout) {
double x_old = x;
x = x * x - y * y + x0;
y = 2 * x_old * y + y0;
iterations++;
}
// std::cout << "Iter: " << iterations << " zE(" << x << ", " << y << ")"
// << std::endl;
return std::make_tuple(iterations, x, y);
}

Mandelcruncher::~Mandelcruncher() {}
constants::Iterations Mandelcruncher::iterations_factory(unsigned int its,
double Zx, double Zy)
double Zx,
double Zy) const
{
constants::Iterations it;
if (this->params->col_algo == constants::COL_ALGO::ESCAPE_TIME)
Expand Down
4 changes: 2 additions & 2 deletions src/mandelcruncher.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Mandelcruncher
* the Complex Number.
*/
std::tuple<unsigned int, double, double> crunch_mandel_complex(
double x, double y, unsigned int bailout);
double x, double y, unsigned int bailout) const;
/**
* @brief Returns an Iterations object based on the coloring algorithm
*
Expand All @@ -68,7 +68,7 @@ class Mandelcruncher
* @return Mandelbrot Set Buffer tuple
*/
constants::Iterations iterations_factory(unsigned int its, double Zx,
double Zy);
double Zy) const;

private:
};
Expand Down
14 changes: 13 additions & 1 deletion src/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
set(UNIT_HEADER
${CMAKE_CURRENT_SOURCE_DIR}/mandelcruncher_mock.h
)

set(UNIT_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/test_main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_commandline.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_computation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mandelcruncher_mock.cpp
)

set (MAIN_HEADER_TEST
${CMAKE_CURRENT_SOURCE_DIR}/../global.h
${CMAKE_CURRENT_SOURCE_DIR}/../main_helper.h
${CMAKE_CURRENT_SOURCE_DIR}/../mandelcruncher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../mandelparams.h
${CMAKE_CURRENT_SOURCE_DIR}/../mandelzoom.h
)

set (MAIN_SOURCE_TEST
${CMAKE_CURRENT_SOURCE_DIR}/../mandelcruncher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../mandelzoom.cpp
)

add_executable(geomandel_tests ${UNIT_SOURCE} ${MAIN_HEADER_TEST} ${MAIN_SOURCE_TEST})
add_executable(geomandel_tests
${UNIT_HEADER}
${UNIT_SOURCE}
${MAIN_HEADER_TEST}
${MAIN_SOURCE_TEST})
# target_link_libraries(geomandel_tests ${CMAKE_THREAD_LIBS_INIT})
40 changes: 40 additions & 0 deletions src/test/mandelcruncher_mock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
This file is part of geomandel. Mandelbrot Set infused by GeoTIFF
Copyright © 2015, 2016 Christian Rapp
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "mandelcruncher_mock.h"

MandelcruncherMock::MandelcruncherMock(
constants::mandelbuff &buff, const std::shared_ptr<MandelParameters> &params)
: Mandelcruncher(buff, params)
{
}

MandelcruncherMock::~MandelcruncherMock() {}
void MandelcruncherMock::fill_buffer() {}
std::tuple<unsigned int, double, double> MandelcruncherMock::test_cruncher(
double real, double ima, unsigned int bailout) const
{
return this->crunch_mandel_complex(real, ima, bailout);
}

constants::Iterations MandelcruncherMock::test_iterfactory(unsigned int its,
double z_real,
double z_ima) const
{
return this->iterations_factory(its, z_real, z_ima);
}
43 changes: 43 additions & 0 deletions src/test/mandelcruncher_mock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
This file is part of geomandel. Mandelbrot Set infused by GeoTIFF
Copyright © 2015, 2016 Christian Rapp
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MANDELCRUNCHER_MOCK_H
#define MANDELCRUNCHER_MOCK_H

#include <tuple>

#include "mandelcruncher.h"

class MandelcruncherMock : public Mandelcruncher
{
public:
MandelcruncherMock(constants::mandelbuff &buff,
const std::shared_ptr<MandelParameters> &params);
virtual ~MandelcruncherMock();

void fill_buffer();
std::tuple<unsigned int, double, double> test_cruncher(
double real, double ima, unsigned int bailout) const;
constants::Iterations test_iterfactory(unsigned int its, double z_real,
double z_ima) const;

private:
/* data */
};

#endif /* ifndef MANDELCRUNCHER_MOCK_H */
Loading

0 comments on commit 288b473

Please sign in to comment.