[qfcc] Implement the rest of 3d VGA

With tests.
This commit is contained in:
Bill Currie 2023-09-08 11:15:36 +09:00
parent a299cda463
commit be4405485d
5 changed files with 573 additions and 16 deletions

View file

@ -322,6 +322,21 @@ algebra_init (algebra_t *a)
basis_group_init (&a->groups[4], 1, pga_blades + 11, a, 4);
basis_group_init (&a->groups[5], 4, pga_blades + 12, a, 5);
basis_layout_init (&a->layout, 6, a->groups);
} else if (p == 3 && m == 0 && z == 0) {
// 3d VGA (x y z square to +1):
// : x y z xyz
// : yz zx xy 1
basis_blade_t pga_blades[8] = {
blades[1], blades[2], blades[3], blades[7],
blades[6], blades[5], blades[4], blades[0],
};
a->groups = malloc (sizeof (basis_group_t[4]));
a->mvec_types = alloc_mvec_types (4);
basis_group_init (&a->groups[0], 3, pga_blades + 0, a, 0);
basis_group_init (&a->groups[1], 1, pga_blades + 3, a, 1);
basis_group_init (&a->groups[2], 3, pga_blades + 4, a, 2);
basis_group_init (&a->groups[3], 1, pga_blades + 7, a, 3);
basis_layout_init (&a->layout, 4, a->groups);
} else if (p == 2 && m == 0 && z == 1) {
// 2d PGA (w squares to 0, x y square to +1):
// : yw xw xy 1
@ -533,12 +548,16 @@ static int pga_swaps_3d[16] = {
[0xa] = 1, // e31
[0xd] = 1, // e032
};
static int vga_swaps_3d[8] = {
[0x5] = 1, // e31
};
int
algebra_count_flips (const algebra_t *alg, pr_uint_t a, pr_uint_t b)
{
bool pga_2d = (alg->plus == 2 && alg->minus == 0 && alg->zero == 1);
bool pga_3d = (alg->plus == 3 && alg->minus == 0 && alg->zero == 1);
bool vga_3d = (alg->plus == 3 && alg->minus == 0 && alg->zero == 0);
int swaps = count_flips (a, b);
if (pga_2d) {
swaps += pga_swaps_2d[a];
@ -548,6 +567,10 @@ algebra_count_flips (const algebra_t *alg, pr_uint_t a, pr_uint_t b)
swaps += pga_swaps_3d[a];
swaps += pga_swaps_3d[b];
}
if (vga_3d) {
swaps += vga_swaps_3d[a];
swaps += vga_swaps_3d[b];
}
return swaps;
}
@ -557,6 +580,7 @@ algebra_blade_value (algebra_t *alg, const char *name)
uint32_t dimension = alg->plus + alg->minus + alg->zero;
bool pga_2d = (alg->plus == 2 && alg->minus == 0 && alg->zero == 1);
bool pga_3d = (alg->plus == 3 && alg->minus == 0 && alg->zero == 1);
bool vga_3d = (alg->plus == 3 && alg->minus == 0 && alg->zero == 0);
//FIXME supports only 0-9 (ie, up to 10d)
if (name[0] == 'e' && isdigit(name[1])) {
@ -593,6 +617,9 @@ algebra_blade_value (algebra_t *alg, const char *name)
if (pga_3d) {
swaps += pga_swaps_3d[blade];
}
if (vga_3d) {
swaps += vga_swaps_3d[blade];
}
int sign = 1 - 2 * (swaps & 1);
auto g = alg->layout.group_map[alg->layout.mask_map[blade]];
auto group = &alg->layout.groups[g[0]];

View file

@ -258,6 +258,10 @@ evaluate_constexpr (expr_t *e)
auto opb = get_def (s->opb);
auto opc = get_def (s->opc);
auto inst = opcode_find (s->opcode, s->opa, s->opb, s->opc);
if (!inst) {
print_statement (s);
internal_error (e, "no such instruction");
}
auto ds = codespace_newstatement (&value_codespace);
*ds = (dstatement_t) {
.op = opcode_get (inst),

View file

@ -930,6 +930,88 @@ static pga_func pga2_dot_funcs[4][4] = {
},
};
static void
vga3_x_y_z_dot_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = dot_expr (algebra_mvec_type (alg, 0x08), a, b);
}
static void
vga3_x_y_z_dot_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
}
static void
vga3_x_y_z_dot_xyz (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), a, b);
}
static void
vga3_yz_zx_xy_dot_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
}
static void
vga3_yz_zx_xy_dot_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = neg_expr (dot_expr (algebra_mvec_type (alg, 0x08), a, b));
}
static void
vga3_yz_zx_xy_dot_xyz (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), a, b));
}
static void
vga3_xyz_dot_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), b, a);
}
static void
vga3_xyz_dot_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), b, a));
}
static void
vga3_xyz_dot_xyz (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x08), b, a));
}
static pga_func vga3_dot_funcs[4][4] = {
[0] = {
[0] = vga3_x_y_z_dot_x_y_z,
[1] = vga3_x_y_z_dot_xyz,
[2] = vga3_x_y_z_dot_yz_zx_xy,
[3] = scale_component,
},
[1] = {
[0] = vga3_xyz_dot_x_y_z,
[1] = vga3_xyz_dot_xyz,
[2] = vga3_xyz_dot_yz_zx_xy,
[3] = scale_component,
},
[2] = {
[0] = vga3_yz_zx_xy_dot_x_y_z,
[1] = vga3_yz_zx_xy_dot_xyz,
[2] = vga3_yz_zx_xy_dot_yz_zx_xy,
[3] = scale_component,
},
[3] = {
[0] = scale_component,
[1] = scale_component,
[2] = scale_component,
[3] = scale_component,
},
};
static void
component_dot (expr_t **c, expr_t *a, expr_t *b, algebra_t *algebra)
{
@ -949,6 +1031,12 @@ component_dot (expr_t **c, expr_t *a, expr_t *b, algebra_t *algebra)
if (pga2_dot_funcs[ga][gb]) {
pga2_dot_funcs[ga][gb] (c, a, b, algebra);
}
} else if (p == 3 && m == 0 && z == 0) {
int ga = get_group (get_type (a), algebra);
int gb = get_group (get_type (b), algebra);
if (vga3_dot_funcs[ga][gb]) {
vga3_dot_funcs[ga][gb] (c, a, b, algebra);
}
} else {
internal_error (a, "not implemented");
}
@ -1148,41 +1236,42 @@ static pga_func pga2_wedge_funcs[4][4] = {
};
static void
vga2_x_y_z_wedge_x_y_w (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
vga3_x_y_z_wedge_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[2] = cross_expr (algebra_mvec_type (alg, 0x04), a, b);
}
static void
vga2_x_y_w_wedge_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
vga3_x_y_z_wedge_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = dot_expr (algebra_mvec_type (alg, 0x08), a, b);
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
}
static void
vga2_yz_zx_xy_wedge_x_y_w (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
vga3_yz_zx_xy_wedge_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = dot_expr (algebra_mvec_type (alg, 0x08), a, b);
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
}
static pga_func vga3_wedge_funcs[4][4] = {
[0] = {
[0] = vga3_x_y_z_wedge_x_y_z,
[2] = vga3_x_y_z_wedge_yz_zx_xy,
[3] = scale_component,
},
[1] = {
[3] = scale_component,
},
[2] = {
[0] = vga3_yz_zx_xy_wedge_x_y_z,
[3] = scale_component,
},
[3] = {
[0] = scale_component,
[1] = scale_component,
[2] = scale_component,
[3] = scale_component,
},
[1] = {
[0] = scale_component,
[1] = vga2_x_y_z_wedge_x_y_w,
[2] = vga2_x_y_w_wedge_yz_zx_xy,
},
[2] = {
[0] = scale_component,
[1] = vga2_yz_zx_xy_wedge_x_y_w,
},
[3] = {
},
};
static void
@ -1692,6 +1781,90 @@ static pga_func pga2_geometric_funcs[6][6] = {
},
};
static void
vga3_x_y_z_geom_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = dot_expr (algebra_mvec_type (alg, 0x08), a, b);
c[2] = cross_expr (algebra_mvec_type (alg, 0x04), a, b);
}
static void
vga3_x_y_z_geom_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
}
static void
vga3_x_y_z_geom_xyz (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), a, b);
}
static void
vga3_yz_zx_xy_geom_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = cross_expr (algebra_mvec_type (alg, 0x01), b, a);
c[1] = dot_expr (algebra_mvec_type (alg, 0x02), a, b);
}
static void
vga3_yz_zx_xy_geom_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = neg_expr (dot_expr (algebra_mvec_type (alg, 0x08), a, b));
}
static void
vga3_yz_zx_xy_geom_xyz (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), a, b));
}
static void
vga3_xyz_geom_x_y_z (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[2] = scale_expr (algebra_mvec_type (alg, 0x04), b, a);
}
static void
vga3_xyz_geom_yz_zx_xy (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[0] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x01), b, a));
}
static void
vga3_xyz_geom_xyz (expr_t **c, expr_t *a, expr_t *b, algebra_t *alg)
{
c[3] = neg_expr (scale_expr (algebra_mvec_type (alg, 0x08), b, a));
}
static pga_func vga3_geometric_funcs[6][6] = {
[0] = {
[0] = vga3_x_y_z_geom_x_y_z,
[1] = vga3_x_y_z_geom_xyz,
[2] = vga3_x_y_z_geom_yz_zx_xy,
[3] = scale_component,
},
[1] = {
[0] = vga3_xyz_geom_x_y_z,
[1] = vga3_xyz_geom_xyz,
[2] = vga3_xyz_geom_yz_zx_xy,
[3] = scale_component,
},
[2] = {
[0] = vga3_yz_zx_xy_geom_x_y_z,
[1] = vga3_yz_zx_xy_geom_xyz,
[2] = vga3_yz_zx_xy_geom_yz_zx_xy,
[3] = scale_component,
},
[3] = {
[0] = scale_component,
[1] = scale_component,
[2] = scale_component,
[3] = scale_component,
},
};
static void
component_geometric (expr_t **c, expr_t *a, expr_t *b, algebra_t *algebra)
{
@ -1711,6 +1884,12 @@ component_geometric (expr_t **c, expr_t *a, expr_t *b, algebra_t *algebra)
if (pga2_geometric_funcs[ga][gb]) {
pga2_geometric_funcs[ga][gb] (c, a, b, algebra);
}
} else if (p == 3 && m == 0 && z == 0) {
int ga = get_group (get_type (a), algebra);
int gb = get_group (get_type (b), algebra);
if (vga3_geometric_funcs[ga][gb]) {
vga3_geometric_funcs[ga][gb] (c, a, b, algebra);
}
} else {
internal_error (a, "not implemented");
}

