/*******************************************************************************
**
*A schreier-sims.h A rudimentary Schreier-Sims Julius Jonusas
** James Mitchell
** Wilf A. Wilson
** Michael Young
**
** Copyright (C) 2014-15 - Julius Jonusas, James Mitchell, Wilf A. Wilson,
** Michael Young
**
** This file is free software, see the digraphs/LICENSE.
**
*******************************************************************************/
#include "schreier-sims.h"
// C headers
#include <stdlib.h> // for NULL
#include <string.h> // for memset
// Digraphs package headers
#include "digraphs-debug.h" // for DIGRAPHS_ASSERT
#include "globals.h" // for HOMOS_STRUCTURE_SIZE
#include "safemalloc.h" // for safe_malloc
uint16_t PERM_DEGREE = 0;
// Schreier-Sims set up
SchreierSims* new_schreier_sims(void) {
SchreierSims* ss = safe_malloc(sizeof(SchreierSims));
ss->tmp_perm = new_perm(HOMOS_STRUCTURE_SIZE);
ss->strong_gens =
(PermColl**) safe_calloc(HOMOS_STRUCTURE_SIZE, sizeof(PermColl*));
for (uint16_t i = 0; i < HOMOS_STRUCTURE_SIZE; ++i) {
ss->strong_gens[i] =
new_perm_coll(HOMOS_STRUCTURE_SIZE, HOMOS_STRUCTURE_SIZE);
}
ss->transversal = (Perm*) safe_calloc(
HOMOS_STRUCTURE_SIZE * HOMOS_STRUCTURE_SIZE, sizeof(Perm));
ss->inversal = (Perm*) safe_calloc(
HOMOS_STRUCTURE_SIZE * HOMOS_STRUCTURE_SIZE, sizeof(Perm));
for (size_t i = 0; i < HOMOS_STRUCTURE_SIZE * HOMOS_STRUCTURE_SIZE; ++i) {
ss->transversal[i] = new_perm(HOMOS_STRUCTURE_SIZE);
ss->inversal[i] = new_perm(HOMOS_STRUCTURE_SIZE);
}
ss->base = (uint16_t*) safe_calloc(HOMOS_STRUCTURE_SIZE, sizeof(uint16_t));
ss->orbits = (uint16_t*) safe_calloc(
HOMOS_STRUCTURE_SIZE * HOMOS_STRUCTURE_SIZE, sizeof(uint16_t));
ss->size_orbits =
(uint16_t*) safe_calloc(HOMOS_STRUCTURE_SIZE, sizeof(uint16_t));
ss->orb_lookup = (bool*) safe_calloc(
HOMOS_STRUCTURE_SIZE * HOMOS_STRUCTURE_SIZE, sizeof(bool));
return ss;
}
static void init_ss(SchreierSims* ss, uint16_t degree) {
DIGRAPHS_ASSERT(degree <= HOMOS_STRUCTURE_SIZE);
for (uint16_t i = 0; i < degree; ++i) {
clear_perm_coll(ss->strong_gens[i]);
ss->strong_gens[i]->degree = degree;
}
memset((void*) ss->orb_lookup, false, degree * degree * sizeof(bool));
memset((void*) ss->size_orbits, 0, degree * sizeof(uint16_t));
ss->size_base = 0;
ss->degree = degree;
}
void free_schreier_sims(SchreierSims* ss) {
free(ss->tmp_perm);
for (uint16_t i = 0; i < HOMOS_STRUCTURE_SIZE; ++i) {
free_perm_coll(ss->strong_gens[i]);
}
free(ss->strong_gens);
for (size_t i = 0; i < HOMOS_STRUCTURE_SIZE * HOMOS_STRUCTURE_SIZE; ++i) {
free(ss->transversal[i]);
free(ss->inversal[i]);
}
free(ss->transversal);
free(ss->inversal);
free(ss->base);
free(ss->orbits);
free(ss->size_orbits);
free(ss->orb_lookup);
free(ss);
}
static inline void
add_strong_gen_ss(SchreierSims* ss, uint16_t const pos, Perm const p) {
DIGRAPHS_ASSERT(pos < ss->degree);
add_perm_coll(ss->strong_gens[pos], p);
}
static inline Perm get_strong_gen_ss(SchreierSims const* const ss,
uint16_t const i,
uint16_t const j) {
DIGRAPHS_ASSERT(i < ss->degree);
DIGRAPHS_ASSERT(j < ss->degree);
return ss->strong_gens[i]->perms[j];
}
static inline Perm get_transversal_ss(SchreierSims const* const ss,
uint16_t const i,
uint16_t const j) {
DIGRAPHS_ASSERT(i < ss->degree);
DIGRAPHS_ASSERT(j < ss->degree);
return ss->transversal[i * HOMOS_STRUCTURE_SIZE + j];
}
static inline Perm get_inversal_ss(SchreierSims const* const ss,
uint16_t const i,
uint16_t const j) {
DIGRAPHS_ASSERT(i < ss->degree);
DIGRAPHS_ASSERT(j < ss->degree);
return ss->inversal[i * HOMOS_STRUCTURE_SIZE + j];
}
static inline void add_base_point_ss(SchreierSims* ss, uint16_t const pt) {
ss->base[ss->size_base] = pt;
ss->size_orbits[ss->size_base] = 1;
ss->orbits[ss->size_base * ss->degree] = pt;
ss->orb_lookup[ss->size_base * ss->degree + pt] = true;
id_perm(get_transversal_ss(ss, ss->size_base, pt), ss->degree);
id_perm(get_inversal_ss(ss, ss->size_base, pt), ss->degree);
ss->size_base++;
}
static void
orbit_ss(SchreierSims* ss, uint16_t const depth, uint16_t const init_pt) {
DIGRAPHS_ASSERT(depth <= ss->size_base);
for (uint16_t i = 0; i < ss->size_orbits[depth]; i++) {
uint16_t pt = ss->orbits[depth * ss->degree + i];
for (uint16_t j = 0; j < ss->strong_gens[depth]->size; j++) {
Perm x = ss->strong_gens[depth]->perms[j];
uint16_t img = x[pt];
if (!ss->orb_lookup[depth * ss->degree + img]) {
ss->orbits[depth * ss->degree + ss->size_orbits[depth]] = img;
ss->size_orbits[depth]++;
ss->orb_lookup[depth * ss->degree + img] = true;
prod_perms(get_transversal_ss(ss, depth, img),
get_transversal_ss(ss, depth, pt),
x,
ss->degree);
invert_perm(get_inversal_ss(ss, depth, img),
get_transversal_ss(ss, depth, img),
ss->degree);
}
}
}
}
static void
add_gen_orbit_ss(SchreierSims* ss, uint16_t const depth, Perm const gen) {
DIGRAPHS_ASSERT(depth <= ss->size_base);
// apply the new generator to existing points in ss->orbits[depth]
uint16_t nr = ss->size_orbits[depth];
for (uint16_t i = 0; i < nr; i++) {
uint16_t pt = ss->orbits[depth * ss->degree + i];
uint16_t img = gen[pt];
if (!ss->orb_lookup[depth * ss->degree + img]) {
ss->orbits[depth * ss->degree + ss->size_orbits[depth]] = img;
ss->size_orbits[depth]++;
ss->orb_lookup[depth * ss->degree + img] = true;
prod_perms(get_transversal_ss(ss, depth, img),
get_transversal_ss(ss, depth, pt),
gen,
ss->degree);
invert_perm(get_inversal_ss(ss, depth, img),
get_transversal_ss(ss, depth, img),
ss->degree);
}
}
for (uint16_t i = nr; i < ss->size_orbits[depth]; i++) {
uint16_t pt = ss->orbits[depth * ss->degree + i];
for (uint16_t j = 0; j < ss->strong_gens[depth]->size; j++) {
Perm x = get_strong_gen_ss(ss, depth, j);
uint16_t img = x[pt];
if (!ss->orb_lookup[depth * ss->degree + img]) {
ss->orbits[depth * ss->degree + ss->size_orbits[depth]] = img;
ss->size_orbits[depth]++;
ss->orb_lookup[depth * ss->degree + img] = true;
prod_perms(get_transversal_ss(ss, depth, img),
get_transversal_ss(ss, depth, pt),
x,
ss->degree);
invert_perm(get_inversal_ss(ss, depth, img),
get_transversal_ss(ss, depth, img),
ss->degree);
}
}
}
}
static uint16_t sift_ss(SchreierSims* ss, Perm g) {
uint16_t depth;
for (depth = 0; depth < ss->size_base; depth++) {
uint16_t beta = g[ss->base[depth]];
if (!ss->orb_lookup[depth * ss->degree + beta]) {
return depth;
}
prod_perms(g, g, get_inversal_ss(ss, depth, beta), ss->degree);
}
return depth;
}
static bool perm_fixes_all_base_points(SchreierSims* ss, Perm const x) {
for (uint16_t i = 0; i < ss->size_base; i++) {
if (x[ss->base[i]] != ss->base[i]) {
return false;
}
}
return true;
}
static void run_ss(SchreierSims* ss) {
uint16_t depth = 0;
for (uint16_t j = 0; j < ss->strong_gens[depth]->size; j++) {
Perm x = get_strong_gen_ss(ss, depth, j);
if (perm_fixes_all_base_points(ss, x)) {
for (uint16_t k = 0; k < ss->degree; k++) {
if (k != x[k]) {
add_base_point_ss(ss, k);
break;
}
}
}
}
for (uint16_t i = depth + 1; i < ss->size_base + 1; i++) {
uint16_t beta = ss->base[i - 1];
// set up the strong generators
for (uint16_t j = 0; j < ss->strong_gens[i - 1]->size; j++) {
Perm x = get_strong_gen_ss(ss, i - 1, j);
if (beta == x[beta]) {
add_strong_gen_ss(ss, i, x);
}
}
// find the orbit of <beta> under ss->strong_gens[i - 1]
orbit_ss(ss, i - 1, beta);
}
int i = ss->size_base - 1;
while (i >= (int) depth) {
bool escape = false;
for (uint16_t j = 0; j < ss->size_orbits[i] && !escape; j++) {
uint16_t beta = ss->orbits[i * ss->degree + j];
for (uint16_t m = 0; m < ss->strong_gens[i]->size && !escape; m++) {
Perm x = get_strong_gen_ss(ss, i, m);
prod_perms(
ss->tmp_perm, get_transversal_ss(ss, i, beta), x, ss->degree);
uint16_t betax = x[beta];
if (!eq_perms(
ss->tmp_perm, get_transversal_ss(ss, i, betax), ss->degree)) {
bool y = true;
prod_perms(ss->tmp_perm,
ss->tmp_perm,
get_inversal_ss(ss, i, betax),
ss->degree);
uint16_t jj = sift_ss(ss, ss->tmp_perm);
if (jj < ss->size_base) {
y = false;
} else if (!is_one(ss->tmp_perm, ss->degree)) {
y = false;
for (uint16_t k = 0; k < ss->degree; k++) {
if (k != ss->tmp_perm[k]) {
add_base_point_ss(ss, k);
break;
}
}
}
if (!y) {
for (uint16_t l = i + 1; l <= jj; l++) {
add_strong_gen_ss(ss, l, ss->tmp_perm);
add_gen_orbit_ss(ss, l, ss->tmp_perm);
// add generator to <h> to orbit of ss->base[l]
}
i = jj;
escape = true;
}
}
}
}
if (!escape) {
i--;
}
}
}
void point_stabilizer(SchreierSims* ss,
PermColl* src,
PermColl* dst,
uint16_t const pt) {
init_ss(ss, src->degree);
copy_perm_coll(ss->strong_gens[0], src);
add_base_point_ss(ss, pt);
run_ss(ss);
copy_perm_coll(dst, ss->strong_gens[1]);
}
¤ Dauer der Verarbeitung: 0.6 Sekunden
¤
*© Formatika GbR, Deutschland
|
|