#include <cstdlib>
#include <cmath>
#include <GL/gl.h>

#include "util/Logger.hpp"
#include "util/convert.hpp"
#include "Geom.hpp"
#include "BSP.hpp"

BSP::BSP() {
	front = NULL;
	back = NULL;
}

void BSP::add_triangle(Vector a, Vector b, Vector c, void *material) {
	Triangle t = {a, b, c, material};
	soup.push_back(t);
}

void BSP::add_triangle(Triangle t) {
	soup.push_back(t);
}

int max(int a, int b) {
	return a > b ? a : b;
}

// less ratio - closer to a
Vector split(Vector a, Vector b, float ratio) {
	return a * (1 - ratio) + b * ratio;
}

#define EPSILON 0.005

#define INSIDE(D) ((-EPSILON <= (D)) && ((D) <= EPSILON))
#define BACK(D) ((D) < -EPSILON)
#define FRONT(D) ((D) > EPSILON)

void BSP::scatter_triangle(Triangle t) {
	float ad = dotProduct(t.a - origin, normal); // Signed distance
	float bd = dotProduct(t.b - origin, normal); // to the plane.
	float cd = dotProduct(t.c - origin, normal);

	#define III (INSIDE(ad) && INSIDE(bd) && INSIDE(cd)) // front
	#define IIF (INSIDE(ad) && INSIDE(bd) && FRONT(cd)) // front
	#define IIB (INSIDE(ad) && INSIDE(bd) && BACK(cd)) // back
	#define IFI (INSIDE(ad) && FRONT(bd) && INSIDE(cd)) // front
	#define IFF (INSIDE(ad) && FRONT(bd) && FRONT(cd)) // front
	#define IFB (INSIDE(ad) && FRONT(bd) && BACK(cd)) // split b-c
	#define IBI (INSIDE(ad) && BACK(bd) && INSIDE(cd)) // back
	#define IBF (INSIDE(ad) && BACK(bd) && FRONT(cd)) // split b-c
	#define IBB (INSIDE(ad) && BACK(bd) && BACK(cd)) // back
	#define FII (FRONT(ad) && INSIDE(bd) && INSIDE(cd)) // front
	#define FIF (FRONT(ad) && INSIDE(bd) && FRONT(cd)) // front
	#define FIB (FRONT(ad) && INSIDE(bd) && BACK(cd)) // split a-c
	#define FFI (FRONT(ad) && FRONT(bd) && INSIDE(cd)) // front
	#define FFF (FRONT(ad) && FRONT(bd) && FRONT(cd)) // front
	#define FFB (FRONT(ad) && FRONT(bd) && BACK(cd)) // split a-c, b-c
	#define FBI (FRONT(ad) && BACK(bd) && INSIDE(cd)) // split a-b
	#define FBF (FRONT(ad) && BACK(bd) && FRONT(cd)) // split a-b, b-c
	#define FBB (FRONT(ad) && BACK(bd) && BACK(cd)) // split a-b, a-c
	#define BII (BACK(ad) && INSIDE(bd) && INSIDE(cd)) // back
	#define BIF (BACK(ad) && INSIDE(bd) && FRONT(cd)) // split a-c
	#define BIB (BACK(ad) && INSIDE(bd) && BACK(cd)) // back
	#define BFI (BACK(ad) && FRONT(bd) && INSIDE(cd)) // split a-b
	#define BFF (BACK(ad) && FRONT(bd) && FRONT(cd)) // split a-b, a-c
	#define BFB (BACK(ad) && FRONT(bd) && BACK(cd)) // split a-b, b-c
	#define BBI (BACK(ad) && BACK(bd) && INSIDE(cd)) // back
	#define BBF (BACK(ad) && BACK(bd) && FRONT(cd)) // split a-c, b-c
	#define BBB (BACK(ad) && BACK(bd) && BACK(cd)) // back

	// Expand SPLIT(a, b) into split(t.a, t.b, ad / (ad - bd))
	// ad and bd always have opposite signs, so we do not need the abs().
	#define SPLIT(A, B) split(t.A, t.B, A ## d / (A ## d - B ## d))

	if (III || IIF || IFI || IFF || FII || FIF || FFI || FFF) {
		front->add_triangle(t);
		return;
	}

	if (IIB || IBI || IBB || BII || BIB || BBI || BBB) {
		back->add_triangle(t);
		return;
	}

	if (IFB) { // split b-c
		Vector point_on_bc = SPLIT(b, c);
		front->add_triangle(t.a, t.b, point_on_bc, t.material);
		back->add_triangle(t.a, t.c, point_on_bc, t.material);
		return;
	}

	if (IBF) { // split b-c
		Vector point_on_bc = SPLIT(b, c);
		back->add_triangle(t.a, t.b, point_on_bc, t.material);
		front->add_triangle(t.a, t.c, point_on_bc, t.material);
		return;
	}

	if (FIB) { // split a-c
		Vector point_on_ac = SPLIT(a, c);
		front->add_triangle(t.b, t.a, point_on_ac, t.material);
		back->add_triangle(t.b, t.c, point_on_ac, t.material);
		return;
	}

	if (FFB) { // split a-c, b-c
		Vector point_on_ac = SPLIT(a, c);
		Vector point_on_bc = SPLIT(b, c);
		front->add_triangle(t.a, t.b, point_on_bc, t.material);
		front->add_triangle(t.a, point_on_ac, point_on_bc, t.material);
		back->add_triangle(t.c, point_on_ac, point_on_bc, t.material);
		return;
	}

	if (FBI) { // split a-b
		Vector point_on_ab = SPLIT(a, b);
		front->add_triangle(t.c, t.a, point_on_ab, t.material);
		back->add_triangle(t.c, t.b, point_on_ab, t.material);
		return;
	}

	if (FBF) { // split a-b, b-c
		Vector point_on_ab = SPLIT(a, b);
		Vector point_on_bc = SPLIT(b, c);
		front->add_triangle(t.a, t.c, point_on_bc, t.material);
		back->add_triangle(t.b, point_on_ab, point_on_bc, t.material);
		front->add_triangle(t.a, point_on_ab, point_on_bc, t.material);
		return;
	}

	if (FBB) { // split a-b, a-c
		Vector point_on_ab = SPLIT(a, b);
		Vector point_on_ac = SPLIT(a, c);
		front->add_triangle(t.a, point_on_ab, point_on_ac, t.material);
		back->add_triangle(t.b, point_on_ab, point_on_ac, t.material);
		back->add_triangle(t.c, t.b, point_on_ac, t.material);
		return;
	}

	if (BIF) { // split a-c
		Vector point_on_ac = SPLIT(a, c);
		back->add_triangle(t.b, t.a, point_on_ac, t.material);
		front->add_triangle(t.b, t.c, point_on_ac, t.material);
		return;
	}

	if (BFI) { // split a-b
		Vector point_on_ab = SPLIT(a, b);
		back->add_triangle(t.c, t.a, point_on_ab, t.material);
		front->add_triangle(t.c, t.b, point_on_ab, t.material);
		return;
	}

	if (BFF) { // split a-b, a-c
		Vector point_on_ab = SPLIT(a, b);
		Vector point_on_ac = SPLIT(a, c);
		back->add_triangle(t.a, point_on_ab, point_on_ac, t.material);
		front->add_triangle(t.b, point_on_ab, point_on_ac, t.material);
		front->add_triangle(t.c, t.b, point_on_ac, t.material);
		return;
	}

	if (BFB) { // split a-b, b-c
		Vector point_on_ab = SPLIT(a, b);
		Vector point_on_bc = SPLIT(b, c);
		back->add_triangle(t.a, point_on_ab, point_on_bc, t.material);
		front->add_triangle(t.b, point_on_ab, point_on_bc, t.material);
		back->add_triangle(t.c, t.a, point_on_bc, t.material);
		return;
	}

	if (BBF) { // split a-c, b-c
		Vector point_on_ac = SPLIT(a, c);
		Vector point_on_bc = SPLIT(b, c);
		back->add_triangle(t.a, t.b, point_on_ac, t.material);
		back->add_triangle(t.b, point_on_bc, point_on_ac, t.material);
		front->add_triangle(t.c, point_on_bc, point_on_ac, t.material);
		return;
	}
}