View file

@ -74,6 +74,7 @@ test_progs_dat=\
tools/qfcc/test/vecconst.dat \
tools/qfcc/test/vecinit.dat \
tools/qfcc/test/vecops.dat \
tools/qfcc/test/vga3d.dat \
tools/qfcc/test/voidfor.dat \
tools/qfcc/test/while.dat \
tools/qfcc/test/zerolinker.dat
@ -845,6 +846,16 @@ tools/qfcc/test/vecops.run: $(qfcc_test_run_deps)
include $(vecops_dep) # am--include-marker
r_depfiles_remade += $(vecops_dep)
tools_qfcc_test_vga3d_dat_SOURCES=tools/qfcc/test/vga3d.r
vga3d_obj=$(tools_qfcc_test_vga3d_dat_SOURCES:.r=.o)
vga3d_dep=$(call qcautodep,$(tools_qfcc_test_vga3d_dat_SOURCES))
tools/qfcc/test/vga3d.dat$(EXEEXT): $(vga3d_obj) $(QFCC_DEP)
$(V_QFCCLD)$(QLINK) -o $@ $(vga3d_obj)
tools/qfcc/test/vga3d.run: $(qfcc_test_run_deps)
@$(top_srcdir)/tools/qfcc/test/build-run $@
include $(vga3d_dep) # am--include-marker
r_depfiles_remade += $(vga3d_dep)
tools_qfcc_test_voidfor_dat_SOURCES=tools/qfcc/test/voidfor.r
voidfor_obj=$(tools_qfcc_test_voidfor_dat_SOURCES:.r=.o)
voidfor_dep=$(call qcautodep,$(tools_qfcc_test_voidfor_dat_SOURCES))

