LAPACK — Linear Algebra PACKage

홈페이지: http://www.netlib.org/lapack/

가장 대표적이고 가잘 빠르다고 소문난 포트란 90 버전으로 작성된 선형 대수 라이브러리.
많은 선형대수 라이브러리들이 LAPACK을 참조하고 있다고함.
LAPACK은 C 바인딩도 자체적으로 지원하며, BLAS 라이브러가 내장되어있음.

LAPACK is written in Fortran 90 and provides routines for solving systems of simultaneous linear equations, least-squares solutions of linear systems of equations, eigenvalue problems, and singular value problems. The associated matrix factorizations (LU, Cholesky, QR, SVD, Schur, generalized Schur) are also provided, as are related computations such as reordering of the Schur factorizations and estimating condition numbers. Dense and banded matrices are handled, but not general sparse matrices. In all areas, similar functionality is provided for real and complex matrices, in both single and double precision.

아래의 코드는 MinGW에서 테스트한 코드이며, 컴파일 방법은 아래와 같음.

gcc sample.c -llapack -lblas -lm -lgfortran

아래는 테스트 코드.

#include<stdio.h>
#define N 3
 
double A[N*N];
double x[N];
 
int main(void)
{
  static int i;
  static long int n=N,inc=1,info,piv[N];
 
  A[0]=1.; A[1]=3.; A[2]=1.;
  A[3]=1.; A[4]=1.;A[5]=-2.;
  A[6]=1.; A[7]=-3.;A[8]=-5.;
  x[0]=3.; x[1]=1.; x[2]=-6.;
 
  printf("N = %d\n",N);
  dgesv_(&n,&inc,A,&n,piv,x,&n,&info);
  for(i=0; i<N; ++i) printf("%lf\n", x[i]);
  return(0);
}

다운로드: 3.4.0

Armadillo – C++ linear algebra library

홈페이지: http://arma.sourceforge.net/

C++ 용 매트릭스 연산 라이브러리. 사용하기 쉽고 빠른것이 장점이다.

Armadillo is an open-source C++ linear algebra library (matrix maths) aiming towards a good balance between speed and ease of use. Integer, floating point and complex numbers are supported, as well as a subset of trigonometric and statistics functions.

이런 느낌의 코드.

mat A = randu(size,size);
mat B = randu(size,size);
...
mat Z = zeros(size,size);

for(int i=0; i<N; ++i)
  Z = A+B;  //  or Z = A+B+C ... etc

다운로드: 2.4.2

librsvg

홈페이지: http://librsvg.sourceforge.net/

벡터 그래픽 포맷 SVG를 취급하는 라이브러리.

In simple terms, librsvg is a component used within software applications to enable support for SVG-format scalable graphics. In contrast to raster formats, scalable vector graphics provide users and artists a way to create, view, and provide imagery that is not limited to the pixel or dot density that an output device is capable of.
Many software developers use the librsvg library to render SVG graphics. It is lightweight and portable, requiring only libxml and libart at a minimum, while providing extra features when used with libcroco, libgsf, and mozilla. It is included as part of the GNOME Desktop, and is licensed under the LGPL license.

다운로드: 2.26.0

cairo & cairomm example

아래의 코드들은 wxWidgets와의 조합이며, wxEVT_PAINT 이벤트내에서 작성하면 될것이다. MinGW로 테스트 되었다.

아래의 코드는 cairo의 경우이다.

wxPaintDC dc(this);

wxRect rect = GetClientRect();

if(rect.width == 0 || rect.height == 0) return;

// RENDER_NATIVE
HWND hWnd = (HWND)this->GetHandle();
HDC hDC = ::GetDC(hWnd);

HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, rect.width, rect.height);
SelectObject(hMemDC, hBitmap); 

cairo_surface_t* surface = cairo_win32_surface_create(hMemDC);
cairo_t* image = cairo_create(surface);

cairo_pattern_t *pat;

pat = cairo_pattern_create_linear (0.0, 0.0,  0.0, 256.0);
cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
cairo_rectangle (image, 0, 0, rect.width, rect.height);
cairo_set_source (image, pat);
cairo_fill (image);
cairo_pattern_destroy (pat);

pat = cairo_pattern_create_radial (115.2, 102.4, 25.6,
							   102.4,  102.4, 128.0);
cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
cairo_set_source (image, pat);
cairo_arc (image, 128.0, 128.0, 76.8, 0, 2 * M_PI);
cairo_fill (image);
cairo_pattern_destroy (pat);

BitBlt(hDC, 0, 0, rect.width, rect.height, hMemDC, 0, 0, SRCCOPY);