// Recursively divides the soup into two groups (splitting triangles if
// needed), until the soup portions fit the soup_portion size.
// Returns the depth of the tree.
int BSP::subdivide(int soup_portion) {
	if (soup.size() <= soup_portion) {
		// no division needed
		return 0;
	}

	front = new BSP();
	back = new BSP();

	// choose the splitting plane
	int splitter_idx = std::rand() % soup.size();
	base = soup[splitter_idx];
	origin = base.a;
	normal = crossProduct(
		base.b - base.a,
		base.c - base.a
	).normalized();

	// distribute the triangles between front and back soups
	for (int i = 0; i < soup.size(); i++) {
		if (i == splitter_idx) {
			continue;
		}
		scatter_triangle(soup[i]);
	}
	soup.clear();

	return 1 + max(front->subdivide(soup_portion), back->subdivide(soup_portion));
}

Vector closest_point_on_triangle(Vector p0, Vector p1, Vector p2, Vector point) {
    Vector edge0 = p1 - p0;
    Vector edge1 = p2 - p0;
    Vector v0 = p0 - point;

    float a = dotProduct(edge0, edge0);
    float b = dotProduct(edge0, edge1);
    float c = dotProduct(edge1, edge1);
    float d = dotProduct(edge0, v0);
    float e = dotProduct(edge1, v0);

    float det = a * c - b * b;
    float s = b * e - c * d;
    float t = b * d - a * e;

    if (s + t < det) {
        if (s < 0) {
            if (t < 0) {
                if (d < 0) {
                    s = clamp(0, -d / a, 1);
                    t = 0;
                } else {
                    s = 0;
                    t = clamp(0, -e / c, 1);
                }
            } else {
                s = 0;
                t = clamp(0, -e / c, 1);
            }
        } else if (t < 0) {
            s = clamp(0, -d / a, 1);
            t = 0;
        } else {
            float invDet = 1 / det;
            s *= invDet;
            t *= invDet;
        }
    } else {
        if (s < 0) {
            float tmp0 = b + d;
            float tmp1 = c + e;
            if (tmp1 > tmp0) {
                float numer = tmp1 - tmp0;
                float denom = a - 2 * b + c;
                s = clamp(0, numer / denom, 1);
                t = 1 - s;
            } else {
                t = clamp(0, -e / c, 1);
                s = 0;
            }
        } else if (t < 0) {
            if (a + d > b + e) {
                float numer = c + e - b - d;
                float denom = a - 2 * b + c;
                s = clamp(0, numer / denom, 1);
                t = 1 - s;
            } else {
                s = clamp(0, -e / c, 1);
                t = 0;
            }
        } else {
            float numer = c + e - b - d;
            float denom = a - 2 * b + c;
            s = clamp(0, numer / denom, 1);
            t = 1 - s;
        }
    }

    return p0 + s * edge0 + t * edge1;
}