336
tools/qfcc/test/vga3d.r Normal file
View file

@ -0,0 +1,336 @@
#include "test-harness.h"
#pragma warn no-vararg-integer
typedef @algebra(float(3,0,0)) VGA;
typedef VGA.group_mask(0x08) scalar_t;
typedef VGA.group_mask(0x01) vector_t;
typedef VGA.group_mask(0x04) bivector_t;
typedef VGA.group_mask(0x02) trivector_t;
typedef union {
VGA.group_mask(0x0c) mvec;
struct {
bivector_t bvec;
scalar_t scalar;
};
} evengrades_t;
typedef union {
VGA.group_mask(0x3) mvec;
struct {
vector_t vec;
trivector_t tvec;
};
} oddgrades_t;
static int
test_wedge (void)
{
scalar_t scalar;
vector_t vec, vecb, vecc, vecd;
bivector_t bvec, bvecb;
trivector_t tvec, tvecb;
@algebra (VGA) {
scalar = 42;
vec = 3*e1 - 2*e2 + 4*e3;
bvec = 11*e23 - 4*e31 + 2*e12;
tvec = 2*e123;
vecb = 5*e1 + 12*e2;
bvecb = 1*e12;
tvecb = 1*e123;
vecc = 5*e1 + 4*e2 - 3*e3;
vecd = e1 + e2 + e3;
}
if (scalar != 42) {
printf ("scalar != 42: %g\n", scalar);
return 1;
}
if ((vec3)vec != '3 -2 4') {
printf ("vec != '3 -2 4': %v\n", vec);
return 1;
}
if ((vec3)bvec != '11 -4 2') {
printf ("bvec != '11 -4 2': %v\n", bvec);
return 1;
}
if ((scalar_t)tvec != 2) {
printf ("tvec != 2: %g\n", (scalar_t)tvec);
return 1;
}
bivector_t a = vecvecb;
if ((vec3)a != '-48 20 46') {
printf ("vec ∧ vecb != '-48 20 46': %v\n", a);
return 1;
}
auto b = avecc;
if ((scalar_t)b != -298) {
printf ("a ∧ vecc != -298: %g\n", (scalar_t)b);
return 1;
}
auto c = bvecd;
if ((scalar_t)c != 0) {
printf ("b ∧ vecd != 0': %g\n", (scalar_t) c);
return 1;
}
a = vecbvec;
if ((vec3)a != '48 -20 -46') {
printf ("vecb ∧ vec != '48 -20 -46': %v\n", a);
return 1;
}
b = vecca;
if ((scalar_t)b != 298) {
printf ("vecc ∧ a != 298: %g\n", (scalar_t)b);
return 1;
}
c = vecdb;
if ((scalar_t)c != 0) {
printf ("vecd ^ b != 0': %g\n", (scalar_t) c);
return 1;
}
c = a(veccvecd);
if ((scalar_t)c != 0) {
printf ("a ∧ (vecc ∧ vecd) != 0': %g\n", (scalar_t) c);
return 1;
}
c = (vecdvecc)a;
if ((scalar_t)c != 0) {
printf ("(vecd ∧ vecc) ∧ a != 0': %g\n", (scalar_t) c);
return 1;
}
return 0;
}
static int
test_dot (void)
{
scalar_t scalar;
vector_t vec, vecb, vecc, vecd;
bivector_t bvec, bvecb;
trivector_t tvec, tvecb;
@algebra (VGA) {
scalar = 42;
vec = 3*e1 - 2*e2 + 4*e3;
bvec = 11*e23 - 4*e31 + 2*e12;
tvec = 8*e123;
vecb = 5*e1 + 12*e2;
bvecb = 1*e12;
tvecb = 1*e123;
vecc = 5*e1 + 4*e2 - 3*e3;
vecd = e1 + e2 + e3;
}
auto a = bvectvec;
if ((vec3)a != '-88 32 -16') {
printf ("bvec • tvec != '-88 32 -16': %v\n", a);
return 1;
}
auto b = vectvec;
if ((vec3)b != '24 -16 32') {
printf ("vec • tvec != '24 -16 32': %v\n", b);
return 1;
}
if (bvecbvec != -141) {
printf ("(bvec • bvec) != -141': %g\n", bvecbvec);
return 1;
}
a = vecbvec;
if ((vec3)a != '-12 -38 -10') {
printf ("vec • bvec != '-12 -38 -10': %v\n", a);
return 1;
}
if (vecvecb != -9) {
printf ("(vec • vecb) != -9': %g\n", vecvecb);
return 1;
}
auto d = tvectvec;
if (d != -64) {
printf ("tvec • tvec != -64: %g\n", a);
return 1;
}
a = tvecbvec;
if ((vec3)a != '-88 32 -16') {
printf ("tvec • vec != '-88 32 -16': %v\n", a);
return 1;
}
b = tvecvec;
if ((vec3)b != '24 -16 32') {
printf ("tvec • vec != '24 -16 32': %v\n", b);
return 1;
}
a = bvecvec;
if ((vec3)a != '12 38 10') {
printf ("bvec • vec != '12 38 10': %v\n", a);
return 1;
}
return 0;
}
static int
test_geom (void)
{
scalar_t scalar;
vector_t vec, vecb, vecc, vecd;
bivector_t bvec, bvecb;
trivector_t tvec, tvecb;
@algebra (VGA) {
scalar = 42;
vec = 3*e1 - 2*e2 + 4*e3;
bvec = 11*e23 - 4*e31 + 2*e12;
tvec = 8*e123;
vecb = 5*e1 + 12*e2;
bvecb = 1*e12;
tvecb = 1*e123;
vecc = 5*e1 + 4*e2 - 3*e3;
vecd = e1 + e2 + e3;
}
if (tvec * tvecb != -8) {
printf ("(tvec * tvecb) != -8': %g\n", tvec * tvecb);
return 1;
}
auto d = bvec * tvec;
if ((vec3)d != '-88 32 -16') {
printf ("bvec * tvec != '-88 32 -16': %v\n", d);
return 1;
}
auto e = vec * tvec;
if ((vec3)e != '24 -16 32') {
printf ("vec * tvec != 0 '24 -16 32': %v\n", e);
return 1;
}
auto f = bvec * bvec;
if (f != -141) {
printf ("bvec * bvec != -141: %g\n", f);
return 1;
}
oddgrades_t odd = { .mvec = vec * bvec };
if ((vec3)odd.vec != '-12 -38 -10' || (scalar_t)odd.tvec != 49) {
printf ("vec * bvec != '-12 -38 -10' 49: %v %g\n",
odd.vec, (scalar_t)odd.tvec);
return 1;
}
evengrades_t even = { .mvec = vec * vecb };
if (even.scalar != -9 || (vec3)even.bvec != '-48 20 46') {
printf ("(vec * vecb) != -9 '-48 20 46': %g %v\n",
even.scalar, even.bvec);
return 1;
}
auto b = tvec * bvec;
if ((vec3)b != '-88 32 -16') {
printf ("tvec * bvec != '-88 32 -16': %v\n", b);
return 1;
}
e = tvec * vec;
if ((vec3)e != '24 -16 32') {
printf ("tvec * vec != '24 -16 32': %v\n", e);
return 1;
}
odd.mvec = bvec * vec;
if ((vec3)odd.vec != '12 38 10' || (scalar_t)odd.tvec != 49) {
printf ("vec * bvec != '12 38 10' 49: %v %g\n",
odd.vec, (scalar_t)odd.tvec);
return 1;
}
return 0;
}
static int
test_basics (void)
{
return 0;
}
int
main (void)
{
if (sizeof (scalar_t) != sizeof (float)) {
printf ("scalar has wrong size: %d\n", sizeof (scalar_t));
return 1;
}
if (sizeof (vector_t) != 4 * sizeof (scalar_t)) {
printf ("vector has wrong size: %d\n", sizeof (vector_t));
return 1;
}
if (sizeof (bivector_t) != 4 * sizeof (scalar_t)) {
printf ("bivector has wrong size: %d\n", sizeof (bivector_t));
return 1;
}
if (sizeof (trivector_t) != sizeof (scalar_t)) {
printf ("trivector has wrong size: %d\n", sizeof (trivector_t));
return 1;
}
if (sizeof (evengrades_t) != 4) {
evengrades_t e;
#define offsetof(s,f) ((int)(&((s*)0).f))
printf ("evengrades has wrong size: %d\n", sizeof (evengrades_t));
printf ("mvec: %d, bvec: %d, scalar: %d\n",
sizeof (e.mvec), sizeof (e.bvec), sizeof (e.scalar));
printf ("mvec: %d, bvec: %d, scalar: %d\n",
offsetof (evengrades_t, mvec), offsetof (evengrades_t, bvec),
offsetof (evengrades_t, scalar));
return 1;
}
if (sizeof (oddgrades_t) != 4) {
oddgrades_t o;
#define offsetof(s,f) ((int)(&((s*)0).f))
printf ("oddgrades has wrong size: %d\n", sizeof (oddgrades_t));
printf ("mvec: %d, vec: %d, tvec: %d\n",
sizeof (o.mvec), sizeof (o.vec), sizeof (o.tvec));
printf ("mvec: %d, vec: %d, tvec: %d\n",
offsetof (oddgrades_t, mvec), offsetof (oddgrades_t, vec),
offsetof (oddgrades_t, tvec));
return 1;
}
if (test_wedge ()) {
printf ("wedge products failed\n");
return 1;
}
if (test_dot ()) {
printf ("dot products failed\n");
return 1;
}
if (test_geom ()) {
printf ("geometric products failed\n");
return 1;
}
if (test_basics ()) {
printf ("basics failed\n");
return 1;
}
return 0; // to survive and prevail :)
}