DeleteDC(hMemDC);
DeleteObject(hBitmap);

// Because we called ::GetDC make sure we relase the handle
// back to the system or we'll have a memory leak.
::ReleaseDC(hWnd, hDC);

아래의 코드는 cairomm의 경우이다.

wxPaintDC dc(this);

wxRect rect = GetClientRect();

if(rect.width == 0 || rect.height == 0) return;

// RENDER_NATIVE
HWND hWnd = (HWND)this->GetHandle();
HDC hDC = ::GetDC(hWnd);

HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, rect.width, rect.height);
SelectObject(hMemDC, hBitmap); 

Cairo::RefPtr<Context> context;
Cairo::RefPtr<Win32Surface> surface;

surface = Win32Surface::create(hMemDC);
context = Context::create(surface);

// draw background
Cairo::RefPtr<Cairo::LinearGradient> background_gradient_ptr = 
	Cairo::LinearGradient::create (0, 0, rect.width, rect.height);

background_gradient_ptr->add_color_stop_rgb (0, 0.7,0,0);
background_gradient_ptr->add_color_stop_rgb (1, 0.3,0,0);

// Draw a rectangle and fill with gradient
context->set_source (background_gradient_ptr);
context->rectangle (0, 0, rect.width, rect.height);
context->fill();

surface->finish();

BitBlt(hDC, 0, 0, rect.width, rect.height, hMemDC, 0, 0, SRCCOPY);

DeleteDC(hMemDC);
DeleteObject(hBitmap);

// Because we called ::GetDC make sure we relase the handle
// back to the system or we'll have a memory leak.
::ReleaseDC(hWnd, hDC);

libglu 테스트

libglu 라이브러리중 linked list인 ls** 함수들과 hash table인 st_** 함수들을 조합하면 STL의 vector 클래스를 흉내낼 수 있다.
사내 프로젝트에서도 자주 이용하는 편이다.
아래는 mingw로 간단하게 테스트해본 코드이다.

#include <string.h>

#include <util.h>
#include <list.h>
#include <st.h>

typedef struct _child_list {
    int element;
} *child_list;

typedef struct _db {
	char *name;
    int age;
    lsList *child_list;		// linked list
} *db;

st_table *mydb_table;		// hash table

st_strcasehash(string, modulus)
register char *string;
int modulus;
{
    register int val = 0;
    register int c;
    register int c2;
    
    while ((c = *string++) != '\0') {
	if ( c >= 'a' && c <= 'z' ) {
	    // capitaliize c
	    c2 = c - ( 'a' - 'A' );
	} else {
	    c2 = c;
	}
	val = val*997 + c2;
    }

    return ((val < 0) ? -val : val)%modulus;
}

int main(void)
{
	char *name;
	db mydb;
    st_generator *gen;
    char *idx;
    char *key;
	
    mydb_table = st_init_table(strcmp, st_strcasehash);

	// append data
	{
		mydb = malloc(sizeof(struct _db));

		mydb->age = 10;
		name = malloc(sizeof(char)*(strlen("name1")+1));
		sprintf(name, "name1");
		mydb->name = strdup(name);

		mydb->child_list = lsCreate();
		lsNewEnd(mydb->child_list, 1, LS_NH);
		lsNewEnd(mydb->child_list, 2, LS_NH);
		lsNewEnd(mydb->child_list, 3, LS_NH);
		lsNewEnd(mydb->child_list, 4, LS_NH);

		st_insert(mydb_table, strdup(name), (db)mydb);
	}

	
	// append data
	{
		mydb = malloc(sizeof(struct _db));
		mydb->age = 10;
		name = malloc(sizeof(char)*(strlen("name2")+1));
		sprintf(name, "name2");
		mydb->name = strdup(name);

		mydb->child_list = lsCreate();
		lsNewEnd(mydb->child_list, 5, LS_NH);
		lsNewEnd(mydb->child_list, 6, LS_NH);
		lsNewEnd(mydb->child_list, 7, LS_NH);
		lsNewEnd(mydb->child_list, 8, LS_NH);

		st_insert(mydb_table, strdup(name), (db)mydb);
	}

	// display datas
    st_foreach_item(mydb_table, gen, &idx, &mydb) {
		lsGen gen2;
		int data;

		fprintf(stdout, "----> %s\n", mydb->name);

		lsForEachItem(mydb->child_list, gen2, data) {
			fprintf(stdout, "%d ", data);
		}
		fprintf(stdout, "\n");
		fflush(stdout);
	}

	return 0;
}
$ gcc -o test.exe test.c -lglu
$ ./test
----> name2
5 6 7 8 
----> name1
1 2 3 4