// Checks that the angle between triangles (a, b, c1) and (a, b, c2) is sharp.
// This means that points c1 and c2 are standing more or less on the same side
// from the "ab" vector.
bool sharp_angle_between_planes(Vector a, Vector b, Vector c1, Vector c2) {
        // (AB × AC1) · (AB × AC2) > 0
        return dotProduct(
                crossProduct(b - a, c1 - a),
                crossProduct(b - a, c2 - a)
        ) > 0;
}

// Checks that the point is to the inside from each edge of the triangle.
bool point_in_triangle(Vector a, Vector b, Vector c, Vector point) {
        return sharp_angle_between_planes(a, b, c, point)
                && sharp_angle_between_planes(b, c, a, point)
                && sharp_angle_between_planes(a, c, b, point);
}


// Finds out if a unit sphere would hit the triangles transformed by "model"
// matrix. On hit fills in the "push" vector which shows how to push the sphere
// out of the nearest triangle. Increments the "count" with each triangle
// tested.
bool BSP::unit_sphere_hits(Matrix model, Vector center, Vector *push, int *count, std::vector<Triangle> *hitting_triangles) {
	if (front != NULL) {
		// Not a leaf node

		//Matrix normal_matrix = ~model.transposed();
		//for (int i = 0; i < 4; i++) {
		//	normal_matrix(i, 3) = 0;
		//	normal_matrix(3, i) = 0;
		//}
		//normal_matrix(3, 3) = 1;

		//Vector global_normal = (normal_matrix * normal).normalized();
		//Vector global_origin = model * origin;

		// Another way of calculating the normal and origin
		Triangle global_triangle = {model * base.a, model * base.b, model * base.c};
		Vector global_normal = crossProduct(
			global_triangle.b - global_triangle.a,
			global_triangle.c - global_triangle.a
		).normalized();
		Vector global_origin = global_triangle.a;

		// Signed distance
		float d = dotProduct(center - global_origin, global_normal);

		if (d < -1) {
			return back->unit_sphere_hits(model, center, push, count, hitting_triangles);
		}

		if (d > 1) {
			return front->unit_sphere_hits(model, center, push, count, hitting_triangles);
		}

		bool hit = false;
		Vector newpush;

		if (back->unit_sphere_hits(model, center, &newpush, count, hitting_triangles)) {
			if (!hit || (newpush.length2() > push->length2())) {
				*push = newpush;
			}
			hit = true;
		}

		if (front->unit_sphere_hits(model, center, &newpush, count, hitting_triangles)) {
			if (!hit || (newpush.length2() > push->length2())) {
				*push = newpush;
			}
			hit = true;
		}

		(*count)++;
		Vector closest = closest_point_on_triangle(
			model * base.a,
			model * base.b,
			model * base.c,
			center
		);
		Vector from_closest = center - closest;
		if (from_closest.length2() < 1) {
			Vector n = from_closest.normalized();
			newpush = n - from_closest;

			hitting_triangles->push_back(base);
			if (!hit || (newpush.length2() > push->length2())) {
				*push = newpush;
			}
			hit = true;
		}

		return hit;
	} else {
		// A leaf node

		*count += soup.size();
		bool hit = false;
		for (int i = 0; i < soup.size(); i++) {
			Vector closest = closest_point_on_triangle(
				model * soup[i].a,
				model * soup[i].b,
				model * soup[i].c,
				center
			);
			Vector from_closest = center - closest;
			if (from_closest.length2() < 1) {
				Vector n = from_closest.normalized();
				Vector newpush = n - from_closest;

				hitting_triangles->push_back(base);
				if (!hit || (newpush.length2() > push->length2())) {
					*push = newpush;
				}
				hit = true;
			}
		}

		return hit;
	}
}

// Finds out if a "from-to" line would hit the triangles transformed by "model"
// matrix. On hit fills in the "hit" vector which shows where the line first
// hit some triangle.  Increments the "count" with each triangle tested.
bool BSP::line_hits(Matrix model, Vector from, Vector to, Vector *hit, void **material, int *count) {
	if (front != NULL) {
		// Not a leaf node

		Triangle global_triangle = {model * base.a, model * base.b, model * base.c};
		Vector global_normal = crossProduct(
			global_triangle.b - global_triangle.a,
			global_triangle.c - global_triangle.a
		).normalized();
		Vector global_origin = global_triangle.a;

		// Signed distance
		float dfrom = dotProduct(from - global_origin, global_normal);
		float dto = dotProduct(to - global_origin, global_normal);

		// Check if it hits before the plane
		if (dfrom < 0) {
			if (back->line_hits(model, from, to, hit, material, count)) {
				return true;
			}
		} else {
			if (front->line_hits(model, from, to, hit, material, count)) {
				return true;
			}
		}

		if (dfrom * dto < 0) {
			// The line goes through the plane
			Vector point_in_plane = split(from, to, dfrom / (dfrom - dto));
			(*count)++;

			// Check if it hits in the plane
			if (point_in_triangle(
				global_triangle.a,
				global_triangle.b,
				global_triangle.c,
				point_in_plane
			)) {
				// The line goes though the base triangle
				*hit = point_in_plane;
				*material = base.material;
				return true;
			}

			// Check if it hits after the plane
			if (dto < 0) {
				if (back->line_hits(model, from, to, hit, material, count)) {
					return true;
				}
			} else {
				if (front->line_hits(model, from, to, hit, material, count)) {
					return true;
				}
			}
		}

		return false;
	} else {
		// A leaf node
		*count += soup.size();

		bool was_hit = false;
		for (int i = 0; i < soup.size(); i++) {
			Vector a = model * soup[i].a;
			Vector b = model * soup[i].b;
			Vector c = model * soup[i].c;

			// Signed distance
			float dfrom = dotProduct(from - a, crossProduct(c - a, b - a));
			float dto = dotProduct(to - a, crossProduct(c - a, b - a));

			if (dfrom * dto < 0) {
				Vector point_in_plane = split(from, to, dfrom / (dfrom - dto));

				// Check if it hits in the plane
				if (point_in_triangle(a, b, c, point_in_plane)) {
					// The line goes though the triangle
					if (was_hit) {
						if ((*hit - from).length2() > (point_in_plane - from).length2()) {
							// The new intersection point is closer than the last one
							*hit = point_in_plane;
							*material = soup[i].material;
						}
					} else {
						*hit = point_in_plane;
						*material = soup[i].material;
						was_hit = true;
					}
				}
			}
		}

		return was_hit;
	}
}

bool same_triangles(Triangle a, Triangle b) {
	return ((a.a - b.a).length2() < EPSILON)
		&& ((a.b - b.b).length2() < EPSILON)
		&& ((a.c - b.c).length2() < EPSILON);
}

bool triangle_in_vector(Triangle a, std::vector<Triangle> *v) {
	for (int i = 0; i < v->size(); i++) {
		if (same_triangles(a, (*v)[i])) {
			return true;
		}
	}
	return false;
}

void BSP::render(Matrix model, Vector eyepos, float range) {
	glEnable(GL_DEPTH_TEST);
	if (front != NULL) {
		Triangle global_triangle = {model * base.a, model * base.b, model * base.c};
		Vector global_normal = crossProduct(
			global_triangle.b - global_triangle.a,
			global_triangle.c - global_triangle.a
		).normalized();
		Vector global_origin = global_triangle.a;

		// Signed distance
		float d = dotProduct(eyepos - global_origin, global_normal);

		if (fabsf(d) < range) {
			glBegin(GL_TRIANGLES);
				glColor3f(((size_t)this % 97) / 97.0 / 2 + 0.5, ((size_t)this % 1243) / 1243 / 2 + 0.5, ((size_t)this % 243) / 243.0 / 2 + 0.5);
				glVertex3f(base.a.x, base.a.y, base.a.z);
				glColor3f(((size_t)this % 123) / 123.0 / 2 + 0.5, ((size_t)this % 1321) / 1321 / 2 + 0.5, ((size_t)this % 243) / 243.0 / 2 + 0.5);
				glVertex3f(base.b.x, base.b.y, base.b.z);
				glColor3f(((size_t)this % 54) / 54.0 / 2 + 0.5, ((size_t)this % 625) / 625 / 2 + 0.5, ((size_t)this % 572) / 572.0 / 2 + 0.5);
				glVertex3f(base.c.x, base.c.y, base.c.z);
			glEnd();
		}
		if (d > -range) {
			front->render(model, eyepos, range);
		}
		if (d < range) {
			back->render(model, eyepos, range);
		}
	} else {
		glBegin(GL_TRIANGLES);
		for (int i = 0; i < soup.size(); i++) {
			glColor3f(((size_t)this % 97) / 97.0 / 2, ((size_t)this % 1243) / 1243.0 / 2, ((size_t)this % 243) / 243.0 / 2);
			glVertex3f(soup[i].a.x, soup[i].a.y, soup[i].a.z);
			glColor3f(((size_t)this % 123) / 123.0 / 2, ((size_t)this % 1321) / 1321 / 2, ((size_t)this % 243) / 243.0 / 2);
			glVertex3f(soup[i].b.x, soup[i].b.y, soup[i].b.z);
			glColor3f(((size_t)this % 54) / 54.0 / 2, ((size_t)this % 625) / 625 / 2, ((size_t)this % 572) / 572.0 / 2);
			glVertex3f(soup[i].c.x, soup[i].c.y, soup[i].c.z);
		}
		glEnd();
	}
}

BSP::~BSP() {
	if (front != NULL) {
		delete front;
	}
	if (back != NULL) {
		delete back;
	}
}

Talks

Year:
Author:
Level:
  1. Miniakhmetova M.S., Zymbler M.L.
    An Approach to Personalized Video Summarization Based on User Preferences Analysis. 9th International Conference on Application of Information and Communication Technologies, AICT 2015 (Rostov-on-Don, Russia, October 14-16, 2015).
  2. Rechkalov T.V., Zymbler M.L.
    Accelerating Medoids-based Clustering with the Intel Many Integrated Core Architecture. 9th International Conference on Application of Information and Communication Technologies, AICT 2015 (Rostov-on-Don, Russia, October 14-16, 2015).
  3. Movchan A.V., Zymbler M.L.
    Time Series Subsequence Similarity Search under Dynamic Time Warping Distance on the Intel Many-core Accelerators. 8th International Conference on Similarity Search and Applications, SISAP 2015 (Glasgow, Scotland, UK, October 12-14, 2015).
  4. Мовчан А.В., Цымблер М.Л.
    Параллельный алгоритм поиска локально похожих подпоследовательностей временного ряда для ускорителей на базе архитектуры Intel MIC. Международная научная конференция "Суперкомпьютерные дни в России" (28-29 сентября 2015 г., г. Москва).
  5. Zymbler M.L.
    Best-match Time Series Subsequence Search on the Intel Many Integrated Core Architecture. 19th East-European Conference on Advances in Databases and Information Systems, ADBIS 2015 (Poitiers, France, September 8–11, 2015).
  6. Miniakhmetov R.M., Movchan A.V., Zymbler M.L.
    Accelerating Time Series Subsequence Matching on the Intel Xeon Phi Many-core Coprocessor. MIPRO 2015 - 38th International Convention (Opatija, Croatia, May 25-29, 2015).
  7. Мовчан А.В., Цымблер М.Л.
    Нахождение похожих подпоследовательностей временного ряда с помощью многоядерного сопроцессора Intel Xeon Phi. Международная научная конференция "Параллельные вычислительные технологии 2015" (31 марта – 2 апреля 2015 г., Екатеринбург).
  8. Речкалов Т.В., Цымблер М.Л.
    Подход к интеграции интеллектуального анализа данных и реляционной СУБД на основе таблиц предвычислений. Международная научная конференция "Параллельные вычислительные технологии 2015" (31 марта – 2 апреля 2015 г., Екатеринбург).
  9. Цымблер М.Л., Мовчан А.В.
    Поиск похожих подпоследовательностей временных рядов на сопроцессорах Intel Xeon Phi. Конференция "Большие данные в национальной экономике 2014" (21 октября 2014 г., Москва).
  10. Мовчан А.В., Цымблер М.Л.
    Разработка параллельного алгоритма поиска похожих подпоследовательностей временного ряда для сопроцессора Intel Xeon Phi. Международная научная конференция "Параллельные вычислительные технологии 2014" (1-3 апреля 2014 г., Ростов-на-Дону).
  11. Янцен Д.Д., Цымблер М.Л.
    Алгоритм репрезентативного сэмплинга для параллельных систем баз данных. Международная научная конференция "Параллельные вычислительные технологии 2014" (1-3 апреля 2014 г., Ростов-на-Дону).
  12. Пан К.С., Цымблер М.Л.
    Внедрение фрагментного параллелизма в СУБД с открытым исходным кодом. Конференция ведущих научных сотрудников факультета Вычислительной математики и информатики (2 декабря 2013 г., Челябинск).
  13. Пан К.С., Цымблер М.Л.
    Исследование эффективности параллельной СУБД PargreSQL. Международная суперкомпьютерная конференция "Научный сервис в сети Интернет: все грани параллелизма" (23-28 сентября 2013 г., Новороссийск).
  14. Pan C., Zymbler M.
    Taming Elephants, or How to Embed Parallelism into PostgreSQL. Database and Expert Systems Applications - 24th International Conference, DEXA 2013 (Prague, Czech Republic, August 26-29, 2013).
  15. Pan C., Zymbler M.
    Very Large Graph Partitioning by Means of Parallel DBMS. 17th East-European Conference on Advances in Databases and Information Systems, ADBIS 2013 (Genoa, Italy, September 1-4, 2013).
  16. Миниахметова М.С., Цымблер М.Л.
    Параллельный алгоритм шифрования по ГОСТ 28147-89 на платформе Intel Xeon Phi. Международная научная конференция "Параллельные вычислительные технологии 2013" (Челябинск, 1–5 апреля 2013 г.)
  17. Миниахметов Р.М.
    Подход к распареллеливанию алгоритмических композиций в интеллектуальном анализе данных. Пятая научная конференция аспирантов и докторантов ЮУрГУ. (Челябинск, 8-15 февраля 2013 г.).
  18. Пан К.С., Цымблер М.Л.
    Разбиение сверхбольших графов с помощью реляционной параллельной СУБД. 65 научная конференция профессорско-преподавательского состава, аспирантов и сотрудников ЮУрГУ (Челябинск, 9 апреля - 6 мая 2013 г.).
  19. Pan C.S., Zymbler M.L.
    Elephants Can Split Graphs, or Very Large Graph Partitioning via PargreSQL. Institute of Computer Science of the Heidelberg University, Database Systems Research Group Scientific Seminar (September 6, 2013, Heidelberg, Germany).
  20. Миниахметов Р.М.
    Интеграция алгоритма кластеризации Fuzzy c-Means в СУБД PostgreSQL. 64-я научная конференция профессорско-преподавательского состава ЮУрГУ (Челябинск, 11 апреля - 4 мая 2012 г.).
  21. Zymbler M.L., Pan C.S.
    Development of Parallel DBMS on the Basis of PostgreSQL. Institute of Computer Science of the Heidelberg University, Database Systems Research Group Scientific Seminar (Heidelberg, Germany, May 9, 2012).
  22. Пан К.С., Цымблер М.Л.
    Интеграция параллелизма в свободную СУБД PostgreSQL. Второй Московский суперкомпьютерный форум (МСКФ-2011). (Москва, 26-27 октября 2011 г.).
  23. Пан К.С.
    Разработка параллельной СУБД на основе свободной СУБД PostgreSQL. Международная суперкомпьютерная конференция "Научный сервис в сети Интернет: экзафлопсное будущее" (19-24 сентября 2011 г., Новороссийск).
  24. Miniakhmetov R.
    Integrating Fuzzy c-Means Clustering with PostgreSQL. The Seventh Spring Researchers Colloquium on Databases and Information Systems, SYRCoDIS’2011 (June 2-3, 2011, Moscow, Russia).
  25. Pan С.
    Development of a Parallel DBMS on the Basis of PostgreSQL. The Seventh Spring Researchers Colloquium on Databases and Information Systems, SYRCoDIS’2011 (June 2-3, 2011, Moscow, Russia).
  26. Пан К.С., Цымблер М.Л.
    Архитектура и принципы реализации параллельной СУБД PargreSQL. Международная научная конференция "Параллельные вычислительные технологии (ПаВТ'2011)" (Москва, 28 марта - 1 апреля 2011 г.).
  27. Пан К.С., Цымблер М.Л.
    Проект PargreSQL: разработка параллельной СУБД на основе свободной СУБД PostgreSQL. "Научный сервис в сети Интернет: суперкомпьютерные центры и задачи": Международная научная конференция (Новороссийск, 20-25 сентября 2010 г.).
  28. Пан К.С., Цымблер М.Л.
    Решение задачи анализа рыночной корзины на процессорах Cell. Параллельные вычислительные технологии (ПаВТ'2010). Международная научная конференция (Уфа, 29 марта - 2 апреля 2010 г.).