https://hal.archives-ouvertes.fr/hal-02398953
Tip revision: c33910a29d53f4e137c225b21a8d59e43327cbf9 authored by Software Heritage on 08 December 2019, 12:26:32 UTC
hal: Deposit 351 in collection hal
hal: Deposit 351 in collection hal
Tip revision: c33910a
Polytope.cpp
#include "Polytope.h"
#include <cmath>
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <ctime>
using namespace std;
using namespace giac;
Polytope::Polytope(string s) {
c_start = std::clock();
verbose = false;
K = CMfield(s);
// options, to speed up process change some of these to false (some depend on each other though)
emb_dim1 = true;
emb_dim2 = true;
check_cycles = true;
check_euler = true;
check_sphere = true;
draw_pics = true;
is_symmetric = true;
isarithmeticitychecked = false;
word_p1.push_back(1); // used if symmetric
word_m1.push_back(-1);
word_123.push_back(1); // used if non-symmmetric
word_123.push_back(2);
word_123.push_back(3);
word_321.push_back(-3);
word_321.push_back(-2);
word_321.push_back(-1);
w1.push_back(1);
w2.push_back(2);
w3.push_back(3);
vecteur ipm;
ipm.push_back(K.onenumber);
ipm.push_back(K.zeronumber);
ipm.push_back(K.onenumber);
ipmin = gen(ipm);
if (K.tag.at(0)=='m') {
int k=1;
bool done = false;
string p_str = "";
while (!done && k<K.tag.size()) {
char te = K.tag.at(k);
done = te=='-';
if (!done) {
p_str = p_str + te;
}
k++;
}
if (!done) {
cerr << "Trouble reading tag" << endl;
exit(1);
}
done = false;
string tnum_str = "";
while (!done && k<K.tag.size()) {
char te = K.tag.at(k);
done = te=='%';
if (!done) {
tnum_str = tnum_str + te;
}
k++;
}
if (!done) {
cerr << "Trouble reading tag" << endl;
exit(1);
}
done = false;
string tden_str = "";
while (k<K.tag.size()) {
tden_str = tden_str + K.tag.at(k);
k++;
}
pval = atoi(p_str.c_str());
tnum = atoi(tnum_str.c_str());
tden = atoi(tden_str.c_str());
cout << "p=" << pval << endl;
cout << "t=" << tnum << "/" << tden << endl;
cout << endl;
}
else {
if (K.tag.at(0)=='t') {
// thompson group
int k=1;
bool done = false;
string p_str = "";
while (!done && k<K.tag.size()) {
char te = K.tag.at(k);
done = (te=='H' || te=='S' || te=='E');
if (!done) {
p_str = p_str + te;
}
k++;
}
if (!done) {
cerr << "Trouble reading tag" << endl;
exit(1);
}
pval = atoi(p_str.c_str());
cout << "p=" << pval << endl;
cout << "T=" << K.tautag << endl;
cout << endl;
}
else {
// should be sporadic...
int k=0;
bool done = false;
string p_str = "";
while (!done && k<K.tag.size()) {
char te = K.tag.at(k);
done = te=='s';
if (!done) {
p_str = p_str + te;
}
k++;
}
if (!done) {
cerr << "Trouble reading tag" << endl;
exit(1);
}
K.tautag = "s";
while (k<K.tag.size()) {
K.tautag = K.tautag + K.tag.at(k);
k++;
}
pval = atoi(p_str.c_str());
cout << "p=" << pval << endl;
cout << "tau=" << K.tautag << endl;
cout << endl;
}
}
};
void Polytope::createGroup() {
if (K.tag.at(0)=='m') {
initMostowGroup();
}
else {
if (K.tag.at(0)=='t') {
initThompsonGroup();
}
else {
initSporadicGroup();
}
}
}
void Polytope::startAlgo() {
cout << "Creating initial prism..." << endl;
Prism A0 = createPrism(e1w,e2w,e3w);
computeVertices(A0);
addFaceOrbit(A0);
// may also want to include its opposite face?
cout << "Expanding family of prisms..." << endl;
expand();
// cout << "Done with function startAlgo()" << endl;
}
void Polytope::initMostowGroup() {
// gen beta = eval(gen("2*sin(pi/"+print_INT_(pval)+")",&ct),1,&ct);
// gen beta_int = convert_interval(beta,K.nd,&ct);
gen zeta = rootof(_cyclotomic(pval,&ct),&ct);
gen zeta_int = convert_interval(zeta,K.nd,&ct);
cout << "zeta interval=" << zeta_int << endl;
cout << "zeta=" << zeta << endl;
gen pol_zeta;
if (operator_equal(simplify(zeta-K.onenumber,&ct),K.zeronumber,&ct) || operator_equal(simplify(zeta+K.onenumber,&ct),K.zeronumber,&ct)) {
pol_zeta=z__IDNT_e-zeta;
}
else {
cout << "Checked, not -1 nor 1" << endl;
pol_zeta = giac::expand(_poly2symb(makesequence(_pmin(zeta,&ct),z__IDNT_e),&ct),&ct);
cout << "min pol of zeta: " << pol_zeta << endl;
if (!K.findInField(pol_zeta,zeta_int,zeta)) {
cerr << "Trouble identifying reflection multiplier in field" << endl;
exit(1);
}
}
cout << "zeta in field: " << zeta << endl;
gen arg_t3 = _simplify(((9*pval+2)*K.onenumber - 2*pval*tnum*K.onenumber/tden)/(4*pval*K.onenumber),&ct);
int arg_t3_num = _numer(arg_t3,&ct).val;
int arg_t3_den = _denom(arg_t3,&ct).val;
arg_t3_num = arg_t3_num % arg_t3_den;
gen t3ro;
if (arg_t3_num==0) {
t3ro = K.onenumber;
}
else {
if (arg_t3_den==2) {
// num must be one
t3ro = -K.onenumber;
}
else {
cout << "arg_t3/2pi: " << arg_t3_num << "/" << arg_t3_den << endl;
t3ro = eval(_pow(makesequence(rootof(_cyclotomic(arg_t3_den,&ct),&ct),arg_t3_num),&ct),&ct);
// t3ro = eval(normal(_pow(makesequence(rootof(_cyclotomic(arg_t3_den,&ct),&ct),arg_t3_num),&ct),&ct),&ct);
}
}
cout << "t3ro=" << t3ro << endl;
gen t3_int = convert_interval(t3ro,K.nd,&ct);
cout << "t3 int: " << t3_int << endl;
gen t3;
if (!operator_equal(t3ro,K.onenumber,&ct)) {
// gen pol_t3ro = giac::expand(_poly2symb(makesequence(_pmin(t3ro,&ct),z__IDNT_e),&ct),&ct);
gen pol_t3ro = giac::expand(_poly2symb(makesequence(_pmin(eval(t3ro,&ct),&ct),z__IDNT_e),&ct),&ct);
cout << "pol_t3ro=" << pol_t3ro << endl;
if (! K.findInField(pol_t3ro,t3_int,t3)) {
cerr << "Trouble identifying tau^3 in field" << endl;
exit(1);
}
}
else {
t3 = K.onenumber;
}
cout << "t3 in field: " << t3 << endl;
gen t3c = K.myconj(t3);
cout << "t3c in field: " << t3c << endl;
/* gen alpha;
if (!operator_equal(beta,K.onenumber,&ct)) {
cout << eval(_pmin(beta,&ct),1,&ct) << endl;
gen pol_beta = giac::expand(_poly2symb(makesequence(_pmin(beta,&ct),z__IDNT_e),&ct),&ct);
cout << "min pol of 1/alpha: " << pol_beta << endl;
if (! K.findInField(pol_beta,beta_int,beta)) {
cerr << "Trouble identifying 1/alpha in field" << endl;
exit(1);
}
alpha = K.inverse(beta);
}
else {
alpha = K.onenumber;
}*/
/* gen phi;
// 2019 Oct 25, changed exp to rootof...
// gen phi_orig = eval(gen("exp(pi*i*"+print_INT_(tnum)+"/"+print_INT_(3*tden)+")",&ct),1,&ct);
int tt = 6*tden;
gen pp = normal(eval(gen("rootof(cyclotomic("+print_INT_(tt)+"))",&ct),1,&ct),&ct);
gen phi_orig = normal(_pow(makesequence(pp,tnum),&ct),&ct);
gen phi_int = convert_interval(phi_orig,K.nd,&ct);
cout << "phi interval=" << phi_int << endl;
// cout << "phi alt=" << phi_alt << endl;
cout << "phi=" << phi_orig << endl;
if (!operator_equal(phi_orig,K.onenumber,&ct)) {
cout << _pmin(phi_orig,&ct) << endl;
gen pol_phi = giac::expand(_poly2symb(makesequence(_pmin(phi_orig,&ct),z__IDNT_e),&ct),&ct);
cout << "min pol of phi: " << pol_phi << endl;
if (!K.findInField(pol_phi,phi_int,phi)) {
cerr << "Trouble identifying phase shift in field" << endl;
exit(1);
}
}
else {
phi = K.onenumber;
}*/
taugen = K.taugen;
cout << "Defining taugen of group: " << taugen << endl;
cout << " (" << _evalf(taugen,&ct) << ")" << endl;
mult = zeta;
multconj = K.myconj(mult);
gen a = 2 - mult - multconj;
gen b13 = (K.onenumber - multconj)*t3c;
gen b12 = multconj - K.onenumber;
K.red(a);
K.red(b12);
K.red(b13);
vecteur coh(9);
coh[0] = a; coh[1] = b12; coh[2] = b13;
coh[3] = K.myconj(b12); coh[4] = a; coh[5] = b12;
coh[6] = K.myconj(b13); coh[7] = K.myconj(b12); coh[8] = a;
H = K.createMatrix(coh);
R1 = reflMat(K.e1,mult);
R1i = reflMat(K.e1,multconj);
R2 = reflMat(K.e2,mult);
R2i = reflMat(K.e2,multconj);
R3 = reflMat(K.e3,mult);
R3i = reflMat(K.e3,multconj);
gen bou = multconj*t3c;
K.red(bou);
vecteur coj(9);
coj[0] = 0; coj[1] = 0; coj[2] = bou;
coj[3] = 1; coj[4] = 0; coj[5] = 0;
coj[6] = 0; coj[7] = 1; coj[8] = 0;
J = K.createMatrix(coj);
vecteur coji(9);
coji[0] = 0; coji[1] = 1; coji[2] = 0;
coji[3] = 0; coji[4] = 0; coji[5] = 1;
coji[6] = K.myconj(bou); coji[7] = 0; coji[8] = 0;
Ji = K.createMatrix(coji);
is_symmetric = true;
if (is_symmetric) {
P = R1*J;
Pi = Ji*R1i;
}
else {
P = R1*R2*R3;
Pi = R3i*R2i*R1i;
}
K.matred(P);
K.matred(Pi);
cout << "x is a root of " << K.minpol << endl;
cout << endl;
cout << "R1 has order " << K.order(R1) << endl;
cout << "H=" << H << endl;
cout << "R1=" << R1 << endl;
cout << "J=" << J << endl;
cout << "R1, R2 braid with order " << K.braidOrder(R1,R2) << endl;
cout << endl;
H_rootof = recursive_normal(eval(_subst(makesequence(H,x__IDNT_e,K.genasrootof),&ct),&ct),&ct);
// cout << "H as rootof: " << H_rootof << endl;
orderofp = K.order(P);
if (orderofp<0) {
cerr << "I can't handle this group (yet), P has large (infinite?) order" << endl;
exit(1);
}
else {
cout << "P has order " << orderofp << endl;
}
// somehow the following doesn't work for some Mostow groups
/* gen axes_attempt;
bool bo = my_jordan(P,axes_attempt);
if (bo) {
p0_rootof = _col(makesequence(axes_attempt,0),&ct);
}
else {
cout << "Trouble computing fixed point of P in the ball" << endl;
exit(1);
}*/
bool is_split = findEigenVectors_P();
if (is_split) {
p0 = _col(makesequence(Q,0),&ct);
p0c = K.vectconj(p0);
cout << endl;
cout << "p0=" << p0 << endl;
cout << "<p0,p0>=" << SqNorm(p0) << " (" << K.evali(SqNorm(p0)) << endl;
gen imp0 = P*p0;
K.vectred(imp0);
cout << "Check p0 fixed by P? ";
bool tf = K.areDep(p0,imp0);
if (tf) {
cout << " OK " << endl;
}
else {
cout << " does not seem fixed :(" << endl;
exit(1);
}
Ppower = K.Id;
bool ir = false;
orderofppower = 0;
while (!ir && orderofppower<orderofp-1) {
orderofppower++;
Ppower = Ppower*P;
K.matred(Ppower);
gen dt = K.discrAdjusted(Ppower);
ir = operator_equal(dt,K.zeronumber,&ct);
}
if (ir) {
cout << "Power " << orderofppower << " of P is a complex reflection (or parabolic)" << endl;
}
vector<int> w232b;
w232b.push_back(2);
w232b.push_back(3);
w232b.push_back(-2);
vector<int> w3b23;
w3b23.push_back(-3);
w3b23.push_back(2);
w3b23.push_back(3);
vector<int> w2323b2b;
w2323b2b.push_back(2);
w2323b2b.push_back(3);
w2323b2b.push_back(2);
w2323b2b.push_back(-3);
w2323b2b.push_back(-2);
createBraidRelation(word_p1,w2);
createBraidRelation(word_p1,w232b);
createBraidRelation(word_p1,w3b23);
createBraidRelation(word_p1,w2323b2b);
cout << "Relations:" << endl;
for (int k=0; k<relations.size(); k++) {
cout << " " << convertword(relations[k]) << endl;
}
e1w = WVector(K.e1,w1);
e2w = WVector(K.e2,w2);
e3w = WVector(K.e3,w3);
}
}
bool Polytope::findEigenVectors_P() {
needppower = false;
cout << "K.genasrootof=" << K.genasrootof << endl;
gen st("j",&ct);
gen tepo = simplify(K.minpol - gen("x^2+1",&ct),&ct);
if (!operator_equal(tepo,K.zeronumber,&ct)) {
cout << "Sto j with " << K.genasrootof << endl;
// }
sto(st,K.genasrootof,&ct);
}
else {
st = K.genasrootof;
cout << "Skipping sto, can't do it with i" << endl;
}
// if (verbose) {
gen cpm0 = _charpoly(P,&ct);
vecteur cpm1;
for (int j=0; j<4; j++) {
gen tej = cpm0[j];
K.red(tej);
cpm1.push_back(_subst(makesequence(tej,x__IDNT_e,eval(K.genasrootof,&ct)),&ct));
}
gen var = u__IDNT_e;
gen charpol = normal(_poly2symb(makesequence(cpm1,var),&ct),&ct);
// gen charpol = _det(P - var*K.Id,&ct);
// K.red(charpol);
// cout << "charpol=" << charpol << endl;
gen fa = _factors(makesequence(charpol,K.genasrootof),&ct);
// cout << "fa=" << fa << endl;
bool split = true;
for (int l=0; 2*l<(*fa._VECTptr).size(); l++) {
int deg = _degree(makesequence(fa[2*l],var),&ct).val;
if (deg>1) {
split = false;
cout << "In order to describe the axes of P, need to extend the ambient number field" << endl;
cout << " (this may well slow down the computations)" << endl;
// if (verbose) {
cout << "Will now split " << fa[2*l] << endl;
// }
gen avoid = eval(gen("u^2-i",&ct),&ct);
gen test = _simplify(fa[2*l]-avoid,&ct);
vecteur coe;
if (operator_equal(test,K.zeronumber,&ct) && operator_equal(eval(gen("i",&ct),&ct),K.genasrootof,&ct)) {
// ad hoc solution to handle m4-1%4 (annoying because of sto(i) impossible)
coe.push_back(K.onenumber);
coe.push_back(K.zeronumber);
coe.push_back(x__IDNT_e);
}
else {
for (int uu=deg; uu>=0; uu--) {
gen teuu = _simplify(_coeff(makesequence(fa[2*l],var,uu),&ct),&ct);
if (verbose) {
cout << "teuu=" << teuu << endl;
}
if (contains(teuu,st)) {
// cout << "Contains " << st << endl;
vecteur coe_u;
int subdeg = _degree(makesequence(teuu,st),&ct).val;
// cout << "subdeg=" << subdeg << endl;
for (int vv=subdeg; vv>=0; vv--) {
gen teuu_vv = _coeff(makesequence(teuu,st,vv),&ct);
coe_u.push_back(teuu_vv);
}
coe.push_back(giac::expand(_poly2symb(makesequence(coe_u,x__IDNT_e),&ct),&ct));
}
else {
if (teuu.type==8) {
if (teuu.is_symb_of_sommet(at_prod)) {
gen yoo = _poly2symb(makesequence(_simplify(teuu[1][1]*teuu[2],&ct),x__IDNT_e),&ct);
coe.push_back(yoo);
}
else {
if (teuu.is_symb_of_sommet(at_rootof)) {
gen yoo = _poly2symb(makesequence(_simplify(teuu[1],&ct),x__IDNT_e),&ct);
coe.push_back(yoo);
}
else {
cout << "teuu=" << teuu << endl;
cout << "Problem reading factors!" << endl;
}
}
}
else {
coe.push_back(teuu);
}
}
}
}
vecteur eqs;
eqs.push_back(K.minpol);
eqs.push_back(giac::expand(_poly2symb(makesequence(coe,a__IDNT_e),&ct),&ct));
vecteur vars;
vars.push_back(x__IDNT_e);
vars.push_back(a__IDNT_e);
if (verbose) {
cout << "eqs: " << eqs << endl;
cout << "vars: " << vars << endl;
}
gen gb = _gbasis(makesequence(eqs,vars,change_subtype(_RUR_REVLEX,_INT_GROEBNER)),&ct);
gen varprov = lidnt(gb[2])[0];
gen para = _subst(makesequence(gb[2],varprov,x__IDNT_e),&ct);
int dpara = _degree(para,&ct).val;
if (gb[0]==-4) {
if (operator_equal(_coeff(makesequence(para,x__IDNT_e,dpara),&ct),-K.onenumber,&ct)) {
// if (verbose) {
cout << "New min pol: " << _simplify(-para,&ct) << endl;
// }
cout << endl;
cout << "Will start over with new field" << endl;
gen taugensave = K.taugen;
string tautagsave = K.tautag;
// cout << "taugensave=" << taugensave << endl;
// cout << " (" << _evalf(taugensave,&ct) << ")" << endl;
gen Tsave = K.T;
K = CMfield(-para,K.tag);
K.taugen = taugensave;
K.tautag = tautagsave;
// cout << "taugensave=" << taugensave << endl;
// cout << " (" << _evalf(taugensave,&ct) << ")" << endl;
K.T = Tsave;
createGroup();
}
else {
cout << "New min pol: " << _simplify(para,&ct) << endl;
cout << "Will start over with new field" << endl;
gen taugensave = K.taugen;
// cout << "taugensave=" << taugensave << endl;
// cout << " (" << _evalf(taugensave,&ct) << ")" << endl;
gen Tsave = K.T;
K = CMfield(para,K.tag);
K.taugen = taugensave;
// cout << "taugensave=" << taugensave << endl;
// cout << " (" << _evalf(taugensave,&ct) << ")" << endl;
K.T = Tsave;
createGroup();
}
}
else {
cerr << "Trouble computing primitive element" << endl;
exit(1);
}
}
}
if (split) {
gen Pk = P;
Ppowers.push_back(K.Id);
Ppowers.push_back(P);
bool foundorder = false;
int kk=1;
while (!foundorder && kk<100) {
kk++;
Pk = Pk*P;
K.matred(Pk);
foundorder = K.isScalar(Pk);
if (!foundorder) {
Ppowers.push_back(Pk);
}
}
if (foundorder) {
orderofp = kk;
}
else {
cout << "P has infinite (or at least very large) order, not sure what to do at this stage" << endl;
exit(1);
}
cout << "Computations will take place in a number field of degree " << K.dc << endl;
if (is_symmetric) {
cout << "R1*J = P has order " << orderofp << endl;
}
else {
cout << "R1*R2*R3 = P has order " << orderofp << endl;
}
vecteur evals_P;
for (int l=0; 2*l<(*fa._VECTptr).size(); l++) {
int deg = _degree(makesequence(fa[2*l],var),&ct).val;
if (deg>1) {
cerr << "I thought we constructed an extension splitting the char poly of P!?" << endl;
exit(1);
}
else {
if (deg==1) {
gen te = _simplify(-_coeff(makesequence(fa[2*l],var,0),&ct)/_coeff(makesequence(fa[2*l],var,1),&ct),&ct);
if (contains(te,st)) {
int subdeg = _degree(makesequence(te,st),&ct).val;
vecteur te2;
for (int uu=subdeg; uu>=0; uu--) {
te2.push_back(_coeff(makesequence(te,st,uu),&ct));
}
evals_P.push_back(giac::expand(_poly2symb(makesequence(te2,x__IDNT_e),&ct),&ct));
}
else {
if (te.type==8) {
if (te.is_symb_of_sommet(at_prod)) {
evals_P.push_back(giac::expand(_poly2symb(makesequence(_simplify(te[1][1]*te[2],&ct),x__IDNT_e),&ct),&ct));
}
else {
if (te.is_symb_of_sommet(at_rootof)) {
evals_P.push_back(giac::expand(_poly2symb(makesequence(_simplify(te[1],&ct),x__IDNT_e),&ct),&ct));
}
else {
cout << "te=" << te << endl;
cout << "Problem reading factors!" << endl;
}
}
}
else {
cout << "hopefully this is an integer (or at least rational): " << te << endl;
evals_P.push_back(te);
}
}
}
}
}
vecteur evects_P;
for (int k=0; k<evals_P.size(); k++) {
gen U = _simplify(P-evals_P[k]*K.Id,&ct); // should have rank 2 in most cases WELL NOT ALWAYS!
K.matred(U);
gen de = _det(U,&ct);
K.red(de);
gen X;
vecteur U1;
U1.push_back(U[0][1]*U[1][2]-U[1][1]*U[0][2]);
U1.push_back(U[0][2]*U[1][0]-U[1][2]*U[0][0]);
U1.push_back(U[0][0]*U[1][1]-U[1][0]*U[0][1]);
X = gen(U1);
K.vectred(X);
if (operator_equal(X,K.zerovector,&ct)) {
U1.clear();
U1.push_back(U[1][1]*U[2][2]-U[1][1]*U[2][2]);
U1.push_back(U[1][2]*U[2][0]-U[1][2]*U[2][0]);
U1.push_back(U[1][0]*U[2][1]-U[1][0]*U[2][1]);
X = gen(U1);
K.vectred(X);
if (operator_equal(X,K.zerovector,&ct)) {
U1.clear();
U1.push_back(U[2][1]*U[0][2]-U[0][1]*U[2][2]);
U1.push_back(U[2][2]*U[0][0]-U[0][2]*U[2][0]);
U1.push_back(U[2][0]*U[0][1]-U[0][0]*U[2][1]);
X = gen(U1);
K.vectred(X);
if (operator_equal(X,K.zerovector,&ct)) {
cerr << "Trouble computing eigenvectors of P" << endl;
exit(1);
}
}
}
if (!operator_equal(X[0],K.zeronumber,&ct)) {
gen x0i = K.inverse(X[0]);
X = x0i*X;
K.vectred(X);
}
else {
if (!operator_equal(X[1],K.zeronumber,&ct)) {
gen x1i = K.inverse(X[1]);
X = x1i*X;
K.vectred(X);
}
else {
if (!operator_equal(X[2],K.zeronumber,&ct)) {
gen x2i = K.inverse(X[2]);
X = x2i*X;
K.vectred(X);
}
}
}
evects_P.push_back(X);
}
gen TE = gen(evects_P);
gen detTE =_det(TE,&ct);
K.red(detTE);
// may want to test that vectors are really orthogonal (this may not work in some cases...)
for (int k1 = 0; k1<2; k1++) {
for (int k2=k1+1; k2<3; k2++) {
gen te = Inn(evects_P[k1],evects_P[k2]);
if (!operator_equal(te,K.zeronumber,&ct)) {
cout << "te=" << te << endl;
cout << "value " << K.evali(te) << endl;
cerr << "Eigenvectors are not orthogonal, P is not regular elliptic" << endl;
exit(1);
}
}
}
int lneg;
int count_neg = 0;
for (int l=0; l<3; l++) {
gen ns = SqNorm(evects_P[l]);
int sgns;
if (!K.checkSign(ns,sgns)){
cerr << "Trouble checking sign of eigenvectors" << endl;
exit(1);
}
else {
if (sgns==0) {
cerr << "P is parabolic, I can't use any of its eigenvectors as center of the ball" << endl;
exit(1);
}
else {
if (sgns<0) {
count_neg++;
lneg = l;
}
}
}
}
if (count_neg!=1) {
cout << "Trouble, found " << count_neg << " negative vectors among eigenvectors.." << endl;
if (count_neg==2) {
H = normal(-H,&ct);
}
else {
cerr << "count_neg=" << count_neg << endl;
exit(1);
}
}
vecteur qcoo;
qcoo.push_back(evects_P[lneg]);
for (int uu=0; uu<3; uu++) {
if (uu!=lneg) {
qcoo.push_back(evects_P[uu]);
}
}
Q = _tran(gen(qcoo),&ct);
vecteur evals_P_powers;
evals_P_powers.push_back(K.onenumber);
evals_P_powers.push_back(K.onenumber);
evals_P_powers.push_back(K.onenumber);
bool foundreflection = false;
int po = 0;
while (po<orderofp-1 && !foundreflection) {
po++;
for (int k=0; k<evals_P.size(); k++) {
evals_P_powers[k] = evals_P_powers[k]*evals_P[k];
K.red(evals_P_powers[k]);
}
if (operator_equal(evals_P_powers[0],evals_P_powers[1],&ct)) {
if (operator_equal(evals_P_powers[0],evals_P_powers[2],&ct)) {
cerr << "P^" << po << " has a triple eigenvalue, this is suspicious!" << endl;
exit(1);
}
foundreflection = true;
cout << "P^" << po << " has a repeated eigenvalue" << endl;
gen te = SqNorm(evects_P[2]);
int sign;
if (K.checkSign(te,sign)) {
if (sign>0) {
cout << "Other eigenvector is positive, this is a reflection in a complex line" << endl;
extramirror = evects_P[2];
orderofppower = po;
needppower = true;
}
else {
if (sign==0) {
cerr << "Found an ideal fixed point, P is parabolic" << endl;
cerr << "This should not happen here" << endl;
exit(1);
}
else {
cout << "Other eigenvector is negative, reflection in a point" << endl;
// MAY STILL NEED TO CHECK POSSIBLE RIDGES STABILIZED BY THAT POWER??
}
}
}
else {
cerr << "Trouble checking sign of eigenvector of P" << endl;
exit(1);
}
}
if (!foundreflection && operator_equal(evals_P_powers[0],evals_P_powers[2],&ct)) {
foundreflection = true;
cout << "P^" << po << " has a repeated eigenvalue" << endl;
gen te = SqNorm(evects_P[1]);
int sign;
if (K.checkSign(te,sign)) {
if (sign>0) {
cout << "Other eigenvector is positive, this is a reflection in a complex line" << endl;
extramirror = evects_P[1];
orderofppower = po;
needppower = true;
}
else {
if (sign==0) {
cerr << "Found an ideal fixed point, P is parabolic" << endl;
cerr << "This should not happen here" << endl;
exit(1);
}
else {
cout << "Other eigenvector is negative, reflection in a point" << endl;
}
}
}
else {
cerr << "Trouble checking sign of eigenvector of P" << endl;
exit(1);
}
}
if (!foundreflection && operator_equal(evals_P_powers[1],evals_P_powers[2],&ct)) {
foundreflection = true;
cout << "P^" << po << " has a repeated eigenvalue" << endl;
gen te = SqNorm(evects_P[0]);
int sign;
if (K.checkSign(te,sign)) {
if (sign>0) {
cout << "Other eigenvector is positive, this is a reflection in a complex line" << endl;
extramirror = evects_P[0];
orderofppower = po;
needppower = true;
}
else {
if (sign==0) {
cerr << "Found an ideal fixed point, P is parabolic" << endl;
cerr << "This should not happen here" << endl;
exit(1);
}
else {
cout << "Other eigenvector is negative, reflection in a point" << endl;
}
}
}
else {
cerr << "Trouble checking sign of eigenvector of P" << endl;
exit(1);
}
}
}
}
return split;
}
void Polytope::initThompsonGroup() {
is_symmetric = false;
if (verbose) {
cout << "Initializing Thompson group..." << endl;
}
// taugen makes no sense here, need to think about this
gen zeta;
if (pval>2) {
zeta = rootof(_cyclotomic(pval,&ct),&ct);
gen zeta_int = convert_interval(zeta,K.nd,&ct);
if (verbose) {
cout << "zeta interval=" << zeta_int << endl;
}
zeta = _simplify(zeta,&ct);
if (verbose) {
cout << "zeta=" << zeta << endl;
}
gen pol_zeta;
if (operator_equal(simplify(zeta-K.onenumber,&ct),K.zeronumber,&ct) || operator_equal(simplify(zeta+K.onenumber,&ct),K.zeronumber,&ct)) {
pol_zeta=z__IDNT_e-zeta;
}
else {
pol_zeta = giac::expand(_poly2symb(makesequence(_pmin(zeta,&ct),z__IDNT_e),&ct),&ct);
}
if (verbose) {
cout << "min pol of zeta: " << pol_zeta << endl;
}
if (!K.findInField(pol_zeta,zeta_int,mult)) {
cerr << "Trouble identifying reflection multiplier in field" << endl;
exit(1);
}
multconj = K.myconj(mult);
}
else {
mult = -K.onenumber;
multconj = -K.onenumber;
}
gen r = K.T[0];
gen r_int = convert_interval(r,K.nd,&ct);
if (verbose) {
cout << "rho interval=" << r_int << endl;
}
r = _simplify(r,&ct);
if (verbose) {
cout << "rho=" << r << endl;
}
gen pol_r;
if (operator_equal(r,K.onenumber,&ct) || operator_equal(r,-K.onenumber,&ct)) {
pol_r=z__IDNT_e-r;
}
else {
pol_r = giac::expand(_poly2symb(makesequence(_pmin(r,&ct),z__IDNT_e),&ct),&ct);
}
if (verbose) {
cout << "min pol of rho: " << pol_r << endl;
}
if (!K.findInField(pol_r,r_int,r)) {
cerr << "Trouble identifying reflection multiplier in field" << endl;
exit(1);
}
gen s = K.T[1];
gen s_int = convert_interval(s,K.nd,&ct);
if (verbose) {
cout << "sigma interval=" << s_int << endl;
}
s = _simplify(s,&ct);
if (verbose) {
cout << "sigma=" << s << endl;
}
gen pol_s;
if (operator_equal(s,K.onenumber,&ct) || operator_equal(s,-K.onenumber,&ct)) {
pol_s=z__IDNT_e-s;
}
else {
pol_s = giac::expand(_poly2symb(makesequence(_pmin(s,&ct),z__IDNT_e),&ct),&ct);
}
if (verbose) {
cout << "min pol of sigma: " << pol_s << endl;
}
if (!K.findInField(pol_s,s_int,s)) {
cerr << "Trouble identifying reflection multiplier in field" << endl;
exit(1);
}
gen t = K.T[2];
gen t_int = convert_interval(t,K.nd,&ct);
if (verbose) {
cout << "tau interval=" << t_int << endl;
}
t = _simplify(t,&ct);
if (verbose) {
cout << "tau=" << t << endl;
}
gen pol_t;
if (operator_equal(t,K.onenumber,&ct) || operator_equal(t,-K.onenumber,&ct)) {
pol_t=z__IDNT_e-t;
}
else {
pol_t = giac::expand(_poly2symb(makesequence(_pmin(t,&ct),z__IDNT_e),&ct),&ct);
}
if (verbose) {
cout << "min pol of tau: " << pol_t << endl;
}
if (!K.findInField(pol_t,t_int,t)) {
cerr << "Trouble identifying reflection multiplier in field" << endl;
exit(1);
}
gen rc = K.myconj(r);
gen sc = K.myconj(s);
gen tc = K.myconj(t);
gen a = 2-mult-multconj;
gen b12 = (multconj-1)*r;
gen b31 = (1-mult)*t;
gen b23 = (multconj-1)*s;
K.red(a);
K.red(b12);
K.red(b31);
K.red(b23);
vecteur coh(9);
coh[0] = a; coh[1] = b12; coh[2] = K.myconj(b31);
coh[3] = K.myconj(b12); coh[4] = a; coh[5] = b23;
coh[6] = b31; coh[7] = K.myconj(b23); coh[8] = a;
H = K.createMatrix(coh);
vecteur cor1(9);
cor1[0] = mult; cor1[1] = r; cor1[2] = -tc;
cor1[3] = 0; cor1[4] = 1; cor1[5] = 0;
cor1[6] = 0; cor1[7] = 0; cor1[8] = 1;
R1 = K.createMatrix(cor1);
K.matred(R1);
vecteur cor2(9);
cor2[0] = 1; cor2[1] = 0; cor2[2] = 0;
cor2[3] = -rc*mult; cor2[4] = mult; cor2[5] = s;
cor2[6] = 0; cor2[7] = 0; cor2[8] = 1;
R2 = K.createMatrix(cor2);
K.matred(R2);
vecteur cor3(9);
cor3[0] = 1; cor3[1] = 0; cor3[2] = 0;
cor3[3] = 0; cor3[4] = 1; cor3[5] = 0;
cor3[6] = t*mult; cor3[7] = -sc*mult; cor3[8] = mult;
R3 = K.createMatrix(cor3);
K.matred(R3);
vecteur cor1i(9);
cor1i[0] = multconj; cor1i[1] = -r*multconj; cor1i[2] = tc*multconj;
cor1i[3] = 0; cor1i[4] = 1; cor1i[5] = 0;
cor1i[6] = 0; cor1i[7] = 0; cor1i[8] = 1;
R1i = K.createMatrix(cor1i);
K.matred(R1i);
vecteur cor2i(9);
cor2i[0] = 1; cor2i[1] = 0; cor2i[2] = 0;
cor2i[3] = rc; cor2i[4] = multconj; cor2i[5] = -s*multconj;
cor2i[6] = 0; cor2i[7] = 0; cor2i[8] = 1;
R2i = K.createMatrix(cor2i);
K.matred(R2i);
vecteur cor3i(9);
cor3i[0] = 1; cor3i[1] = 0; cor3i[2] = 0;
cor3i[3] = 0; cor3i[4] = 1; cor3i[5] = 0;
cor3i[6] = -t; cor3i[7] = sc; cor3i[8] = multconj;
R3i = K.createMatrix(cor3i);
K.matred(R3i);
if (verbose) {
cout << "R1:" << R1 << endl;
cout << "R2:" << R2 << endl;
cout << "R3:" << R3 << endl;
cout << "H:" << H << endl;
}
H_rootof = recursive_normal(_subst(makesequence(H,x__IDNT_e,K.genasrootof),&ct),&ct);
// cout << "H as rootof: " << H_rootof << endl;
gen tede = K.det(H);
if (verbose) {
cout << "det(H)=" << tede << ", " << K.evali(tede) << endl;
}
P = R1*R2*R3;
Pi = R3i*R2i*R1i;
K.matred(P);
K.matred(Pi);
cout << "P=" << normal(_subst(makesequence(P,x__IDNT_e,K.genasrootof),&ct),&ct) << endl;
orderofp = K.order(P);
if (orderofp<0) {
cerr << "I can't handle this group (yet), P has large (infinite?) order" << endl;
exit(1);
}
else {
cout << "P has order " << orderofp << endl;
}
/* gen axes_attempt, evs_attempt;
bool bo = my_jordan(P,axes_attempt,evs_attempt);
if (bo) {
p0_rootof = _col(makesequence(axes_attempt,0),&ct);
is_p0_rootof_computed = true;
}
else {
cout << "Trouble computing fixed point of P in the ball" << endl;
exit(1);
}*/
bool is_split = findEigenVectors_P();
/* gen M = P*P*P*R2i;
K.matred(M);
cout << "M:=" << M << ";" << endl;
cout << "x_val:=" << K.genasrootof << endl;
gen axes_m, ev_m;
my_jordan(M,axes_m,ev_m);
exit(1);*/
if (is_split) {
p0 = _col(makesequence(Q,0),&ct);
p0c = K.vectconj(p0);
cout << endl;
cout << "p0=" << p0 << endl;
gen p0_12 = R1*R2*p0;
K.vectred(p0_12);
gen p0_13 = R1*R3*p0;
K.vectred(p0_13);
gen p0_23 = R3i*R2i*p0;
K.vectred(p0_23);
gen p0_1232 = R1*R2*R3*R2i*p0;
K.vectred(p0_1232);
if (K.areDep(p0,p0_12)) {
cout << "p0 fixed by 12" << endl;
}
if (K.areDep(p0,p0_13)) {
cout << "p0 fixed by 13" << endl;
}
if (K.areDep(p0,p0_23)) {
cout << "p0 fixed by 23" << endl;
}
if (K.areDep(p0,p0_1232)) {
cout << "p0 fixed by 1232b" << endl;
}
// exit(1);
Ppower = K.Id;
bool ir = false;
orderofppower = 0;
while (!ir && orderofppower<orderofp-1) {
orderofppower++;
Ppower = Ppower*P;
K.matred(Ppower);
gen dt = K.discrAdjusted(Ppower);
ir = operator_equal(dt,K.zeronumber,&ct);
}
if (ir) {
cout << "Power " << orderofppower << " of P is (probably) a complex reflection!" << endl;
// not quite right! this does not work for s1 for instance...
}
else {
cout << "No power of P is a complex reflection!" << endl;
}
vector<int> w121b;
w121b.push_back(1);
w121b.push_back(2);
w121b.push_back(-1);
vector<int> w2b12;
w2b12.push_back(-2);
w2b12.push_back(1);
w2b12.push_back(2);
vector<int> w232b;
w232b.push_back(2);
w232b.push_back(3);
w232b.push_back(-2);
vector<int> w3b23;
w3b23.push_back(-3);
w3b23.push_back(2);
w3b23.push_back(3);
vector<int> w313b;
w313b.push_back(3);
w313b.push_back(1);
w313b.push_back(-3);
vector<int> w1b31;
w1b31.push_back(-1);
w1b31.push_back(3);
w1b31.push_back(1);
createBraidRelation(word_p1,w2);
createBraidRelation(w2,w3);
createBraidRelation(w3,w1);
createBraidRelation(word_p1,w232b);
createBraidRelation(word_p1,w3b23);
createBraidRelation(w2,w313b);
createBraidRelation(w2,w1b31);
createBraidRelation(w3,w121b);
createBraidRelation(w3,w2b12);
cout << "Relations:" << endl;
for (int k=0; k<relations.size(); k++) {
cout << " " << convertword(relations[k]) << endl;
}
e1w = WVector(K.e1,w1);
e2w = WVector(K.e2,w2);
e3w = WVector(K.e3,w3);
}
}
void Polytope::initSporadicGroup() {
if (verbose) {
cout << "Initializing sporadic group..." << endl;
}
taugen = K.taugen;
gen sigma_int = convert_interval(taugen,K.nd,&ct);
gen sigma = _simplify(taugen,&ct);
if (!operator_equal(sigma,K.onenumber,&ct)) {
gen pol_sigma = giac::expand(_poly2symb(makesequence(_pmin(sigma,&ct),z__IDNT_e),&ct),&ct);
if (!K.findInField(pol_sigma,sigma_int,tau)) {
cerr << "Trouble identifying sigma in field" << endl;
exit(1);
}
}
tauc = K.myconj(tau);
if (verbose) {
cout << "sigma=" << tau << endl;
cout << " evali: " << K.evali(tau) << endl;
}
gen zeta = gen("exp(2*pi*i/"+print_INT_(pval)+")",&ct);
gen zeta_int = convert_interval(zeta,K.nd,&ct);
if (verbose) {
cout << "zeta interval=" << zeta_int << endl;
}
zeta = _simplify(zeta,&ct);
if (verbose) {
cout << "zeta=" << zeta << endl;
}
gen pol_zeta;
if (operator_equal(simplify(zeta-K.onenumber,&ct),K.zeronumber,&ct) || operator_equal(simplify(zeta+K.onenumber,&ct),K.zeronumber,&ct)) {
pol_zeta=z__IDNT_e-zeta;
mult = zeta;
}
else {
pol_zeta = giac::expand(_poly2symb(makesequence(_pmin(zeta,&ct),z__IDNT_e),&ct),&ct);
//cout << _pmin(zeta,&ct) << endl;
if (verbose) {
cout << "min pol of zeta: " << pol_zeta << endl;
}
if (!K.findInField(pol_zeta,zeta_int,mult)) {
cerr << "Trouble identifying reflection multiplier in field" << endl;
exit(1);
}
}
if (verbose) {
cout << "mult=" << mult << endl;
}
multconj = K.myconj(mult);
if (K.tautag!="s5") {
cout << "Not s5" << endl;
gen a = 2-mult-multconj;
gen b12 = (multconj-1)*tau;
gen b13 = (1-multconj)*tauc;
K.red(a);
K.red(b12);
K.red(b13);
vecteur coh(9);
coh[0] = a; coh[1] = b12; coh[2] = b13;
coh[3] = K.myconj(b12); coh[4] = a; coh[5] = b12;
coh[6] = K.myconj(b13); coh[7] = K.myconj(b12); coh[8] = a;
H = K.createMatrix(coh);
vecteur cor1(9);
cor1[0] = mult; cor1[1] = tau; cor1[2] = -tauc;
cor1[3] = 0; cor1[4] = 1; cor1[5] = 0;
cor1[6] = 0; cor1[7] = 0; cor1[8] = 1;
R1 = K.createMatrix(cor1);
K.matred(R1);
vecteur cor2(9);
cor2[0] = 1; cor2[1] = 0; cor2[2] = 0;
cor2[3] = -tauc*mult; cor2[4] = mult; cor2[5] = tau;
cor2[6] = 0; cor2[7] = 0; cor2[8] = 1;
R2 = K.createMatrix(cor2);
K.matred(R2);
vecteur cor3(9);
cor3[0] = 1; cor3[1] = 0; cor3[2] = 0;
cor3[3] = 0; cor3[4] = 1; cor3[5] = 0;
cor3[6] = tau*mult; cor3[7] = -tauc*mult; cor3[8] = mult;
R3 = K.createMatrix(cor3);
K.matred(R3);
vecteur cor1i(9);
cor1i[0] = multconj; cor1i[1] = -tau*multconj; cor1i[2] = tauc*multconj;
cor1i[3] = 0; cor1i[4] = 1; cor1i[5] = 0;
cor1i[6] = 0; cor1i[7] = 0; cor1i[8] = 1;
R1i = K.createMatrix(cor1i);
K.matred(R1i);
vecteur cor2i(9);
cor2i[0] = 1; cor2i[1] = 0; cor2i[2] = 0;
cor2i[3] = tauc; cor2i[4] = multconj; cor2i[5] = -tau*multconj;
cor2i[6] = 0; cor2i[7] = 0; cor2i[8] = 1;
R2i = K.createMatrix(cor2i);
K.matred(R2i);
vecteur cor3i(9);
cor3i[0] = 1; cor3i[1] = 0; cor3i[2] = 0;
cor3i[3] = 0; cor3i[4] = 1; cor3i[5] = 0;
cor3i[6] = -tau; cor3i[7] = tauc; cor3i[8] = multconj;
R3i = K.createMatrix(cor3i);
K.matred(R3i);
vecteur coj(9);
coj[0] = 0; coj[1] = 0; coj[2] = multconj;
coj[3] = 1; coj[4] = 0; coj[5] = 0;
coj[6] = 0; coj[7] = 1; coj[8] = 0;
J = K.createMatrix(coj);
vecteur coji(9);
coji[0] = 0; coji[1] = 1; coji[2] = 0;
coji[3] = 0; coji[4] = 0; coji[5] = 1;
coji[6] = mult; coji[7] = 0; coji[8] = 0;
Ji = K.createMatrix(coji);
}
else {
// special case for s5 to make CM field (slightly) smaller
cout << "This is an s5 group, I will reduce CM field (could do even better by not using p0)" << endl;
gen ta0 = _eval(gen("(sqrt(5)+i*sqrt(3))/2",&ct),&ct);
gen ta0_int = convert_interval(ta0,K.nd,&ct);
// cout << "ta0_int " << ta0_int << endl;
gen pol_ta = giac::expand(_poly2symb(makesequence(_pmin(ta0,&ct),z__IDNT_e),&ct),&ct);
// cout << "min pol of ta: " << pol_ta << endl;
gen ta;
if (!K.findInField(pol_ta,ta0_int,ta)) {
cerr << "Trouble identifying alt tau (s5 case) in field" << endl;
exit(1);
}
cout << "tau^3=" << ta << endl;
gen tac;
if (!K.findInField(pol_ta,conj(ta0_int,&ct),tac)) {
cerr << "Trouble identifying conj of alt tau (s5 case) in field" << endl;
exit(1);
}
// cout << "tac=" << tac << endl;
gen om0 = gen("(-1+i*sqrt(3))/2",&ct);
gen om0_int = convert_interval(om0,K.nd,&ct);
gen pol_om = eval(gen("z^2+z+1",&ct),&ct);
// giac::expand(_poly2symb(makesequence(_pmin(om0,&ct),z__IDNT_e),&ct),&ct);
// cout << "min pol of om: " << pol_om << endl;
gen om;
if (!K.findInField(pol_om,om0_int,om)) {
cerr << "Trouble identifying omega in field" << endl;
exit(1);
}
cout << "om=" << om << endl;
gen omc = K.inverse(om);
gen a = 2-mult-multconj;
gen b12 = (multconj-1)*ta;
gen b13 = (multconj-1)*tac*omc;
K.red(a);
K.red(b12);
K.red(b13);
vecteur coh(9);
coh[0] = a; coh[1] = b12; coh[2] = b13;
coh[3] = K.myconj(b12); coh[4] = a; coh[5] = b12;
coh[6] = K.myconj(b13); coh[7] = K.myconj(b12); coh[8] = a;
H = K.createMatrix(coh);
vecteur cor1(9);
cor1[0] = mult; cor1[1] = ta; cor1[2] = tac*omc;
cor1[3] = 0; cor1[4] = 1; cor1[5] = 0;
cor1[6] = 0; cor1[7] = 0; cor1[8] = 1;
R1 = K.createMatrix(cor1);
K.matred(R1);
vecteur cor2(9);
cor2[0] = 1; cor2[1] = 0; cor2[2] = 0;
cor2[3] = -mult*tac; cor2[4] = mult; cor2[5] = ta;
cor2[6] = 0; cor2[7] = 0; cor2[8] = 1;
R2 = K.createMatrix(cor2);
K.matred(R2);
vecteur cor3(9);
cor3[0] = 1; cor3[1] = 0; cor3[2] = 0;
cor3[3] = 0; cor3[4] = 1; cor3[5] = 0;
cor3[6] = -ta*mult*om; cor3[7] = -tac*mult; cor3[8] = mult;
R3 = K.createMatrix(cor3);
K.matred(R3);
vecteur cor1i(9);
cor1i[0] = multconj; cor1i[1] = -ta*multconj; cor1i[2] = -tac*multconj*omc;
cor1i[3] = 0; cor1i[4] = 1; cor1i[5] = 0;
cor1i[6] = 0; cor1i[7] = 0; cor1i[8] = 1;
R1i = K.createMatrix(cor1i);
K.matred(R1i);
vecteur cor2i(9);
cor2i[0] = 1; cor2i[1] = 0; cor2i[2] = 0;
cor2i[3] = tac; cor2i[4] = multconj; cor2i[5] = -ta*multconj;
cor2i[6] = 0; cor2i[7] = 0; cor2i[8] = 1;
R2i = K.createMatrix(cor2i);
K.matred(R2i);
vecteur cor3i(9);
cor3i[0] = 1; cor3i[1] = 0; cor3i[2] = 0;
cor3i[3] = 0; cor3i[4] = 1; cor3i[5] = 0;
cor3i[6] = ta*om; cor3i[7] = tac; cor3i[8] = multconj;
R3i = K.createMatrix(cor3i);
K.matred(R3i);
vecteur coj(9);
coj[0] = 0; coj[1] = 0; coj[2] = -multconj*omc;
coj[3] = 1; coj[4] = 0; coj[5] = 0;
coj[6] = 0; coj[7] = 1; coj[8] = 0;
J = K.createMatrix(coj);
vecteur coji(9);
coji[0] = 0; coji[1] = 1; coji[2] = 0;
coji[3] = 0; coji[4] = 0; coji[5] = 1;
coji[6] = -mult*om; coji[7] = 0; coji[8] = 0;
Ji = K.createMatrix(coji);
}
// cout << "Done creating matrices" << endl;
if (is_symmetric) {
// cout << "Symmetric" << endl;
P = R1*J;
Pi = Ji*R1i;
}
else {
// cout << "Not symmetric" << endl;
P = R1*R2*R3;
Pi = R3i*R2i*R1i;
}
K.matred(P);
K.matred(Pi);
gen tede = _det(H,&ct);
K.red(tede);
K.convertToReal(tede);
// orderofp = K.order(P);
orderofp = K.order(P);
if (orderofp<0) {
cerr << "I can't handle this group (yet), P has large (infinite?) order" << endl;
exit(1);
}
else {
cout << "P has order " << orderofp << endl;
}
H_rootof = recursive_normal(_subst(makesequence(H,x__IDNT_e,K.genasrootof),&ct),&ct);
// cout << "H as rootof: " << H_rootof << endl;
/* gen axes_attempt, evs_attempt;
bool bo = my_jordan(P,axes_attempt,evs_attempt);
if (bo) {
p0_rootof = _col(makesequence(axes_attempt,0),&ct);
is_p0_rootof_computed = true;
}
else {
cout << "Trouble computing fixed point of P in the ball" << endl;
exit(1);
}*/
/* gen M = P*P*P*R2i;
K.matred(M);
cout << "M:=" << M << ";" << endl;
cout << "x_val:=" << K.genasrootof << endl;
gen axes_m, ev_m;
my_jordan(M,axes_m,ev_m);
exit(1);*/
bool is_split = findEigenVectors_P();
if (is_split) {
/* cout << "K.minpol: " << K.minpol << endl;
gen Mt = P*P*P*R2i;
K.matred(Mt);
int ot = K.linearorder(Mt);
cout << "Order P*P*P*R2^-1: " << ot << endl;
cout << "Mt=" << Mt << endl;
gen A = Mt*Mt;
K.matred(A);
A = A*Mt;
K.matred(A);
gen miA;
if (!findMirror(A,miA)) {
cout << "Error in findMirror" << endl;
exit(1);
}
cout << "miA=" << miA << endl;
cout << " intervals: " << convert_interval(miA,K.nd,&ct);
gen miAnum = _subst(makesequence(miA,x__IDNT_e,K.xvi),&ct);
gen Hnum = _subst(makesequence(H,x__IDNT_e,K.xvi),&ct);
vector<int> wt;
wt.push_back(1);
wt.push_back(2);
wt.push_back(3);
wt.push_back(-2);
vecteur axes_attempt, evs_attempt;
// bool bo = my_jordan(Mt,axes_attempt,evs_attempt);
bool bo = my_jordan_knowing_linear_order_alt(Mt,ot,axes_attempt,evs_attempt);
if (bo) {
cout << "axes: " << axes_attempt << endl;
cout << "evs: " << evs_attempt << endl;
}
else {
cout << "trouble in my_jordan" << endl;
}
for (int j=1; j<3; j++) {
cout << "Inner prod mirror perp with axis " << j << ": " << conj(miAnum,&ct)*Hnum*axes_attempt[j] << endl;
}
// exit(1);*/
p0 = _col(makesequence(Q,0),&ct);
p0c = K.vectconj(p0);
cout << endl;
gen imp0 = P*p0;
K.vectred(imp0);
cout << "Check p0 fixed by P? ";
bool tf = K.areDep(p0,imp0);
if (tf) {
cout << " OK " << endl;
}
else {
cout << " does not seem fixed :(" << endl;
exit(1);
}
Ppower = K.Id;
bool ir = false;
orderofppower = 0;
while (!ir && orderofppower<orderofp-1) {
orderofppower++;
Ppower = Ppower*P;
K.matred(Ppower);
gen dt = K.discrAdjusted(Ppower);
ir = operator_equal(dt,K.zeronumber,&ct);
}
if (ir) {
cout << "Power " << orderofppower << " of P is (probably) a complex reflection!" << endl;
// not quite right! this does not work for s1 for instance...
}
else {
cout << "No power of P is a complex reflection!" << endl;
}
vector<int> w232b;
w232b.push_back(2);
w232b.push_back(3);
w232b.push_back(-2);
vector<int> w3b23;
w3b23.push_back(-3);
w3b23.push_back(2);
w3b23.push_back(3);
createBraidRelation(word_p1,w2);
createBraidRelation(word_p1,w232b);
createBraidRelation(word_p1,w3b23);
cout << "Relations:" << endl;
for (int k=0; k<relations.size(); k++) {
cout << " " << convertword(relations[k]) << endl;
}
e1w = WVector(K.e1,w1);
e2w = WVector(K.e2,w2);
e3w = WVector(K.e3,w3);
}
}
gen Polytope::Proj(gen v, gen w) {
gen fai = Inn(w,w);
if (operator_equal(fai,K.zeronumber,&ct)) {
cerr << "Do you really mean to divide by zero?" << endl;
exit(1);
}
else {
gen fa = K.inverse(fai);
gen te = _simplify(v-Inn(v,w)*fa*w,&ct);
K.vectred(te);
return te;
}
}
gen Polytope::Inn(gen v, gen w) {
gen res = K.vectconj(w)*H*v;
K.red(res);
return res;
}
gen Polytope::SqNorm(gen v) {
gen res = K.vectconj(v)*H*v;
K.red(res);
return K.convertToReal(res);
}
gen Polytope::BoxProd(gen v, gen w) {
gen X = K.vectconj(v)*H;
gen Y = K.vectconj(w)*H;
vecteur res(3);
res[0] = X[1]*Y[2] - X[2]*Y[1];
res[1] = X[2]*Y[0] - X[0]*Y[2];
res[2] = X[0]*Y[1] - X[1]*Y[0];
gen bp = gen(res);
K.vectred(bp);
return bp;
}
gen Polytope::refl(gen X, gen V, gen z) {
gen te = Inn(V,V);
if (te==K.zeronumber) {
cerr << "Trying to reflect across a null vector!" << endl;
exit(1);
}
else {
gen yo = _simplify(X + (z-1)*Inn(X,V)*K.inverse(te)*V,&ct);
K.vectred(yo);
return yo;
}
}
gen Polytope::reflMat(gen u, gen z) {
vecteur te;
gen te1 = refl(K.e1,u,z);
gen te2 = refl(K.e2,u,z);
gen te3 = refl(K.e3,u,z);
for (int k=0; k<3; k++) {
te.push_back(te1[k]);
te.push_back(te2[k]);
te.push_back(te3[k]);
}
return K.createMatrix(te);
}
Prism Polytope::createPrism(WVector v0, WVector v1, WVector v2){
Prism A;
A.jstart = 0;
A.mirror = v0;
A.sides.push_back(v1);
A.sides.push_back(v2);
vector<int> w; // provisoire, on trouvera w plus tard
A.apex = WVector(BoxProd(v1.coords,v2.coords),w);
A.apexProjection = Proj(A.apex.coords,A.mirror.coords);
A.cspine = BoxProd(A.apex.coords,A.apexProjection);
// the apex projection should be inside complex hyperbolic space
// (this is relevant only when the corresponding apex is outside)
int sg;
if (!K.checkSign(SqNorm(A.apexProjection),sg)) {
cerr << "Problem checking sign" << endl;
exit(1);
}
else {
if (sg>-1) {
cout << "Apex projection outside the ball!? (I will stop here)" << endl;
exit(1);
}
}
// the complex spine should intersect complex hyperbolic space
// (otherwise there is no natural bisector, in principle could still use extors)
if (!K.checkSign(SqNorm(A.cspine),sg)) {
cerr << "Problem checking sign" << endl;
exit(1);
}
else {
if (sg<0) {
cout << "Complex spine does not intersect the ball!? (I will stop here)" << endl;
exit(1);
}
}
// Could replace by the projection of any point not on the bisector...
// (then would need to know which one we want to take as X0,
// which is done by checking if it is on same side as p0).
A.X0 = Proj(p0,A.cspine); // should we test the signs?
A.X1 = reflectAcrossSpine(A.X0,A);
bool done = false;
int n = 2;
while (!done && n<100) {
gen M1 = reflMat(A.sides[0].coords,mult);
vector<int> wl = conjugateword(A.sides[0].word,A.sides[1].word);
gen vl = M1*A.sides[1].coords;
K.vectred(vl);
WVector Vl(vl,wl);
if (!testSame(Vl,A.sides[n-1])) {
A.sides.insert(A.sides.begin(),Vl);
n++;
A.jstart++;
}
else {
done = true;
}
if (!done) {
gen M2 = reflMat(A.sides[n-1].coords,multconj);
vector<int> wr = conjugateword(invertword(A.sides[n-1].word),A.sides[n-2].word);
gen vr = M2*A.sides[n-2].coords;
K.vectred(vr);
WVector Vr(vr,wr);
if (!testSame(Vr,A.sides[0])) {
A.sides.push_back(Vr);
n++;
}
else {
done = true;
}
}
}
if (!done) {
cerr << "Braiding cycle did not close up!" << endl;
exit(1);
}
else {
int k1 = 0;
int l1 = A.sides[0].word.size();
for (int k=1; k<A.sides.size(); k++) {
int l = A.sides[k].word.size();
if (l<l1) {
l1 = l;
k1 = k;
}
}
int k2;
if (k1==0) {
if (A.sides[A.sides.size()-1].word.size()<A.sides[1].word.size()) {
k2 = A.sides.size()-1;
}
else {
k2 = 1;
}
}
else {
k2 = (k1+1)%A.sides.size();
}
gen M1 = reflMat(A.sides[k1].coords,mult)*reflMat(A.sides[k2].coords,mult);
K.matred(M1);
int om1 = K.order(M1);
if (verbose) {
cout << "Product of order " << om1 << endl;
}
int bo = K.braidOrder(reflMat(A.sides[k1].coords,mult),reflMat(A.sides[k2].coords,mult));
if (verbose) {
cout << "Braid length " << bo << endl;
}
if (bo==2) {
cerr << "This pyramid is degenerate!" << endl;
}
vector<int> w0 = concat(A.sides[k1].word,A.sides[k2].word);
vector<int> w = concat(A.sides[k1].word,A.sides[k2].word);
bool isrefl = false;
int k=1;
gen M = M1;
while (k<om1 && !isrefl) {
gen dt = K.discrAdjusted(M);
isrefl = operator_equal(dt,K.zeronumber,&ct); // may still be parabolic
if (isrefl) {
int sg;
if (!K.checkSign(SqNorm(A.apex.coords),sg)) {
cerr << "Problem checking sign" << endl;
exit(1);
}
else {
if (sg>0) {
gen X1 = BoxProd(A.cspine,A.apex.coords);
gen X2 = M*X1;
K.vectred(X2);
isrefl = K.areDep(X1,X2);
}
else {
if (sg<0) {
gen X1 = A.apex.coords;
gen X2 = M*X1;
K.vectred(X2);
isrefl = K.areDep(X1,X2);
}
else {
if (verbose) {
cout << "Mirror intersection is an ideal point, parabolic element" << endl;
}
// don't know if we want to do anything...
// cout << "sg=" << sg << endl;
// cout << "Problem finding reflection power" << endl;
// exit(1);
}
}
}
}
if (isrefl) {
if (verbose) {
cout << "Found reflection, power " << k << endl;
}
A.toppower = k;
A.toporder = om1/k;
}
else {
M = M*M1;
w = concat(w,w0);
K.matred(M);
}
k++;
}
if (!isrefl) {
if (verbose) {
cout << "Did not find any reflection power..." << endl;
}
// exit(1);
}
useRelations(w);
A.apex.word = w;
if (verbose) {
cout << "word for apex=" << convertword(w) << endl;
}
int ns = A.sides.size();
if (verbose) {
cout << "Constructed a pyramid with " << ns << " sides!" << endl;
}
A.isSurrounded = false;
for (int k=0; k<ns; k++) {
A.freeRidges.push_back(k);
}
return A;
}
}
bool Polytope::isPrismNew(Prism A){
int k=0;
bool res = true;
while (res && k<faces.size()) {
res = !comparePrisms(A,faces[k]);
k++;
}
return res;
}
bool Polytope::isVertexNew(WVector V) {
return !isInList(V,vertices);
}
bool Polytope::comparePrisms(Prism A, Prism B) {
int ns = A.sides.size();
if (!testSame(A.mirror,B.mirror) || ns!=B.sides.size()) {
return false;
}
else {
return samePolygon(A.sides,B.sides);
}
}
bool Polytope::samePolygon(vector<WVector> V, vector<WVector> W){
int vs = V.size();
if (W.size()!=vs) {
return false;
}
else {
bool foundsame = false;
int k=0;
while (!foundsame && k<vs) {
foundsame = testSame(V[0],W[k]);
k++;
}
if (!foundsame) {
return false;
}
else {
int l=1;
bool same = true;
while (same && l<V.size()) {
k = k%vs;
same = testSame(V[l],W[k]);
k++;
l++;
}
return same;
}
}
}
void Polytope::updateFreeRidges(){
int nf = faces.size();
int ns = faces[nf-1].sides.size();
for (int k=0; k<ns; k++) {
// test if side #k is free...
vector<WVector> ridge1;
ridge1.push_back(faces[nf-1].sides[k]);
ridge1.push_back(faces[nf-1].sides[(k+1)%ns]);
ridge1.push_back(faces[nf-1].mirror);
bool isfree = true;
int l = 0;
while (isfree && l<nf-1) {
if (!faces[l].isSurrounded) {
int m=0;
bool foundNeighbor = false;
while (!foundNeighbor && m<faces[l].freeRidges.size()) {
vector<WVector> ridge2;
int mm = faces[l].freeRidges[m];
ridge2.push_back(faces[l].sides[mm]);
ridge2.push_back(faces[l].sides[(mm+1)%faces[l].sides.size()]);
ridge2.push_back(faces[l].mirror);
if (samePolygon(ridge1,ridge2)) {
// cout << "Same ridge..." << endl;
// cout << "Filling face #" << (nf-1) << endl;
faces[nf-1].fillRidge(k);
// cout << "Filling face #" << (l) << endl;
faces[l].fillRidge(mm);
foundNeighbor = true;
isfree = false;
}
m++;
}
}
l++;
// cout << "l=" << l << endl;
}
}
}
Prism Polytope::applyReflection(Prism A) {
gen M = reflMat(A.mirror.coords,mult);
vector<int> w = A.mirror.word;
Prism A1;
A1.toporder = A.toporder;
A1.toppower = A.toppower;
gen m = M*A.mirror.coords;
K.vectred(m);
vector<int> w1 = conjugateword(w,A.mirror.word);
A1.mirror = WVector(m,w1);
A1.apex = WVector(M*A.apex.coords,conjugateword(w,A.apex.word));
K.vectred(A1.apex.coords);
A1.apexProjection = M*A.apexProjection;
K.vectred(A1.apexProjection);
A1.cspine = M*A.cspine;
K.vectred(A1.cspine);
for (int k=0; k<A.sides.size(); k++) {
vector<int> wk = conjugateword(w,A.sides[k].word);
gen sk = M*A.sides[k].coords;
K.vectred(sk);
A1.sides.push_back(WVector(sk,wk));
}
for (int k=0; k<A.bottomface.size(); k++) {
vector<int> wk = conjugateword(w,A.bottomface[k].word);
gen sk = M*A.bottomface[k].coords;
K.vectred(sk);
A1.bottomface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.topface.size(); k++) {
vector<int> wk = conjugateword(w,A.topface[k].word);
gen sk = M*A.topface[k].coords;
K.vectred(sk);
A1.topface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.midvertices.size(); k++) {
vector<int> wk = conjugateword(w,A.midvertices[k].word);
gen sk = M*A.midvertices[k].coords;
K.vectred(sk);
A1.midvertices.push_back(WVector(sk,wk));
A1.midvertindices.push_back(A.midvertindices[k]);
}
A1.isSurrounded = false;
for (int k=0; k<A1.sides.size(); k++) {
A1.freeRidges.push_back(k);
}
A1.jstart = A.jstart;
return A1;
}
Prism Polytope::applyInverseReflection(Prism A) {
gen M = reflMat(A.mirror.coords,multconj);
vector<int> w = A.mirror.word;
Prism A1;
A1.toporder = A.toporder;
A1.toppower = A.toppower;
gen m = M*A.mirror.coords;
K.vectred(m);
vector<int> w1 = conjugateword(w,A.mirror.word);
A1.mirror = WVector(m,w1);
A1.apex = WVector(M*A.apex.coords,conjugateword(w,A.apex.word));
K.vectred(A1.apex.coords);
A1.apexProjection = M*A.apexProjection;
K.vectred(A1.apexProjection);
A1.cspine = M*A.cspine;
K.vectred(A1.cspine);
for (int k=0; k<A.sides.size(); k++) {
vector<int> wk = conjugateword(w,A.sides[k].word);
gen sk = M*A.sides[k].coords;
K.vectred(sk);
A1.sides.push_back(WVector(sk,wk));
}
for (int k=0; k<A.bottomface.size(); k++) {
vector<int> wk = conjugateword(w,A.bottomface[k].word);
gen sk = M*A.bottomface[k].coords;
K.vectred(sk);
A1.bottomface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.topface.size(); k++) {
vector<int> wk = conjugateword(w,A.topface[k].word);
gen sk = M*A.topface[k].coords;
K.vectred(sk);
A1.topface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.midvertices.size(); k++) {
vector<int> wk = conjugateword(w,A.midvertices[k].word);
gen sk = M*A.midvertices[k].coords;
K.vectred(sk);
A1.midvertices.push_back(WVector(sk,wk));
A1.midvertindices.push_back(A.midvertindices[k]);
}
A1.isSurrounded = false;
for (int k=0; k<A1.sides.size(); k++) {
A1.freeRidges.push_back(k);
}
A1.jstart = A.jstart;
return A1;
}
void Polytope::startFromFaceData() {
cout << "Will now bypass the algorithm and import face data..." << endl;
importFaceData();
}
void Polytope::expand() {
cout << "There are now " << faces.size() << " faces." << endl;
if (faces.size()>500) {
cout << "Found over 500 faces, are you sure you want to continue?!" << endl;
}
else {
bool closed = true;
int nf = faces.size();
int n = 0;
while (closed && n < nf) {
closed = faces[n].isSurrounded;
n++;
}
if (closed) {
cout << "The polytope has no free ridge!" << endl;
bool hasremoved = false;
for (int k=0; k<facePOrbits.size(); k++) {
cout << convertword(facePOrbits[k]) << endl;
}
for (int k=facePOrbits.size()-1; k>=0; k--) {
if (faces[facePOrbits[k][0]].sides.size()<3) {
hasremoved = true;
// cout << "Should remove orbit #" << k << endl;
int nr = facePOrbits[k].size();
for (int l=nr-1; l>=0; l--) {
// cout << "Removing face #" << facePOrbits[k][l] << endl;
faces.erase(faces.begin()+facePOrbits[k][l]);
}
for (int m=facePOrbits.size()-1; m>k; m--) {
for (int n=0; n<facePOrbits[m].size(); n++) {
facePOrbits[m][n] = facePOrbits[m][n] - nr;
}
}
facePOrbits.erase(facePOrbits.begin()+k);
// need to adjust facePOrbits indices!!!!
}
}
if (hasremoved) {
cout << "REMOVED SOME DEGENERATE PRISMS (hopefully this has no unpleasant consequences)!!" << endl;
}
exportFaceData();
checkPairings();
computeAllVertices();
computeAllEdges();
computeAllRidges();
cout << endl;
if (emb_dim1) {
cout << "Will now check that the 1-skeleton is embedded (there are " << edgePOrbits.size() << " orbits of edges)" << endl;
for (int k=0; k<edgePOrbits.size(); k++) {
checkEdge(edgePOrbits[k][0]);
}
cout << "If you read this, the 1-skeleton is embedded!" << endl;
cout << endl;
}
if (emb_dim2) {
cout << "Will now check that G-polygons defining ridges are embedded" << endl;
cout << " be patient, there are " << ridgePOrbits.size() << " P-orbits of ridges..." << endl;
for (int k=0; k<ridgePOrbits.size(); k++) {
cout << endl;
cout << "Ridge P-orbit #" << k << "..." << endl;
checkRidge(ridgePOrbits[k][0]);
}
cout << " " << endl;
cout << " * * " << endl;
cout << " \\_/ " << endl;
cout << " " << endl;
cout << "If you read this, the program checked that the polytope for " << K.tag << " is embedded!" << endl;
cout << " Used at most " << K.ndrecord << " digits to perform the computations." << endl;
cout << endl;
}
if (check_cycles) {
checkCycles();
cout << endl;
}
if (check_euler) {
computeEulerCharacteristic();
cout << endl;
}
if (check_sphere) {
checkLinks();
checkSphere();
cout << endl;
}
cout << endl;
isArithmetic();
/* bool is_arith = isArithmetic();
if (is_arith) {
cout << "Sorry, this group is arithmetic." << endl;
}
else {
cout << "The group is NOT arithmetic, NA(" << naindex << ")" << endl;
}*/
cout << endl;
cout << "Done studying group " << K.tag << endl;
cout << "If you read this message, all requested checks were successful:" << endl;
if (emb_dim1) {
cout << " 1-skeleton is embedded" << endl;
}
if (emb_dim2) {
cout << " 2-skeleton is embedded" << endl;
}
if (check_sphere) {
cout << " The boundary of the polytope should be a sphere" << endl;
cout << " (to be completely sure, you should simplify the presentation using GAP)" << endl;
}
if (check_cycles) {
cout << " Hypotheses of the Poincaré polyhedron theorem hold" << endl;
}
if (check_euler) {
cout << " I computed the Euler characteristic, it is " << euler_char << endl;
}
if (iscompact) {
cout << "The group is cocompact" << endl;
}
else {
cout << "The group is not cocompact" << endl;
}
if (isarithmeticitychecked) {
if (isarithmetic) {
cout << "The group is arithmetic" << endl;
}
else {
cout << "The group is non-arithmetic!" << endl;
}
}
else {
cout << "I did not check arithmeticity" << endl;
}
cout << endl;
// do this only to produce a picture of the polyhedron
if (draw_pics) {
cout << "I will now draw pictures of the polyhedron, in projections onto the axes of P, one for each axis" << endl;
cout << "The pictures will be stored in in the pics directory, they need to be compiled with asymptote." << endl;
drawProjection(1);
drawProjection(2);
for (int k=0; k<facePOrbits.size(); k++) {
drawFace(facePOrbits[k][0]);
if (needppower) {
// cout << "extramirror: " << extramirror << endl;
gen te2 = Inn(faces[facePOrbits[k][0]].apexProjection,extramirror);
if (operator_equal(te2,K.zeronumber,&ct)) {
int nb = faces[facePOrbits[k][0]].bottomface.size();
if (nb%2==0) {
nb = nb/2;
}
else {
nb = (nb-3)/2;
}
drawFaceSector(facePOrbits[k][0],nb,nb+1);
}
}
else {
int nb = faces[facePOrbits[k][0]].bottomface.size();
if (nb%2==0) {
nb = nb/2;
}
else {
nb = (nb-3)/2;
}
drawFaceSector(facePOrbits[k][0],nb,nb+1);
}
}
cout << "Done drawing pics" << endl;
c_end = std::clock();
long double time = (c_end-c_start)/CLOCKS_PER_SEC;
cout << "Total time elapsed : " << convert_time(time);
}
}
else {
// not closed
// (this is the main part of the expand procedure)
// Should not add degenerate prisms!!!
gen M = reflMat(faces[n-1].mirror.coords,mult);
gen Mi = reflMat(faces[n-1].mirror.coords,multconj);
gen U0 = M*faces[n-1].sides[0].coords;
K.vectred(U0);
gen U1 = M*faces[n-1].sides[1].coords;
K.vectred(U1);
gen V0 = Mi*faces[n-1].sides[0].coords;
K.vectred(V0);
gen V1 = Mi*faces[n-1].sides[1].coords;
K.vectred(V1);
WVector U0w = WVector(U0,conjugateword(faces[n-1].mirror.word,faces[n-1].sides[0].word));
WVector U1w = WVector(U1,conjugateword(faces[n-1].mirror.word,faces[n-1].sides[1].word));
Prism B1 = createPrism(faces[n-1].mirror, U0w, U1w);
WVector V0w = WVector(V0,conjugateword(invertword(faces[n-1].mirror.word),faces[n-1].sides[0].word));
WVector V1w = WVector(V1,conjugateword(invertword(faces[n-1].mirror.word),faces[n-1].sides[1].word));
Prism B2 = createPrism(faces[n-1].mirror, V0w, V1w);
gen N1 = reflMat(U0,mult);
gen N2 = reflMat(U1,mult);
gen N3 = reflMat(V0,mult);
gen N4 = reflMat(V1,mult);
int oo1 = K.braidOrder(N1,N2);
int oo2 = K.braidOrder(N3,N4);
if (verbose) {
if (oo1==2) {
cout << "SHOULD NOT CHOOSE B1, degenerate prism!" << endl;
};
if (oo2==2) {
cout << "SHOULD NOT CHOOSE B2, degenerate prism!" << endl;
};
cout << "Braid length for B1: " << oo1 << endl;
cout << "Braid length for B2: " << oo2 << endl;
cout << "B1: " << B1 << endl;
cout << "B2: " << B2 << endl;
cout << "John's test (for inverses)" << endl;
}
vector<int> wt1 = concat( faces[n-1].mirror.word,
concat(conjugateword(faces[n-1].mirror.word,faces[n-1].sides[0].word),
conjugateword(faces[n-1].mirror.word,faces[n-1].sides[1].word)) );
vector<int> wt2 = concat( concat(conjugateword(faces[n-1].mirror.word,faces[n-1].sides[0].word),
conjugateword(faces[n-1].mirror.word,faces[n-1].sides[1].word)),
faces[n-1].mirror.word );
vector<int> wt3 = concat( invertword(faces[n-1].mirror.word),
concat( conjugateword(invertword(faces[n-1].mirror.word),faces[n-1].sides[0].word),
conjugateword(invertword(faces[n-1].mirror.word),faces[n-1].sides[1].word)) );
vector<int> wt4 = concat( concat(conjugateword(invertword(faces[n-1].mirror.word),faces[n-1].sides[0].word),
conjugateword(invertword(faces[n-1].mirror.word),faces[n-1].sides[1].word)),
invertword(faces[n-1].mirror.word));
useRelations(wt1);
useRelations(wt2);
useRelations(wt3);
useRelations(wt4);
if (verbose) {
cout << "wt1=" << convertword(wt1) << endl;
cout << "wt2=" << convertword(wt2) << endl;
cout << "wt3=" << convertword(wt3) << endl;
cout << "wt4=" << convertword(wt4) << endl;
}
bool test1 = (wt1==word_123 || wt2==word_123);
bool test2 = (wt3==word_123 || wt4==word_123);
bool done;
if (test1) {
if (test2) {
cerr << "John's test fails, both prisms work" << endl;
exit(1);
}
else {
if (isPrismNew(B1)) {
computeVertices(B1);
useRelations(B1);
if (verbose) {
cout << "Adding new face.." << endl;
}
addFaceOrbit(B1);
done = true;
}
}
}
else {
if (test2) {
if (isPrismNew(B2)) {
computeVertices(B2);
useRelations(B2);
if (verbose) {
cout << "Adding new face.." << endl; }
addFaceOrbit(B2);
done = true;
}
}
}
int k = faces[n-1].freeRidges[0];
if (verbose) {
cout << "Creating two new prisms: " << endl;
}
gen M1 = reflMat(faces[n-1].mirror.coords,mult);
gen M2 = reflMat(faces[n-1].sides[k].coords,mult);
gen M3 = reflMat(faces[n-1].sides[(k+1)%faces[n-1].sides.size()].coords,mult);
gen M4 = reflMat(faces[n-1].mirror.coords,mult);
int o1 = K.braidOrder(M1,M2);
int o2 = K.braidOrder(M3,M4);
if (verbose) {
cout << "Braid length for A1: " << o1 << endl;
cout << "Braid length for A2: " << o2 << endl;
if (o1==2) {
cout << "SHOULD NOT CHOOSE A1, degenerate prism!" << endl;
};
if (o2==2) {
cout << "SHOULD NOT CHOOSE A2, degenerate prism!" << endl;
};
}
Prism A1 = createPrism(faces[n-1].sides[(k+1)%faces[n-1].sides.size()],
faces[n-1].mirror,
faces[n-1].sides[k]);
Prism A2 = createPrism(faces[n-1].sides[k],
faces[n-1].sides[(k+1)%faces[n-1].sides.size()],
faces[n-1].mirror);
if (verbose) {
cout << "A1=" << A1 << endl;
cout << "A2=" << A2 << endl;
cout << "John's test" << endl;
}
wt1 = concat( A1.mirror.word,
concat(faces[n-1].mirror.word, faces[n-1].sides[k].word) );
wt2 = concat( concat(faces[n-1].mirror.word, faces[n-1].sides[k].word),
A1.mirror.word );
wt3 = concat( A2.mirror.word, concat(faces[n-1].sides[(k+1)%faces[n-1].sides.size()].word,
faces[n-1].mirror.word) );
wt4 = concat( concat(faces[n-1].sides[(k+1)%faces[n-1].sides.size()].word, faces[n-1].mirror.word),
A2.mirror.word );
useRelations(wt1);
useRelations(wt2);
useRelations(wt3);
useRelations(wt4);
if (verbose) {
cout << "test words for A1: " << convertword(wt1) << " " << convertword(wt2) << endl;
cout << "test words for A2: " << convertword(wt3) << " " << convertword(wt4) << endl;
}
test1 = (wt1==word_123 || wt2==word_123);
test2 = (wt3==word_123 || wt4==word_123);
if (test1) {
if (test2) {
cerr << "John's test fails, both prisms work" << endl;
exit(1);
}
else {
if (isPrismNew(A1)) {
computeVertices(A1);
useRelations(A1);
if (verbose) {
cout << "Adding new face (A1).." << endl; }
addFaceOrbit(A1);
done = true;
}
}
}
else {
if (test2) {
if (isPrismNew(A2)) {
computeVertices(A2);
useRelations(A2);
if (verbose) {
cout << "Adding new face (A2).." << endl; }
addFaceOrbit(A2);
done = true;
}
}
}
expand();
}
}
}
vecteur Polytope::eulerdim0() {
gen ed0_top = K.zeronumber; // to keep track of topological euler char (without orbifold weights)
gen ed0 = K.zeronumber;
vector<vector<int> > vertexOrbits;
for (int k=0; k<vertexPOrbits.size(); k++) {
vector<int> ok;
ok.push_back(k);
vertexOrbits.push_back(ok);
}
for (int k=0; k<vertexPOrbitPairings.size(); k++) {
cout << vertexPOrbitPairings[k][0] << " -> " << vertexPOrbitPairings[k][1] << endl;
cout << " via " << convertword(vertexPOrbitPairingMaps[k]) << endl;
int u1 = -1;
bool fd1 = false;
while (!fd1 && u1!=vertexOrbits.size()-1) {
u1++;
int v1 = -1;
while (!fd1 && v1!=vertexOrbits[u1].size()-1) {
v1++;
fd1 = vertexPOrbitPairings[k][0]==vertexOrbits[u1][v1];
}
}
int u2 = -1;
bool fd2 = false;
while (!fd2 && u2!=vertexOrbits.size()-1) {
u2++;
int v2 = -1;
while (!fd2 && v2!=vertexOrbits[u2].size()-1) {
v2++;
fd2 = vertexPOrbitPairings[k][1]==vertexOrbits[u2][v2];
}
}
if (!fd1 || !fd1) {
cerr << "Problem identifiying indices in vertexPOrbits..." << endl;
exit(1);
}
else {
if (u1!=u2) {
for (int z=0; z<vertexOrbits[u2].size(); z++) {
vertexOrbits[u1].push_back(vertexOrbits[u2][z]);
}
vertexOrbits.erase(vertexOrbits.begin()+u2);
}
}
// probably better to construct the graph right away, to compute its connected components, then the fund group of each component...
// (I will not do that for now, this is not the time-consuming part of the program)
}
iscompact = true;
cout << "Vertex orbits (under side pairings, * denotes an ideal vertex): " << endl;
for (int z=0; z<vertexOrbits.size(); z++) {
cout << "[";
cout << convertword(vertexOrbits[z]) << "]";
if (vertices[vertexPOrbits[vertexOrbits[z][0]][0]].faceindices[0]==-1) {
iscompact = false;
cout << "*";
}
cout << ", ";
}
cout << endl;
cout << "There are " << vertexOrbits.size() << " orbits of vertices" << endl;
cout << "Still need to compute the order of stabilizer (only when finite vertex!)" << endl;
for (int z=0; z<vertexOrbits.size(); z++) {
vector<int> vo = vertexOrbits[z];
bool needpowerofp;
int baseptindex=0;
int bpi;
if (needppower) {
needpowerofp = false;
bpi = -1;
while (!needpowerofp && bpi!=vo.size()-1) {
bpi++;
gen X = vertices[vertexPOrbits[vo[bpi]][0]].coords;
needpowerofp = operator_equal(Inn(extramirror,X),K.zeronumber,&ct);
}
if (needpowerofp) {
baseptindex = bpi;
}
}
cout << "Computing stabilizer of vertex P-Orbit #" << vo[baseptindex] << endl;
if (needpowerofp) {
cout << "Some element in this orbit (index " << bpi << ") is on mirror of power of P!" << endl;
}
gen XX = vertices[vertexPOrbits[vo[baseptindex]][0]].coords;
vector<int> u1, u2;
for (int k=0; k<faces.size(); k++) {
Prism A = faces[k];
gen teXX = Inn(XX,A.mirror.coords);
K.red(teXX);
if (is_zero(teXX,&ct)) {
cout << "On mirror of " << A << endl;
u1 = A.mirror.word;
}
teXX = Inn(XX,A.apex.coords);
K.red(teXX);
if (is_zero(teXX,&ct) && A.topface.size()>1) {
cout << "On top face of " << A << endl;
u2 = concat(A.sides[A.jstart].word, A.sides[(A.jstart+1)%A.sides.size()].word),
cout << "(" << convertword(u2) << ")^" << A.toppower << " (refl of order " << A.toporder << ")" << endl;
}
}
// not sure what to do with u1, u2, are there better choices?
// a given mirror will be on many mirrors...
vector<vector<int> > stab;
if (vo.size()>1) {
vector<vector<int> > graph_edges;
vector<vector<int> > maps;
for (int uu=0; uu<vertexPOrbitPairings.size(); uu++) {
if (find(vo.begin(),vo.end(),vertexPOrbitPairings[uu][0])!=vo.end()) {
graph_edges.push_back(vertexPOrbitPairings[uu]);
maps.push_back(vertexPOrbitPairingMaps[uu]);
}
}
sgraph G(graph_edges);
vector<vector<int> > stabgens;
vector<vector<bool> > orientations;
G.fundamental_group(vo[baseptindex],stabgens,orientations);
for (int kk=0; kk<stabgens.size(); kk++) {
vector<int> yo;
for (int ll=0; ll<stabgens[kk].size(); ll++) {
if (orientations[kk][ll]) {
yo = concat(maps[stabgens[kk][ll]],yo);
}
else {
yo = concat(invertword(maps[stabgens[kk][ll]]),yo);
}
}
stab.push_back(yo);
}
}
else {
// there is a single vertex, won't use graph routine for this (just take all pairings as generators)
for (int uu=0; uu<vertexPOrbitPairings.size(); uu++) {
if (find(vo.begin(),vo.end(),vertexPOrbitPairings[uu][0])!=vo.end()) {
stab.push_back(vertexPOrbitPairingMaps[uu]);
}
}
}
cout << "Generators of stab:" << endl;
vector<gen> stabgens;
vector<int> trivial_elts;
for (int y=0; y<stab.size(); y++) {
if (stab[y].size()>0) {
cout << " " << convertword(stab[y]) << endl;
gen M = evalWord(stab[y]);
int orm = K.order(M);
if (orm>0) {
cout << " (order " << orm << ")" << endl;
}
else {
cout << "Infinite order" << endl;
}
if (orm>1) {
gen dt = K.discrAdjusted(M);
if (operator_equal(dt,K.zeronumber,&ct)){
gen mirr;
if (!findMirror(M,mirr)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
gen te = SqNorm(mirr);
if (verbose) {
cout << "te=" << te << endl;
}
int sg;
if (K.checkSign(te,sg)) {
if (sg<0) {
cout << " (\"reflection\" in point)" << endl;
}
else {
if (sg>0) {
cout << " (reflection in line)" << endl;
}
else {
cout << "Single e-val gives ideal point, should this happen??" << endl;
}
}
}
else {
cout << "Trouble locating mirror (inside or outside the ball)" << endl;
exit(1);
}
}
else {
// distinct eigenvalues, may want to compute rotation angles
cout << " (distinct eigenvalues)" << endl;
cout << endl;
}
}
if (!K.isScalar(M)) {
stabgens.push_back(M);
gen Z1 = vertices[vertexPOrbits[vo[baseptindex]][0]].coords;
gen Z2 = M*Z1;
K.vectred(Z2);
if (K.areDep(Z1,Z2)) {
cout << "Check!" << endl;
}
else {
cout << "Problem, matrix is actually not in stab!!" << endl;
}
}
else {
cout << convertword(stab[y]) << " is identity" << endl;
trivial_elts.push_back(y);
}
}
}
for (int z=trivial_elts.size()-1; z>=0; z--) {
stab.erase(stab.begin()+trivial_elts[z]);
}
cout << endl;
if (vertices[vertexPOrbits[vo[baseptindex]][0]].faceindices[0]!=-1) {
// the commented out method runs slow, to be used only for small groups
/* cout << "Creating finite group.." << endl;
FiniteGroup L(tag);
L.addElements(stabgens);
L.expandToGroup();*/
gen og;
gen ogmax = K.zeronumber;
bool needpowerofp;
if (needppower) {
needpowerofp = operator_equal(Inn(extramirror,vertices[vertexPOrbits[vo[0]][0]].coords),K.zeronumber,&ct);
}
else {
needpowerofp = false;
}
if (needpowerofp) {
cout << "THIS POINT IS ON THE MIRROR OF P^" << orderofppower << endl;
stabgens.push_back(Ppower);
}
/*
* SHOULD WORK WITH 2x2 MATRICES HERE!
* may also want to use the fact that we have a candidate for the group, where we know the center?
*
*/
// if (K.tag!="5s4c" && K.tag!="3s5") {
if (true) {
// for the excluded groups we have large stabilizers..
vector<gen> sg2d;
// would like to find a mirror of reflection first
gen mii;
bool foundrefl = false;
int zz=-1;
while (!foundrefl && zz!=stab.size()-1) {
zz++;
vector<int> w = stab[zz];
if (w.size()%2==1) {
int n = (w.size()-1)/2;
bool is_pal = true;
int uu=0;
while (is_pal && uu<n) {
is_pal = (w[uu]==-w[w.size()-1-uu]);
uu++;
}
foundrefl = is_pal;
}
}
if (foundrefl) {
if (verbose) {
cout << "Found a reflection: " << convertword(stab[zz]) << endl;
}
int n = (stab[zz].size()-1)/2;
mii = _col(makesequence(K.Id,abs(stab[zz][n])-1),&ct);
if (n>0) {
vector<int> w;
for (int jj=0; jj<n; jj++) {
w.push_back(stab[zz][jj]);
}
mii = evalWord(w)*mii;
K.vectred(mii);
}
if (verbose) {
cout << "mirror=" << mii << endl;
}
}
else {
// use any vector and do Gramm-Schmidt?
mii = K.e1; // (this will not always work?!)
}
vecteur basis;
basis.push_back(vertices[vertexPOrbits[vo[baseptindex]][0]].coords);
basis.push_back( mii );
basis.push_back(BoxProd(basis[0],basis[1]));
gen A = _tran(gen(basis),&ct);
gen Ai = K.matinverse(A);
for (int tt=0; tt<stabgens.size(); tt++) {
gen M = Ai*stabgens[tt]*A;
K.matred(M);
gen coe = K.inverse(M[0][0]);
vecteur r1;
r1.push_back(M[1][1]*coe);
r1.push_back(M[1][2]*coe);
vecteur r2;
r2.push_back(M[2][1]*coe);
r2.push_back(M[2][2]*coe);
vecteur rows;
rows.push_back(r1);
rows.push_back(r2);
gen R = gen(rows);
K.matred(R);
sg2d.push_back(R);
}
FiniteLinearGroup L(K);
L.addElements(sg2d);
int te_ord_gp;
bool ters = L.studyReflectionSubgroup(te_ord_gp);
// if (false) {
if (ters) {
cout << "The stabilizer is a 2-generator reflection group, computation is easy" << endl;
cout << " (it has order " << te_ord_gp << ")" << endl;
ogmax = te_ord_gp;
cout << endl;
}
else {
cout << "The stabilizer is a not 2-generator reflection group" << endl;
cout << "I'm not quite sure how to get the order of stabilizer, will use brute force (this may take some time!)" << endl;
// cout << "Creating finite group (will first conjugate to linear group of 2x2 matrices).." << endl;
cout << endl;
L.expandToGroup();
ogmax = L.elements.size();
vector<int> reflinds;
for (int uu=1; uu<L.elements.size(); uu++) {
gen M = L.elements[uu];
int ouu = K.linearorder2d(M);
if (ouu>1) {
gen Mi = normal(M-K.Id2,&ct);
gen dt = K.det(Mi);
if (operator_equal(dt,K.zeronumber,&ct)){
reflinds.push_back(uu);
}
}
}
cout << "There are " << reflinds.size() << " reflections in this group" << endl;
FiniteLinearGroup LR(K);
for (int uu=0; uu<reflinds.size(); uu++) {
LR.addElement(L.elements[reflinds[uu]]);
}
LR.expandToGroup();
cout << "Subgroup generated by reflections has order " << LR.elements.size() << endl;
if (LR.elements.size()<L.elements.size()) {
cout << "The stabilizer is NOT generated by reflections, this will give a singular point of the quotient" << endl;
cout << endl;
}
else {
cout << "The stabilizer is generated by reflections!" << endl;
cout << endl;
}
cout << endl;
}
// cout << "Stab is generated by " << L.elements.size() << " elements" << endl;
}
else {
cout << "This group has a vertex stabilizer of very high order!" << endl;
cout << "I will use the order of the known stabilizer, this is not valid in all generality (but it is in this case)" << endl;
vector<WVector> mi = findMirrors(vertices[vertexPOrbits[vo[baseptindex]][0]]);
vector<gen> stabgens_guess;
for (int kk=0; kk<mi.size(); kk++) {
cout << "Mirror " << convertword(mi[kk].word) << " contains vertex" << endl;
stabgens_guess.push_back(evalWord(mi[kk].word));
}
for (int kk=0; kk<mi.size(); kk++) {
stabgens_guess.push_back(evalWord(invertword(mi[kk].word)));
}
int nsg = stabgens_guess.size()/2;
int kk_max=0;
int ll_max=0;
for (int kk=0; kk<nsg; kk++) {
int ok = K.order(stabgens_guess[kk]);
for (int ll=kk+1; ll<nsg; ll++) {
int ol = K.order(stabgens_guess[ll]);
int te = K.braidOrder(stabgens_guess[kk],stabgens_guess[ll],20); // 10 is small, but it works for sporadic groups...
if (te>-1) {
cout << "Stab gens #" << kk << " (order " << ok << ") and " << ll << " (order " << ol << ") braid with order " << te << endl;
if (te>2) {
og = gen("8",&ct);
gen den = K.onenumber/ok + K.onenumber/ol + K.twonumber/te - K.onenumber; // formula from Mostow, say
og = og/(te*den*den);
cout << " these generate a group of order " << og << endl;
}
else {
if (te==2) {
og = ok*ol;
}
else {
cerr << "Braid length 0 or 1, this should not happen??" << endl;
exit(1);
}
}
if (is_greater(og,ogmax,&ct)) {
ogmax = og;
kk_max = kk;
ll_max = ll;
}
}
}
}
cout << "Order of stab should be " << ogmax << endl;
cout << " (should check that the generators from incidence graph are all in the guessed stabilizer)" << endl;
}
cout << endl;
ed0 = ed0+K.onenumber/ogmax;
ed0_top = ed0_top+K.onenumber;
}
}
vecteur te;
te.push_back(ed0);
te.push_back(ed0_top);
return te;
}
bool Polytope::expressAsWord(gen M, vecteur list, gen fixed_pt, gen mirror, vector<int> &inds) {
// is never used anywhere, I believe
int ndsave = K.nd;
K.increasePrecision();
inds.clear();
gen other_vect = BoxProd(fixed_pt,mirror);
vecteur ov;
ov.push_back(fixed_pt);
ov.push_back(mirror);
ov.push_back(other_vect);
gen O = _tran(gen(ov),&ct);
// then need its inverse...
gen detO = K.det(O);
K.red(detO);
if (operator_equal(detO,K.zeronumber,&ct)) {
cerr << "Problem in express as word, I expected a basis of C^3" << endl;
exit(1);
}
else {
vecteur coi;
coi.push_back(O[1][1]*O[2][2]-O[1][2]*O[2][1]);
coi.push_back(-O[1][0]*O[2][2]+O[1][2]*O[2][0]);
coi.push_back(O[1][0]*O[2][1]-O[1][1]*O[2][0]);
coi.push_back(-O[0][1]*O[2][2]+O[0][2]*O[2][1]);
coi.push_back(O[0][0]*O[2][2]-O[0][2]*O[2][0]);
coi.push_back(-O[0][0]*O[2][1]+O[0][1]*O[2][0]);
coi.push_back(O[0][1]*O[1][2]-O[0][2]*O[1][1]);
coi.push_back(-O[0][0]*O[1][2]+O[0][2]*O[1][0]);
coi.push_back(O[0][0]*O[1][1]-O[0][1]*O[1][0]);
gen Oi = _tran(K.createMatrix(coi),&ct)*K.inverse(detO);
K.matred(Oi);
gen te = O*Oi;
K.matred(te);
cout << "Check, should be Id: " << te << endl;
gen On = K.matevali(O);
gen Oin = K.matevali(Oi);
cout << "Oin: " << Oin << endl;
bool found = false;
int count = 0;
gen base_pt = p0;
// not shoud how important it is to take p0,
// we want to take something strictly inside the polytope
gen goal = conj(Oin*(K.matevali(M)*p0),&ct);
goal = goal/goal[0];
cout << "goal: " << goal << endl;
gen den = sqrt(re(goal[1]*conj(goal[1],&ct)+goal[2]*conj(goal[2],&ct),&ct),&ct);
gen C = K.Id;
while (!found && count<100) {
gen max = convert_interval(-1,K.nd,&ct);
int lval;
for (int l=0; l<list.size(); l++) {
gen U = Oin*(K.matevali(list[l])*base_pt);
U = U/U[0];
gen den2 = sqrt(re(U[1]*conj(U[1],&ct)+U[2]*conj(U[2],&ct),&ct),&ct);
gen val = re(U[1]*goal[1]+U[2]*goal[2],&ct)/(den*den2);
cout << "val #" << l << ":" << val << endl;
if (is_greater(val,max+K.prec,&ct)) {
max = val;
lval = l;
}
}
inds.insert(inds.begin(),lval);
cout << "inds=" << convertword(inds) << endl;
base_pt = K.matevali(list[lval])*base_pt;
C = list[lval]*C;
K.matred(C);
found = K.isMultiple(C,M);
count++;
}
return found;
}
K.nd = ndsave;
K.lowerPrecision();
}
vecteur Polytope::eulerdim1() {
gen res_top = K.zeronumber;
gen res = K.zeronumber;
vector<vector<int> > edgePOrbitPairings;
vector<vector<int> > edgePOrbitPairingMaps;
vector<vector<int> > edgeOrbits;
for (int k=0; k<edgePOrbits.size(); k++) {
vector<int> ok;
ok.push_back(k);
edgeOrbits.push_back(ok);
vector<int> inds = edges[edgePOrbits[k][0]].faceindices;
for (int l=0; l<inds.size(); l++) {
int image = applyPairingToEdge(inds[l],edgePOrbits[k][0]);
cout << "Pairing for face #" << inds[l] << " maps edge #" << edgePOrbits[k][0] << " to edge #" << image << endl;
int m=-1;
int n;
bool fd = false;
while (!fd && m!=edgePOrbits.size()-1) {
m++;
n = -1;
while (!fd && n!=edgePOrbits[m].size()-1) {
n++;
fd = (image==edgePOrbits[m][n]);
}
}
if (!fd) {
cerr << "Problem identifying image edge in a P-orbit" << endl;
exit(1);
}
else {
cout << "This gives a map from P-orbit #" << k << " to P-orbit #" << m << ", at index " << n << endl;
vector<int> pa;
pa.push_back(k);
pa.push_back(m);
edgePOrbitPairings.push_back(pa);
vector<int> w;
if (faces[inds[l]].invertpairing) {
w = invertword(faces[inds[l]].mirror.word);
}
else {
w = concat(w,faces[inds[l]].mirror.word);
}
if (n>orderofp/2) {
for (int zz=0; zz<orderofp-n; zz++) {
w.insert(w.begin(),4);
}
}
else {
for (int zz=0; zz<n; zz++) {
w.insert(w.begin(),-4);
}
}
cout << "Map: " << convertword(w) << endl;
edgePOrbitPairingMaps.push_back(w);
}
}
}
for (int k=0; k<edgePOrbitPairings.size(); k++) {
int u1 = -1;
bool fd1 = false;
while (!fd1 && u1!=edgeOrbits.size()-1) {
u1++;
int v1 = -1;
while (!fd1 && v1!=edgeOrbits[u1].size()-1) {
v1++;
fd1 = edgePOrbitPairings[k][0]==edgeOrbits[u1][v1];
}
}
int u2 = -1;
bool fd2 = false;
while (!fd2 && u2!=edgeOrbits.size()-1) {
u2++;
int v2 = -1;
while (!fd2 && v2!=edgeOrbits[u2].size()-1) {
v2++;
fd2 = edgePOrbitPairings[k][1]==edgeOrbits[u2][v2];
}
}
if (!fd1 || !fd2) {
cerr << "Problem identifiying indices in vertexPOrbits..." << endl;
exit(1);
}
else {
if (u1!=u2) {
for (int z=0; z<edgeOrbits[u2].size(); z++) {
edgeOrbits[u1].push_back(edgeOrbits[u2][z]);
}
edgeOrbits.erase(edgeOrbits.begin()+u2);
}
}
}
cout << "Edge orbits (under side pairings): " << endl;
for (int z=0; z<edgeOrbits.size(); z++) {
cout << "[";
cout << convertword(edgeOrbits[z]) << "]";
cout << ", ";
}
cout << endl;
cout << "There are " << edgeOrbits.size() << " orbits of edges" << endl;
cout << "Still need to compute the order of stabilizer..." << endl;
for (int z=0; z<edgeOrbits.size(); z++) {
vector<int> vo = edgeOrbits[z];
bool needpowerofp = false;
gen Xo, Xe;
int baseptindex = 0;
if (needppower) {
needpowerofp = false;
int bpi = -1;
while (!needpowerofp && bpi!=vo.size()-1) {
bpi++;
Xo = vertices[edges[edgePOrbits[vo[bpi]][0]].origin].coords;
Xe = vertices[edges[edgePOrbits[vo[bpi]][0]].end].coords;
needpowerofp = operator_equal(Inn(extramirror,Xo),K.zeronumber,&ct) && operator_equal(Inn(extramirror,Xe),K.zeronumber,&ct);
gen yo = Inn(extramirror,BoxProd(Xo,Xe));
if (operator_equal(yo,K.zeronumber,&ct)) {
cout << "Edge is orthogonal to mirror of P^" << orderofppower << endl;
// need to check if some POWER of Ppower flips the edge!
gen A = Ppower;
int mmax = (orderofp/orderofppower)/2;
int m = 1;
gen Xoi = Xo;
gen Xei = Xe;
bool fd = false;
while (m<=mmax && !fd) {
Xoi = Ppower*Xoi;
K.vectred(Xoi);
Xei = Ppower*Xei;
K.vectred(Xei);
A = A*Ppower;
K.matred(A);
fd = (K.areDep(Xoi,Xe) && K.areDep(Xei,Xo));
m++;
}
if (fd) {
cout << "FLIP!" << endl;
}
}
}
if (needpowerofp) {
baseptindex = bpi;
cout << "Some element in this orbit (index " << bpi << ") is on mirror of P^" << orderofppower << endl;
cout << " (it joins v#" << edges[edgePOrbits[vo[bpi]][0]].origin << " and v#" << edges[edgePOrbits[vo[bpi]][0]].end << ")" << endl;
}
else {
cout << "No element in this orbit is on mirror of power of P!" << endl;
Xo = vertices[edges[edgePOrbits[vo[baseptindex]][0]].origin].coords;
Xe = vertices[edges[edgePOrbits[vo[baseptindex]][0]].end].coords;
}
}
else {
// not s5
Xo = vertices[edges[edgePOrbits[vo[baseptindex]][0]].origin].coords;
Xe = vertices[edges[edgePOrbits[vo[baseptindex]][0]].end].coords;
}
cout << "Computing stabilizer of edge P-Orbit #" << vo[baseptindex] << endl;
vector<vector<int> > stab;
if (vo.size()>1) {
vector<vector<int> > graph_edges;
vector<vector<int> > maps;
for (int uu=0; uu<edgePOrbitPairings.size(); uu++) {
if (find(vo.begin(),vo.end(),edgePOrbitPairings[uu][0])!=vo.end()) {
graph_edges.push_back(edgePOrbitPairings[uu]);
maps.push_back(edgePOrbitPairingMaps[uu]);
}
}
sgraph G(graph_edges);
vector<vector<int> > stabgens;
vector<vector<bool> > orientations;
G.fundamental_group(vo[baseptindex],stabgens,orientations);
for (int kk=0; kk<stabgens.size(); kk++) {
vector<int> yo;
for (int ll=0; ll<stabgens[kk].size(); ll++) {
if (orientations[kk][ll]) {
yo = concat(maps[stabgens[kk][ll]],yo);
}
else {
yo = concat(invertword(maps[stabgens[kk][ll]]),yo);
}
}
if (yo.size()>0) {
cout << convertword(yo) << endl;
}
else {
cout << "Trivial elt!" << endl;
}
stab.push_back(yo);
}
}
else {
// there is a single vertex, won't use graph routine for this (just take all pairings as generators)
for (int uu=0; uu<edgePOrbitPairings.size(); uu++) {
if (find(vo.begin(),vo.end(),edgePOrbitPairings[uu][0])!=vo.end()) {
stab.push_back(edgePOrbitPairingMaps[uu]);
}
}
}
// Perhaps the edge is on the mirror of P^5 (s5 cases)
if (needpowerofp) {
cout << "THIS EDGE IS ON THE MIRROR OF P^" << orderofppower << endl;
vector<int> we;
for (int oo=0; oo<orderofppower; oo++) {
we.push_back(4);
}
stab.push_back(we);
}
cout << "Done computing stab" << endl;
vector<gen> sgmatrices;
cout << "Generators of stab: (there are " << stab.size() << ")" << endl;
int max_ord=1;
int maxordind;
bool flip = false;
for (int y=0; y<stab.size(); y++) {
if (stab[y].size()>0) {
cout << " " << convertword(stab[y]) << endl;
gen M = evalWord(stab[y]);
int orm = K.order(M);
cout << " (order " << orm << ")";
if (orm>1) {
gen dt = K.discrAdjusted(M);
if (operator_equal(dt,K.zeronumber,&ct)){
gen mirr;
if (!findMirror(M,mirr)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
gen te = SqNorm(mirr);
int sg;
if (K.checkSign(te,sg)) {
if (sg<0) {
cout << " (\"reflection\" in point)" << endl;
}
else {
if (sg>0) {
cout << " (reflection in line)" << endl;
}
else {
cout << "Single e-val gives ideal point, should this happen??" << endl;
// exit(1);
}
}
}
else {
cout << "Trouble locating mirror (inside or outside the ball)" << endl;
exit(1);
}
}
else {
// distinct eigenvalues, may want to compute rotation angles
cout << " (distinct eigenvalues)" << endl;
cout << endl;
}
}
else {
cout << endl;
}
if (!K.isScalar(M)) {
sgmatrices.push_back(M);
if (orm>max_ord) {
max_ord = orm;
maxordind = sgmatrices.size()-1;
}
gen W1 = M*Xo;
gen W2 = M*Xe;
K.vectred(W1);
K.vectred(W2);
if (K.areDep(W1,Xo) && K.areDep(W2,Xe)) {
cout << "Check (edge is fixed pointwise)" << endl;
}
else {
if (K.areDep(W1,Xe) && K.areDep(W2,Xo)) {
cout << "Check (edge is flipped)" << endl;
flip = true;
}
else {
cerr << "Trouble, edge is not stabilized!" << endl;
exit(1);
}
}
}
}
}
cout << endl;
cout << "There is a cyclic subgroup of order " << max_ord << endl;
vecteur popo;
gen A = K.Id;
for (int jjj=0; jjj<max_ord; jjj++) {
popo.push_back(A);
A = A*sgmatrices[maxordind];
K.matred(A);
}
cout << "Constructed " << max_ord << " powers " << endl;
bool is_cyclic = true;
int jjj=0;
while (is_cyclic && jjj<sgmatrices.size()) {
// for (int j=0; j++; j<sgmatrices.size()) {
if (jjj!=maxordind) {
int kkk=0;
bool fd = false;
while (kkk<max_ord && !fd) {
fd = K.isMultiple(sgmatrices[jjj],popo[kkk]);
kkk++;
}
is_cyclic = fd;
}
jjj++;
}
if (is_cyclic) {
cout << "Cyclic group gives full stabilizer! " << endl;
cout << endl;
vector<int> reflinds;
for (int uu=1; uu<popo.size(); uu++) {
gen M = popo[uu];
int ouu = K.order(M);
if (ouu>1) {
gen dt = K.discrAdjusted(M);
if (operator_equal(dt,K.zeronumber,&ct)){
gen mirr;
if (!findMirror(M,mirr)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
gen te = SqNorm(mirr);
int sg;
if (K.checkSign(te,sg)) {
if (sg>0) {
reflinds.push_back(uu);
}
}
else {
cout << "Trouble locating mirror (inside or outside the ball)" << endl;
exit(1);
}
}
}
}
cout << "There are " << reflinds.size() << " reflections in this group" << endl;
if (reflinds.size()==max_ord-1) {
cout << "Stabilizer is a reflection group" << endl;
}
else {
cout << "Stab is NOT a reflection group, singular point in quotient" << endl;
cout << "Reflection subgroup has order " << (reflinds.size()+1) << ", index " << (max_ord/reflinds.size()+1) << endl;
}
res = res + K.onenumber/max_ord;
if (!flip) {
res_top = res_top + K.onenumber;
}
else {
// do nothing, need to subdivide, and then contribution is 0?
}
}
else {
cout << "Group is not cyclic, will use brute force" << endl;
cout << endl;
FiniteGroup L(K);
L.addElements(sgmatrices);
L.expandToGroup();
cout << "Stab has order " << L.elements.size() << endl;
vector<int> reflinds;
for (int uu=1; uu<L.elements.size(); uu++) {
gen M = L.elements[uu];
int ouu = K.order(M);
if (ouu>1) {
gen dt = K.discrAdjusted(M);
if (operator_equal(dt,K.zeronumber,&ct)){
gen mirr;
if (!findMirror(M,mirr)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
gen te = SqNorm(mirr);
int sg;
if (K.checkSign(te,sg)) {
if (sg>0) {
reflinds.push_back(uu);
}
}
else {
cout << "Trouble locating mirror (inside or outside the ball)" << endl;
exit(1);
}
}
}
}
cout << "There are " << reflinds.size() << " reflections in this group" << endl;
FiniteGroup LR(K);
for (int uu=0; uu<reflinds.size(); uu++) {
LR.addElement(L.elements[reflinds[uu]]);
}
LR.expandToGroup();
cout << "Subgroup generated by reflections has order " << LR.elements.size() << endl;
if (LR.elements.size()<L.elements.size()) {
cout << "The stabilizer is NOT generated by reflections, this will give a singular point of the quotient" << endl;
}
else {
cout << "The stabilizer is generated by reflections!" << endl;
}
cout << endl;
res = res + K.onenumber/L.elements.size();
if (!flip) {
res_top = res_top + K.onenumber;
}
else {
// do nothing, need to subdivide, and then contribution is 0?
}
}
}
vecteur te;
te.push_back(res);
te.push_back(res_top);
return te;
}
gen Polytope::computeAngle(int j, gen X) {
gen mi;
if (isRidgeComplex(j,mi)) {
gen te = SqNorm(X);
if (verbose) {
cout << "<X,X> = " << te << endl;
}
int sg;
if (K.checkSign(te,sg)) {
if (sg<0) {
gen Y = BoxProd(X,mi);
gen Z = BoxProd(X,Y);
// X,Z spans the complex line orthog to common slice
// (beware it's orthogonal but not orthonormal)
// cout << "Will compute equations of faces in complex line" << endl;
Prism P1 = faces[ridges[j].faceindices[0]];
Prism P2 = faces[ridges[j].faceindices[1]];
gen a1 = Inn(X,P1.X0)*Inn(P1.X0,X) - Inn(X,P1.X1)*Inn(P1.X1,X);
gen a2 = Inn(X,P2.X0)*Inn(P2.X0,X) - Inn(X,P2.X1)*Inn(P2.X1,X);
K.red(a1);
K.red(a2);
if (!operator_equal(a1,K.zeronumber,&ct) || !operator_equal(a2,K.zeronumber,&ct)) {
cerr << "Trouble, X is not on bisectors?" << endl;
exit(1);
}
gen b1 = Inn(Z,P1.X0)*Inn(P1.X0,X) - Inn(Z,P1.X1)*Inn(P1.X1,X);
gen b2 = Inn(Z,P2.X0)*Inn(P2.X0,X) - Inn(Z,P2.X1)*Inn(P2.X1,X);
gen mu1 = K.evali(b1);
gen mu2 = K.evali(b2);
gen te = -re(mu1*conj(mu2,&ct)/(abs(mu1,&ct)*abs(mu2,&ct)),&ct);
return acos(te,&ct)/(2*gen("pi",&ct));
}
else {
cerr << "Can't compute the intersection angle at a point outside complex hyperbolic space" << endl;
exit(1);
}
}
else {
cerr << "Trouble checking sign of X" << endl;
exit(1);
}
}
else {
cerr << "Angle computation is implemented only for cotranchal intersections!" << endl;
return K.zeronumber;
}
}
gen Polytope::computeAngleNum(int j, gen X) {
// same as previous method, but X has interval coordinates
gen mi;
if (isRidgeComplex(j,mi)) {
gen Hn = K.matevali(H);
gen te1 = conj(X,&ct)*Hn;
gen te2 = conj(K.vectevali(mi),&ct)*Hn;
vecteur Yv;
Yv.push_back(te1[1]*te2[2]-te1[2]*te2[1]);
Yv.push_back(te1[2]*te2[0]-te1[0]*te2[2]);
Yv.push_back(te1[0]*te2[1]-te1[1]*te2[0]);
gen Y = gen(Yv);
te2 = conj(Y,&ct)*Hn;
vecteur Zv;
Zv.push_back(te1[1]*te2[2]-te1[2]*te2[1]);
Zv.push_back(te1[2]*te2[0]-te1[0]*te2[2]);
Zv.push_back(te1[0]*te2[1]-te1[1]*te2[0]);
gen Z = gen(Zv);
Prism P1 = faces[ridges[j].faceindices[0]];
Prism P2 = faces[ridges[j].faceindices[1]];
gen p1x0 = K.vectevali(P1.X0);
gen p1x1 = K.vectevali(P1.X1);
gen p2x0 = K.vectevali(P2.X0);
gen p2x1 = K.vectevali(P2.X1);
gen mu1 = (conj(p1x0,&ct)*Hn*Z)*(conj(X,&ct)*Hn*p1x0) - (conj(p1x1,&ct)*Hn*Z)*(conj(X,&ct)*Hn*p1x1);
gen mu2 = (conj(p2x0,&ct)*Hn*Z)*(conj(X,&ct)*Hn*p2x0) - (conj(p2x1,&ct)*Hn*Z)*(conj(X,&ct)*Hn*p2x1);
gen te = -re(mu1*conj(mu2,&ct)/(abs(mu1,&ct)*abs(mu2,&ct)),&ct);
return acos(te,&ct)/(2*gen("pi",&ct));
}
}
bool Polytope::isRidgeComplex(int j, gen &mi) {
ridge r = ridges[j];
int jface = r.faceindices[0];
bool iscomplex = false;
bool isbottom = true;
int uu=0;
while (isbottom && uu<r.verts.size()) {
gen X = vertices[r.verts[uu]].coords;
isbottom = operator_equal(Inn(X,faces[jface].mirror.coords),K.zeronumber,&ct);
uu++;
}
if (isbottom) {
if (verbose) {
cout << "Ridge is bottom ridge of face " << jface << endl;
}
mi = faces[jface].mirror.coords;
return true;
}
else {
bool istop = true;
uu=0;
while (istop && uu<r.verts.size()) {
gen X = vertices[r.verts[uu]].coords;
istop = operator_equal(Inn(X,faces[jface].apex.coords),K.zeronumber,&ct);
uu++;
}
if (istop) {
if (verbose) {
cout << "Ridge is top ridge of face " << jface << endl;
}
mi = faces[jface].apex.coords;
return true;
}
}
return false;
}
vecteur Polytope::eulerdim2() {
gen res_top = K.zeronumber;
gen res = K.zeronumber;
vector<int> ridgeorbitstocheck;
for (int k=0; k<ridgePOrbits.size(); k++) {
ridgeorbitstocheck.push_back(k);
}
while (ridgeorbitstocheck.size()>0) {
cout << "Ridge orbits to check: " << convertword(ridgeorbitstocheck) << endl;
cout << "Studying orbit " << ridgePOrbits[ridgeorbitstocheck[0]] << endl;
int init_orbit_index = ridgeorbitstocheck[0];
cout << "Computing cycle for ridge on faces " << convertword(ridges[ridgePOrbits[init_orbit_index][0]].faceindices) << endl;
gen mi;
bool iscomplex = isRidgeComplex(ridgePOrbits[init_orbit_index][0],mi);
int jstart = ridges[ridgePOrbits[init_orbit_index][0]].faceindices[0];
int kstart = ridges[ridgePOrbits[init_orbit_index][0]].faceindices[1];
int current_ridge = ridgePOrbits[init_orbit_index][0];
int j = jstart;
bool back = false;
int ridge_stab;
bool found_stab = false;
if (needppower) {
while (!back && !found_stab) {
int jimage = applyPToRidge(orderofppower,current_ridge);
if (jimage==current_ridge) {
found_stab = true;
cout << "Ridge #" << current_ridge << " is invariant by P^" << orderofppower << endl;
if (!iscomplex) {
cout << " (this is not a complex ridge!)" << endl;
}
}
else {
cout << "Ridge #" << j << " is NOT invariant by P^" << orderofppower << " (image is #" << jimage << ")" << endl;
}
if (found_stab) {
cout << "Element in ridge orbit is stabilized by P^" << orderofppower << "." << endl;
ridge_stab = current_ridge;
}
current_ridge = applyPairingToRidge(j,current_ridge);
// need to change mi
if (iscomplex) {
isRidgeComplex(current_ridge,mi);
}
bool fd = false;
int u = -1;
int v;
while (!fd && u!=ridgePOrbits.size()-1) {
u++;
v = -1;
while (!fd && v!=ridgePOrbits[u].size()-1) {
v++;
fd = current_ridge == ridgePOrbits[u][v];
}
}
if (!fd) {
cerr << "Trouble finding image ridge in a ridge P-orbit" << endl;
exit(1);
}
else {
if (ridges[current_ridge].faceindices[0]==facePairings[j]) {
j = ridges[current_ridge].faceindices[1];
}
else {
if (ridges[current_ridge].faceindices[1]==facePairings[j]) {
j = ridges[current_ridge].faceindices[0];
}
else {
cerr << "Trouble finding next pairing" << endl;
exit(1);
}
}
back = (u==init_orbit_index);
}
}
if (found_stab) {
cout << "Found ridge in orbit stabilized by P power!" << endl;
int jj=-1;
int kk;
bool fdd = false;
while (!fdd && jj!=ridgePOrbits.size()-1) {
jj++;
kk=-1;
while (!fdd && kk!=ridgePOrbits[jj].size()-1) {
kk++;;
fdd = (ridge_stab==ridgePOrbits[jj][kk]);
}
}
if (!fdd) {
cout << "Trouble locating ridge fixed by P power" << endl;
exit(1);
}
else {
init_orbit_index=jj;
}
}
}
gen C;
vector<int> cw;
if (found_stab) {
cout << "Will start with orbit of " << ridges[ridgePOrbits[init_orbit_index][0]] << ", because it is fixed py power of P" << endl;
}
jstart = ridges[ridgePOrbits[init_orbit_index][0]].faceindices[0];
kstart = ridges[ridgePOrbits[init_orbit_index][0]].faceindices[1];
if (faces[jstart].invertpairing) {
cout << convertword(invertword(faces[jstart].mirror.word)) << "->" << endl;
cw = invertword(faces[jstart].mirror.word);
}
else {
cout << convertword(faces[jstart].mirror.word) << "->" << endl;
cw = faces[jstart].mirror.word;
}
C = faces[jstart].pairing;
current_ridge = ridgePOrbits[init_orbit_index][0];
j = jstart;
back = false;
while (!back) {
current_ridge = applyPairingToRidge(j,current_ridge);
bool fd = false;
int u = -1;
int v;
while (!fd && u!=ridgePOrbits.size()-1) {
u++;
v = -1;
while (!fd && v!=ridgePOrbits[u].size()-1) {
v++;
fd = current_ridge == ridgePOrbits[u][v];
}
}
if (!fd) {
cerr << "Trouble finding image in some ridge P-orbit" << endl;
exit(1);
}
else {
ridgeorbitstocheck.erase(remove(ridgeorbitstocheck.begin(),ridgeorbitstocheck.end(),u),ridgeorbitstocheck.end());
if (ridges[current_ridge].faceindices[0]==facePairings[j]) {
j = ridges[current_ridge].faceindices[1];
}
else {
if (ridges[current_ridge].faceindices[1]==facePairings[j]) {
j = ridges[current_ridge].faceindices[0];
}
else {
cerr << "Trouble finding next pairing" << endl;
exit(1);
}
}
back = (u==init_orbit_index);
if (!back) {
if (faces[j].invertpairing) {
cout << convertword(invertword(faces[j].mirror.word)) << "->" << endl;
cw = concat(invertword(faces[j].mirror.word),cw);
}
else {
cout << convertword(faces[j].mirror.word) << "->" << endl;
cw = concat(faces[j].mirror.word,cw);
}
C = faces[j].pairing*C;
K.matred(C);
}
else {
vector<int> power_of_p;
for (int k=0; k<v; k++) {
power_of_p.push_back(-4);
C = Pi*C;
K.matred(C);
}
cout << "P^(-" << v << ")" << endl;
cw = concat(power_of_p,cw);
}
}
}
if (!back) {
cerr << "Trouble with some ridge cycle" << endl;
exit(1);
}
else {
if (found_stab) {
gen mirc;
vector<gen> sgmatrices;
bool is_gen_refl = false;
sgmatrices.push_back(C);
cout << "Elements in stab: " << endl;
cout << convertword(cw);
int orc = K.order(C);
cout << " (order " << orc << ")";
if (orc>1) {
gen dt = K.discrAdjusted(C);
if (operator_equal(dt,K.zeronumber,&ct)){
if (!findMirror(C,mirc)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
gen te = SqNorm(mirc);
int sg;
if (K.checkSign(te,sg)) {
if (sg<0) {
cout << " (\"reflection\" in point)" << endl;
}
else {
if (sg>0) {
is_gen_refl = true;
cout << " (reflection in line)" << endl;
}
else {
cout << "Single e-val gives ideal point, should this happen??" << endl;
// exit(1);
}
}
}
else {
cout << "Trouble locating mirror (inside or outside the ball)" << endl;
exit(1);
}
}
else {
cout << endl;
}
}
cout << "P^" << orderofppower << " (this is a complex reflection)" << endl;
sgmatrices.push_back(Ppower);
if (iscomplex) {
isRidgeComplex(ridgePOrbits[init_orbit_index][0],mi);
for (int yy=0; yy<sgmatrices.size(); yy++) {
gen Y = sgmatrices[yy]*mi;
K.vectred(Y);
if (!K.areDep(mi,Y)) {
cout << "PROBLEM, MATRIX IN SGMATRICES DOES NOT PRESERVE RIDGE!" << endl;
}
}
}
else {
// need to implement a check in generic case...
// (the part that is not implemented is just a sanity check)
}
// Should try studying reflection subgroups generated by two elements!
bool found_shortcut = false;
int shortcut_order;
if (is_gen_refl) {
int bo = K.braidOrder(C,Ppower);
if (bo>2) {
cout << "Generators braid with length " << bo << endl;
cout << " (it is not too bad to figure out what they generate, not implemented yet though)" << endl;
}
else {
if (bo==2) {
gen mirppow;
if (!findMirror(Ppower,mirppow)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
if (K.areDep(mirc,mirppow)) {
cout << "Generators are reflections with the same mirror, cyclic group" << endl;
cout << " (it is not so bad to compute the order of the group they generated, but not implemented)" << endl;
int opp = K.order(Ppower);
vecteur clist;
gen A = K.Id;
for (int j=0; j<orc; j++) {
clist.push_back(A);
A = A*C;
K.matred(A);
}
gen B = K.Id;
int count_intersection = 0;
for (int j=0; j<opp; j++) {
bool is_in_clist = false;
int k = 0;
while (!is_in_clist && k<clist.size()) {
is_in_clist = K.isMultiple(B,clist[k]);
k++;
}
if (is_in_clist) {
count_intersection++;
}
B = B*Ppower;
K.matred(B);
}
shortcut_order = (opp*orc)/count_intersection;
cout << "Order is simply the product of the orders (" << (orc*opp) << ")," << endl;
cout << " divided by order of intersection (" << count_intersection << ")" << endl;
cout << " =" << shortcut_order << ")" << endl;
found_shortcut = true;
}
else {
cout << "Generators are reflections with orthogonal mirrors" << endl;
int opp = K.order(Ppower);
shortcut_order = orc*opp;
cout << "Order is simply the product of the orders (" << shortcut_order << ")" << endl;
found_shortcut = true;
}
}
}
}
if (found_shortcut) {
res = res + K.onenumber/shortcut_order;
res_top = res_top + K.onenumber;
}
else {
FiniteGroup L(K);
L.addElements(sgmatrices);
L.expandToGroup();
cout << "Stab has order " << L.elements.size() << endl;
vector<int> reflinds;
for (int uu=1; uu<L.elements.size(); uu++) {
gen M = L.elements[uu];
int ouu = K.order(M);
if (ouu>1) {
gen dt = K.discrAdjusted(M);
if (operator_equal(dt,K.zeronumber,&ct)){
gen mirr;
if (!findMirror(M,mirr)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
gen te = SqNorm(mirr);
int sg;
if (K.checkSign(te,sg)) {
if (sg>0) {
reflinds.push_back(uu);
}
}
else {
cout << "Trouble locating mirror (inside or outside the ball)" << endl;
exit(1);
}
}
}
}
cout << "There are " << reflinds.size() << " reflections in this group" << endl;
FiniteGroup LR(K);
for (int uu=0; uu<reflinds.size(); uu++) {
LR.addElement(L.elements[reflinds[uu]]);
}
LR.expandToGroup();
cout << "Subgroup generated by reflections has order " << LR.elements.size() << endl;
if (LR.elements.size()<L.elements.size()) {
cout << "The stabilizer is NOT generated by reflections, this will give a singular point of the quotient" << endl;
}
else {
cout << "The stabilizer is generated by reflections!" << endl;
}
cout << endl;
res = res + K.onenumber/L.elements.size();
res_top = res_top + K.onenumber;
}
}
else {
int oc = K.order(C);
if (oc<0) {
cerr << "Ridge with large order of stab (>1000), I will consider it as infinite, and STOP" << endl;
exit(1);
}
else {
cout << "Found a ridge with stabilizer of order " << oc << endl;
if (oc>1) {
gen dt = K.discrAdjusted(C);
if (operator_equal(dt,K.zeronumber,&ct)){
gen mirr;
if (!findMirror(C,mirr)) {
cout << "Trouble finding mirror" << endl;
exit(1);
}
gen te = SqNorm(mirr);
int sg;
if (K.checkSign(te,sg)) {
if (sg<0) {
cout << "Cyclic group generated by a complex reflection in a point" << endl;
cout << " this gives a singular point in the quotient" << endl;
}
else {
if (sg>0) {
cout << " (reflection in line)" << endl;
}
else {
cout << "Single e-val gives ideal point, this should not happen" << endl;
exit(1);
}
}
}
else {
cout << "Trouble locating mirror (inside or outside the ball)" << endl;
exit(1);
}
}
else {
cout << "Cyclic group generated by regular elliptic" << endl;
cout << " this gives a singular point in the quotient" << endl;
cout << endl;
}
}
else {
cout << endl;
}
res = res + K.onenumber/oc;
res_top = res_top + K.onenumber;
}
}
}
}
vecteur te;
te.push_back(res);
te.push_back(res_top);
return te;
}
vecteur Polytope::eulerdim3() {
if (needppower) {
gen res = K.zeronumber;
gen res_top = K.zeronumber;
for (int k=0; k<facePOrbits.size(); k++) {
gen te1 = Inn(faces[facePOrbits[k][0]].apex.coords,extramirror);
if (operator_equal(te1,K.zeronumber,&ct)) {
gen te2 = Inn(faces[facePOrbits[k][0]].apexProjection,extramirror);
if (operator_equal(te2,K.zeronumber,&ct)) {
int te = orderofp/orderofppower;
res = res+K.onenumber/te;
res_top = res_top+K.onenumber;
}
else {
res = res + K.onenumber;
res_top = res_top + K.onenumber;
}
}
else {
res = res + K.onenumber;
res_top = res_top + K.onenumber;
}
}
vecteur te;
te.push_back(res/K.twonumber);
te.push_back(res_top/K.twonumber);
return te;
}
else {
vecteur te;
te.push_back(facePOrbits.size()/2);
te.push_back(facePOrbits.size()/2);
return te;
}
}
void Polytope::computeEulerCharacteristic() {
// VERTEX ORBITS
cout << "Will now compute e0" << endl;
vecteur yo0 = eulerdim0();
gen ed0 = yo0[0];
gen ed0_top = yo0[1];
// EDGE ORBITS
cout << "Will now compute e1" << endl;
vecteur yo1 = eulerdim1();
gen ed1 = yo1[0];
gen ed1_top = yo1[1];
// RIDGE ORBITS
cout << "Will now compute e2" << endl;
vecteur yo2 = eulerdim2();
gen ed2 = yo2[0];
gen ed2_top = yo2[1];
// FACE ORBITS
cout << "Will now compute e3" << endl;
vecteur yo3 = eulerdim3();
gen ed3 = yo3[0];
gen ed3_top = yo3[1];
// Can there ever be faces that are paired with something in the same P-orbit?
// (if so this may not be the right formula)
cout << "Will now compute e4" << endl;
// 4-dim contribution is just (order of P)^-1:
gen ed4 = K.onenumber/orderofp;
gen ed4_top = K.onenumber;
cout << "Euler 0-dim contribution: " << ed0_top << endl;
cout << "Euler 1-dim contribution: " << ed1_top << endl;
cout << "Euler 2-dim contribution: " << ed2_top << endl;
cout << "Euler 3-dim contribution: " << ed3_top << endl;
cout << "Euler 4-dim contribution: " << ed4_top << endl;
cout << endl;
euler_char_top = ed0_top-ed1_top+ed2_top-ed3_top+ed4_top;
cout << "Topological Euler characteristic: " << euler_char_top << endl;
cout << endl;
cout << "Orbifold Euler 0-dim contribution: " << ed0 << endl;
cout << "Orbifold Euler 1-dim contribution: " << ed1 << endl;
cout << "Orbifold Euler 2-dim contribution: " << ed2 << endl;
cout << "Orbifold Euler 3-dim contribution: " << ed3 << endl;
cout << "Orbifold Euler 4-dim contribution: " << ed4 << endl;
cout << endl;
euler_char = ed0-ed1+ed2-ed3+ed4;
cout << "Orbifold Euler characteristic: " << euler_char << endl;
cout << endl;
}
void Polytope::checkPairings() {
for (int k=0; k<faces.size(); k++) {
cout << "#" << k << ": ";
cout << faces[k] << endl;
Prism B = applyReflection(faces[k]);
bool found = false;
int l=0;
while (!found && l<faces.size()) {
found = comparePrisms(B,faces[l]);
l++;
}
if (found) {
cout << " paired with " << faces[l-1] << endl;
faces[k].pairing = reflMat(faces[k].mirror.coords,mult);
faces[k].invertpairing = false;
facePairings.push_back(l-1);
}
else {
Prism Bi = applyInverseReflection(faces[k]);
found = false;
l=0;
while (!found && l<faces.size()) {
found = comparePrisms(Bi,faces[l]);
l++;
}
if (found) {
cout << " [inverse] paired with " << faces[l-1] << endl;
faces[k].invertpairing = true;
faces[k].pairing = reflMat(faces[k].mirror.coords,multconj);
facePairings.push_back(l-1);
}
else {
cerr << "Problem with pairings!" << endl;
exit(1);
}
}
}
cout << "List of pairings: " << endl;
for (int k=0; k<faces.size() ; k++) {
cout << "Face #" << k << " --> " << facePairings[k] << endl;
}
}
void Polytope::computeAllVertices() {
vector<WVector> rawverts;
for (int k=0; k<faces.size(); k++) {
int nb = faces[k].bottomface.size();
for (int l=0; l<nb; l++) {
if (!isInList(faces[k].bottomface[l],rawverts)) {
rawverts.push_back(faces[k].bottomface[l]);
}
}
nb = faces[k].topface.size();
for (int l=0; l<nb; l++) {
if (!isInList(faces[k].topface[l],rawverts)) {
rawverts.push_back(faces[k].topface[l]);
}
}
nb = faces[k].midvertices.size();
for (int l=0; l<nb; l++) {
if (!isInList(faces[k].midvertices[l],rawverts)) {
rawverts.push_back(faces[k].midvertices[l]);
}
}
}
cout << "Collected " << rawverts.size() << " vertices..." << endl;
while (rawverts.size()>0) {
WVector v0 = rawverts[0];
WVector vk = rawverts[0];
vector<int> orb;
orb.push_back(vertices.size());
vertices.push_back(v0);
vertReps.push_back(v0);
rawverts.erase(rawverts.begin());
bool back = false;
while (!back) {
vk.coords = P*vk.coords;
if (is_symmetric) {
vk.word = conjugateword(word_p1,shiftIndicesUp(vk.word));
}
else {
vk.word = conjugateword(word_123,vk.word);
}
K.vectred(vk.coords);
back = testSame(vk,v0);
if (!back) {
orb.push_back(vertices.size());
vertices.push_back(vk);
int ind = findInList(vk,rawverts);
if (ind>-1) {
rawverts.erase(rawverts.begin()+ind);
}
else {
cerr << "Trouble computing orbit!" << endl;
exit(1);
}
}
else {
vertexPOrbits.push_back(orb);
}
}
}
cout << "The vertices come in " << vertReps.size() << " P-orbits." << endl;
for (int k=0; k<vertexPOrbits.size(); k++) {
cout << "Orbit #" << k << ": " << vertexPOrbits[k] << endl;
int no = vertexPOrbits[k].size();
int k0 = vertexPOrbits[k][0];
vector<int> fi = findFaces(vertices[k0]);
cout << "Vert #" << k0 << " is on " << convertword(fi) << endl;
if (fi[0]==-1) {
fi.erase(fi.begin());
for (int m=0; m<no; m++) {
vertices[k0+m].faceindices.push_back(-1);
}
}
for (int l=0; l<fi.size(); l++) {
int fil = fi[l];
// identify it in some POrbit of faces!
bool fd = false;
int u=-1;
int v;
while (!fd && u!=facePOrbits.size()-1) {
u++;
v=-1;
while (!fd && v!=facePOrbits[u].size()-1) {
v++;
fd = (fil==facePOrbits[u][v]);
}
}
if (!fd) {
cerr << "Problem, some face was not found in P-orbits of faces!" << endl;
exit(1);
}
else {
for (int m=0; m<no; m++) {
vertices[vertexPOrbits[k][m]].faceindices.push_back(facePOrbits[u][(v+m)%facePOrbits[u].size()]);
}
}
}
vector<WVector> mi = findMirrors(vertices[k0]);
cout << " and on following mirrors: " << endl;
for (int u = 0; u<mi.size(); u++) {
cout << mi[u].word << endl;
}
}
for (int k=0; k<vertReps.size(); k++) {
// this is misnamed, for now it only finds pairings of vertices
computeStabilizer(k);
}
for (int k=0; k<vertices.size(); k++) {
cout << "Vertex #" << k << " is on " << convertword(vertices[k].faceindices) << endl;
}
}
void Polytope::computeAllEdges() {
cout << "Will now construct edges..." << endl;
for (int kk=0; kk<facePOrbits.size(); kk++) {
int k = facePOrbits[kk][0];
cout << "Face #" << k << endl;
vector<int> tf;
for (int l=0; l<faces[k].topface.size(); l++) {
int te = findInList(faces[k].topface[l],vertices);
if (te<0) {
cerr << "Problem identifying face vertex" << endl;
exit(1);
}
else {
tf.push_back(te);
faces[k].topface[l].reftovlist = te;
}
}
if (tf.size()>1) {
for (int l=0; l<tf.size()-1; l++) {
edge e;
e.origin = tf[l];
e.end = tf[l+1];
addEdge(e);
}
edge e;
e.origin = tf[tf.size()-1];
e.end = tf[0];
addEdge(e);
}
vector<int> mf;
for (int l=0; l<faces[k].midvertices.size(); l++) {
int te = findInList(faces[k].midvertices[l],vertices);
if (te<0) {
cerr << "Problem identifying face vertex" << endl;
exit(1);
}
else {
mf.push_back(te);
faces[k].midvertices[l].reftovlist = te;
}
}
vector<int> bf;
for (int l=0; l<faces[k].bottomface.size(); l++) {
int te = findInList(faces[k].bottomface[l],vertices);
if (te<0) {
cerr << "Problem identifying face vertex" << endl;
exit(1);
}
else {
bf.push_back(te);
faces[k].bottomface[l].reftovlist = te;
}
}
for (int l=0; l<bf.size()-1; l++) {
edge e;
e.origin = bf[l];
e.end = bf[l+1];
addEdge(e);
}
edge eb;
eb.origin = bf[bf.size()-1];
eb.end = bf[0];
addEdge(eb);
if (tf.size()>1) {
for (int l=0; l<bf.size(); l++) {
if (find(faces[k].midvertindices.begin(),faces[k].midvertindices.end(),l)==faces[k].midvertindices.end()) {
edge e;
e.origin = bf[l];
e.end = tf[l];
addEdge(e);
}
}
}
else {
for (int l=0; l<bf.size(); l++) {
if (find(faces[k].midvertindices.begin(),faces[k].midvertindices.end(),l)==faces[k].midvertindices.end()) {
edge e;
e.origin = bf[l];
e.end = tf[0];
addEdge(e);
}
}
}
for (int l=0; l<mf.size(); l++) {
if (tf.size()>1) {
edge e1, e2;
e1.origin = bf[faces[k].midvertindices[l]];
e1.end = mf[l];
addEdge(e1);
e2.origin = mf[l];
e2.end = tf[faces[k].midvertindices[l]];
addEdge(e2);
}
else {
edge e1, e2;
e1.origin = bf[faces[k].midvertindices[l]];
e1.end = mf[l];
addEdge(e1);
e2.origin = mf[l];
e2.end = tf[0];
addEdge(e2);
}
}
}
cout << "Created " << edges.size() << " edges..." << endl;
}
void Polytope::computeAllRidges() {
cout << "Will now construct ridges..." << endl;
for (int kk=0; kk<facePOrbits.size(); kk++) {
int k = facePOrbits[kk][0];
cout << "Face #" << k << endl;
int ns = faces[k].sides.size();
for (int l=0; l<ns; l++) {
ridge r;
if (faces[k].topface.size()==1) {
r.verts.push_back(faces[k].topface[0].reftovlist);
}
else {
r.verts.push_back(faces[k].topface[(l+1)%ns].reftovlist);
r.verts.push_back(faces[k].topface[l].reftovlist);
}
bool fd = false;
int u1=0;
while (!fd && u1<faces[k].midvertindices.size()){
fd = l==faces[k].midvertindices[u1];
u1++;
}
if (fd){
u1--;
r.verts.push_back(faces[k].midvertices[u1].reftovlist);
}
r.verts.push_back(faces[k].bottomface[l].reftovlist);
r.verts.push_back(faces[k].bottomface[(l+1)%ns].reftovlist);
fd = false;
int u2=0;
while (!fd && u2<faces[k].midvertindices.size()){
fd = (l+1)%ns==faces[k].midvertindices[u2];
u2++;
}
if (fd){
u2--;
r.verts.push_back(faces[k].midvertices[u2].reftovlist);
}
addRidge(r);
}
ridge r;
for (int l=0; l<ns; l++) {
r.verts.push_back(faces[k].bottomface[l].reftovlist);
}
addRidge(r);
if (faces[k].topface.size()>1) {
ridge r;
for (int l=0; l<ns; l++) {
r.verts.push_back(faces[k].topface[l].reftovlist);
}
addRidge(r);
}
}
cout << "Created " << ridges.size() << " ridges..." << endl;
}
bool Polytope::isSame(edge e1, edge e2) {
return (e1.origin==e2.origin && e1.end == e2.end);
}
bool Polytope::isFlipped(edge e1, edge e2) {
return (e1.origin==e2.end && e1.end == e2.origin);
}
bool Polytope::isEdgeNew(edge e) {
bool res = true;
int l=0;
while (res && l<edges.size()){
res = !isSame(e,edges[l]) && !isFlipped(e,edges[l]);
l++;
}
return res;
}
int Polytope::applyPtoVertex(int k) {
bool found = false;
int l=-1;
int m;
while (!found && l!=vertexPOrbits.size()-1) {
l++;
m=-1;
while (!found && m!=vertexPOrbits[l].size()-1) {
m++;
found = vertexPOrbits[l][m]==k;
}
}
if (!found) {
cerr << "Not supposed to happen (trouble locating vertex index in P orbits)" << endl;
exit(1);
}
else {
return vertexPOrbits[l][(m+1)%vertexPOrbits[l].size()];
}
}
vector<int> Polytope::getPOrbitOfVertex(int k) {
bool found = false;
int l=-1;
int m;
while (!found && l!=vertexPOrbits.size()-1) {
l++;
m=-1;
while (!found && m!=vertexPOrbits[l].size()-1) {
m++;
found = vertexPOrbits[l][m]==k;
}
}
if (!found) {
cerr << "Not supposed to happen (trouble locating vertex index in P orbits)" << endl;
exit(1);
}
else {
vector<int> res;
int nmax = vertexPOrbits[l].size();
for (int n=0; n<nmax; n++) {
res.push_back(vertexPOrbits[l][(m+n)%nmax]);
}
return res;
}
}
int Polytope::findNextInFacePOrbit(int k) {
bool found = false;
int l=-1;
int m;
while (!found && l!=facePOrbits.size()-1) {
l++;
m=-1;
while (!found && m!=facePOrbits[l].size()-1) {
m++;
found = facePOrbits[l][m]==k;
}
}
if (!found) {
cerr << "Not supposed to happen (trouble locating face index in P orbits)" << endl;
exit(1);
}
else {
return facePOrbits[l][(m+1)%facePOrbits[l].size()];
}
}
vector<int> Polytope::getPOrbitOfFace(int k) {
bool found = false;
int l=-1;
int m;
while (!found && l!=facePOrbits.size()-1) {
l++;
m=-1;
while (!found && m!=facePOrbits[l].size()-1) {
m++;
found = facePOrbits[l][m]==k;
}
}
if (!found) {
cerr << "Not supposed to happen (trouble locating face index in P orbits)" << endl;
exit(1);
}
else {
vector<int> res;
int nmax = facePOrbits[l].size();
for (int n=0; n<nmax; n++) {
res.push_back(facePOrbits[l][(m+n)%nmax]);
}
return res;
}
}
void Polytope::addRidge(ridge e) {
vector<int> orbitinds;
if (isRidgeNew(e)) {
int nv = e.verts.size();
vector<vector<int> > li;
for (int u=0; u<nv; u++) {
cout << "vertex #" << e.verts[u] << ": " << vertices[e.verts[u]].faceindices << endl;
li.push_back(vertices[e.verts[u]].faceindices);
}
vector<int> inds = intersect(li);
if (inds[0]==-1) {
inds.erase(inds.begin());
}
if (inds.size()!=2) {
cerr << "Problem with ridge, it is on " << inds.size() << " faces, namely " << convertword(inds) << endl;
exit(1);
}
else {
for (int u=0; u<2; u++) {
e.faceindices.push_back(inds[u]);
}
}
cout << "Adding ridge w/ vertices " << convertword(e.verts) << " (which is on faces " << convertword(e.faceindices) << ")" << endl;
orbitinds.push_back(ridges.size());
ridges.push_back(e);
vector<vector<int> > yo;
int maxorb = 0;
int maxorbind = 0;
for (int k=0; k<nv; k++) {
vector<int> yok = getPOrbitOfVertex(e.verts[k]);
if (yok.size()>maxorb) {
maxorb = yok.size();
maxorbind = k;
}
yo.push_back(yok);
}
bool test = true;
for (int l=1; l<yo[maxorbind].size() && test; l++) {
ridge r;
for (int m=0; m<nv; m++) {
r.verts.push_back(yo[m][l%yo[m].size()]);
}
for (int u=0; u<2; u++) {
r.faceindices.push_back(findNextInFacePOrbit(ridges[ridges.size()-1].faceindices[u]));
}
test = isRidgeNew(r);
if (test) {
cout << "Adding ridge w/ vertices " << convertword(r.verts) << " (which is on faces " << convertword(r.faceindices) << ")" << endl;
orbitinds.push_back(ridges.size());
ridges.push_back(r);
}
}
ridgePOrbits.push_back(orbitinds);
}
}
void Polytope::addEdge(edge e) {
vector<int> orbitinds;
int j = e.origin;
int k= e.end;
vector<int> commoninds = intersect(vertices[j].faceindices,vertices[k].faceindices);
if (commoninds[0]==-1) {
commoninds.erase(commoninds.begin());
}
for (int m=0; m<commoninds.size(); m++) {
if (isVertexSafe(vertices[j],faces[commoninds[m]]) && isVertexSafe(vertices[k],faces[commoninds[m]])){
e.faceindices.push_back(commoninds[m]);
}
}
if (isEdgeNew(e)) {
cout << "Adding edge... v#" << e.origin << "," << e.end << " (which is on faces " << convertword(e.faceindices) << ")" << endl;
orbitinds.push_back(edges.size());
edges.push_back(e);
vector<int> jo = getPOrbitOfVertex(j);
vector<int> ko = getPOrbitOfVertex(k);
bool test = true;
if (jo.size()<ko.size()) {
for (int l=1; l<ko.size() && test; l++) {
edge e;
e.origin = jo[l%jo.size()];
e.end = ko[l];
test = isEdgeNew(e);
if (test) {
int z = edges.size()-1;
for (int m=0; m<edges[z].faceindices.size(); m++) {
int g = edges[z].faceindices[m];
if (g>-1) {
e.faceindices.push_back(findNextInFacePOrbit(g));
}
}
cout << "Adding edge... v#" << e.origin << "," << e.end << " (which is on faces " << convertword(e.faceindices) << ")" << endl;
orbitinds.push_back(edges.size());
edges.push_back(e);
}
}
}
else {
if (jo.size()>ko.size()) {
for (int l=1; l<jo.size() && test; l++) {
edge e;
e.origin = jo[l];
e.end = ko[l%ko.size()];
test = isEdgeNew(e);
if (test) {
int z = edges.size()-1;
for (int m=0; m<edges[z].faceindices.size(); m++) {
int g = edges[z].faceindices[m];
if (g>-1) {
e.faceindices.push_back(findNextInFacePOrbit(g));
}
}
cout << "Adding edge... v#" << e.origin << "," << e.end << " (which is on faces " << convertword(e.faceindices) << ")" << endl;
orbitinds.push_back(edges.size());
edges.push_back(e);
}
}
}
else {
for (int l=1; l<jo.size() && test; l++) {
edge e;
e.origin = jo[l];
e.end = ko[l];
test = isEdgeNew(e);
if (test) {
int z = edges.size()-1;
for (int m=0; m<edges[z].faceindices.size(); m++) {
int g = edges[z].faceindices[m];
if (g>-1) {
e.faceindices.push_back(findNextInFacePOrbit(g));
}
}
cout << "Adding edge... v#" << e.origin << "," << e.end << " (which is on faces " << convertword(e.faceindices) << ")" << endl;
orbitinds.push_back(edges.size());
edges.push_back(e);
}
}
}
}
edgePOrbits.push_back(orbitinds);
}
}
bool Polytope::isSame(ridge e1, ridge e2) {
if (e1.verts.size()!=e2.verts.size()) {
return false;
}
else {
bool res = true;
int l=0;
while (l<e1.verts.size() && res) {
res = e1.verts[l]==e2.verts[l];
l++;
}
return res;
}
}
bool Polytope::isRotatedFlip(ridge e1, ridge e2) {
int nv = e1.verts.size();
if (nv!=e2.verts.size()) {
return false;
}
else {
int k1 = e1.verts[0];
int l=0;
bool fd = false;
while (!fd && l<nv) {
fd = k1==e2.verts[l];
l++;
}
if (!fd) {
return false;
}
else {
int k2 = (l-1)%nv;
bool res = true;
int m=1;
while (res && m<nv) {
res = e1.verts[m]==e2.verts[(k2+m)%nv];
m++;
}
if (res) {
return true;
}
else {
int k2 = (l-1)%nv;
bool res = true;
int m=1;
while (res && m<nv) {
int k2p;
if (k2-m>-1) {
k2p = k2-m;
}
else {
k2p = k2-m+nv;
}
res = e1.verts[m]==e2.verts[k2p];
m++;
}
return res;
}
}
}
}
// following version assumed the ridges were always oriented the same way,
// this fails when we remove degenerate faces...
bool Polytope::isRotated(ridge e1, ridge e2) {
int nv = e1.verts.size();
if (nv!=e2.verts.size()) {
return false;
}
else {
int k1 = e1.verts[0];
int l=0;
bool fd = false;
while (!fd && l<nv) {
fd = k1==e2.verts[l];
l++;
}
if (!fd) {
return false;
}
else {
int k2 = (l-1)%nv;
bool res = true;
int m=1;
while (res && m<nv) {
res = e1.verts[m]==e2.verts[(k2+m)%nv];
m++;
}
return res;
}
}
}
bool Polytope::isRidgeNew(ridge r) {
bool res = true;
int l=0;
while (res && l<ridges.size()){
res = !isRotated(r,ridges[l]); // apparently should also check if it is flipped!! (occurs in Gamma(6,2/3), eg)
if (res) {
if (isRotatedFlip(r,ridges[l])){
cout << "Rotation with a flip!" << endl;
res = false;
}
}
l++;
}
return res;
}
bool Polytope::testSame(WVector V, WVector W){
return K.areDep(V.coords,W.coords);
}
bool Polytope::isInList(WVector V, vector<WVector> li){
int n = li.size();
bool res = false;
int k = 0;
while (!res && k<n) {
res = testSame(V,li[k]);
k++;
}
return res;
}
int Polytope::findInList(gen V, vector<WVector> li){
vector<int> w;
WVector W = WVector(V,w);
return findInList(W,li);
}
int Polytope::findInList(WVector V, vector<WVector> li){
int n = li.size();
bool res = false;
int k = 0;
while (!res && k<n) {
res = testSame(V,li[k]);
k++;
}
if (res) {
return (k-1);
}
else {
return -1;
}
}
bool Polytope::computeVertices(Prism &A) {
cout << "Will now compute vertices for " << A << endl;
gen te = SqNorm(A.apex.coords);
int res;
if (K.checkSign(te,res)) {
if (verbose) {
cout << "Sign of sq nm of apex: " << res << endl;
}
int k1 = 0;
int l1 = A.sides[0].word.size();
for (int k=1; k<A.sides.size(); k++) {
int l = A.sides[k].word.size();
if (l<l1) {
l1 = l;
k1 = k;
}
}
int k2;
if (k1==0) {
if (A.sides[A.sides.size()-1].word.size()<A.sides[1].word.size()) {
k2 = A.sides.size()-1;
}
else {
k2 = 1;
}
}
else {
k2 = (k1+1)%A.sides.size();
}
gen M1 = reflMat(A.sides[k1].coords,mult)*reflMat(A.sides[k2].coords,mult);
K.matred(M1);
int om1 = K.order(M1);
if (om1==-1) {
cout << "Product of infinite order" << endl;
}
else {
cout << "Product of order " << om1 << endl;
}
int bo = K.braidOrder(reflMat(A.sides[k1].coords,mult),reflMat(A.sides[k2].coords,mult));
cout << "Braid length " << bo << endl;
vector<int> w0 = concat(A.sides[k1].word,A.sides[k2].word);
vector<int> w = concat(A.sides[k1].word,A.sides[k2].word);
bool isrefl = false;
int k=1;
gen M = M1;
while (k<om1 && !isrefl) {
gen dt = K.discrAdjusted(M);
isrefl = operator_equal(dt,K.zeronumber,&ct);
if (isrefl) {
int sg;
if (!K.checkSign(SqNorm(A.apex.coords),sg)) {
cerr << "Problem checking sign" << endl;
exit(1);
}
else {
if (sg>0) {
gen X1 = BoxProd(A.cspine,A.apex.coords);
gen X2 = M*X1;
K.vectred(X2);
isrefl = K.areDep(X1,X2);
}
else {
if (sg<0) {
gen X1 = A.apex.coords;
gen X2 = M*X1;
K.vectred(X2);
isrefl = K.areDep(X1,X2);
}
else {
// don't know what to do...
}
}
}
}
if (isrefl) {
if (verbose) {
cout << "Found reflection, power " << k << endl;
}
A.toppower = k;
A.toporder = om1/k;
}
else {
M = M*M1;
w = concat(w,w0);
K.matred(M);
}
k++;
}
if (!isrefl) {
if (verbose) {
cout << "Did not find any reflection power..." << endl;
}
// exit(1);
}
A.apex.word = w;
if (verbose) {
cout << "word for apex=" << convertword(w) << endl;
}
if (res<1) {
if (verbose) {
if (res==0) {
cout << "Single (IDEAL) vertex at top" << endl;
}
else {
cout << "Single vertex at top" << endl;
}
}
A.topface.push_back(A.apex);
}
else {
if (verbose) {
cout << "Top face is not a point.." << endl;
}
for (int k=0; k<A.sides.size(); k++) {
gen yo = BoxProd(A.apex.coords,A.sides[k].coords);
WVector Vk( yo, concat(A.apex.word,A.sides[k].word) );
A.topface.push_back(Vk);
if (verbose) {
cout << "Vertex for " << convertword(A.sides[k].word) << endl;
}
if (K.checkSign(SqNorm(Vk.coords),res)){
if (res>0) {
cerr << "This should not happen!" << endl;
exit(1);
}
if (res==0) {
cout << " (previous vertex is IDEAL)" << endl;
}
}
else {
cerr << "Problem checking sign!" << endl;
exit(1);
}
}
}
}
else {
cout << "Problem checking sign... " << K.evali(te) << endl;
}
if (verbose) {
cout << "Constructing bottom face..." << endl;
}
for (int k=0; k<A.sides.size(); k++) {
gen yo = BoxProd(A.mirror.coords,A.sides[k].coords);
if (K.checkSign(SqNorm(yo),res)){
if (res>0) {
if (verbose) {
cout << "#" << k << "(" << convertword(A.sides[k].word) << "): bottom and mid vertex." << endl;
}
gen M1 = reflMat(A.mirror.coords,mult)*reflMat(A.sides[k].coords,mult);
K.matred(M1);
int om1 = K.order(M1);
if (verbose) {
cout << "Product of order " << om1 << endl;
}
int bo = K.braidOrder(reflMat(A.mirror.coords,mult),reflMat(A.sides[k].coords,mult));
if (verbose) {
cout << "Braid length " << bo << endl;
}
vector<int> w0 = concat(A.mirror.word,A.sides[k].word);
vector<int> wk = concat(A.mirror.word,A.sides[k].word);
bool isrefl = false;
int kk=1;
gen M = M1;
while (kk<om1 && !isrefl) {
gen dt = K.discrAdjusted(M);
isrefl = operator_equal(dt,K.zeronumber,&ct);
if (isrefl) {
gen X1 = BoxProd(A.sides[k].coords,yo);
gen X2 = M*X1;
isrefl = K.areDep(X1,X2);
}
// also want to check if vertex is fixed.
if (verbose && isrefl) {
cout << "Found reflection, power " << kk << endl;
}
M = M*M1;
wk = concat(wk,w0);
K.matred(M);
kk++;
}
if (verbose && !isrefl) {
cout << "Did not find any reflection power..." << endl;
// exit(1);
}
WVector nm(yo,wk);
gen yok1 = BoxProd(A.mirror.coords,yo);
gen yok2 = BoxProd(A.sides[k].coords,yo);
WVector Wk1(yok1,concat(A.mirror.word,wk));
WVector Wk2(yok2,concat(A.sides[k].word,wk));
if (K.checkSign(SqNorm(Wk1.coords),res)){
if (res>-1) {
cerr << "This should not happen!" << endl;
exit(1);
}
}
else {
cerr << "Problem checking sign!" << endl;
exit(1);
}
if (K.checkSign(SqNorm(Wk2.coords),res)){
if (res>-1) {
cerr << "This should not happen!" << endl;
exit(1);
}
}
else {
cerr << "Problem checking sign!" << endl;
exit(1);
}
A.bottomface.push_back(Wk1);
A.midvertices.push_back(Wk2);
A.midvertindices.push_back(k);
}
else {
if (verbose) {
cout << "#" << k << "(" << convertword(A.sides[k].word) << "): Single bottom vertex." << endl;
}
WVector Vk( yo, concat(A.mirror.word,A.sides[k].word) );
A.bottomface.push_back(Vk);
if (verbose && res==0) {
cout << " (previous vertex is IDEAL)" << endl;
}
}
}
else {
cerr << "Problem checking sign!" << endl;
exit(1);
}
}
}
bool Polytope::isOnMirror(gen X, Prism A) {
gen te = Inn(X,A.mirror.coords);
return operator_equal(te,K.zeronumber,&ct);
}
bool Polytope::isOnTopFace(gen X, Prism A) {
gen te = Inn(X,A.apex.coords);
return operator_equal(te,K.zeronumber,&ct);
}
bool Polytope::isOnPrism(gen X, Prism A){
gen te = Inn(X,A.apex.coords)*Inn(A.apex.coords,A.apexProjection)*Inn(A.apexProjection,X);
K.red(te);
return K.isReal(te);
}
gen Polytope::reflectAcrossSpine(gen X, Prism A){
vecteur co;
co.push_back(Inn(A.apex.coords,A.apex.coords));
co.push_back(Inn(A.apex.coords,A.apexProjection));
co.push_back(Inn(A.apexProjection,A.apex.coords));
co.push_back(Inn(A.apexProjection,A.apexProjection));
gen M = K.createMatrix(2,2,co);
vecteur cov;
cov.push_back(Inn(X,A.apex.coords));
cov.push_back(Inn(X,A.apexProjection));
gen b = gen(cov);
gen de = K.det(M);
K.red(de);
if (operator_equal(de,K.zeronumber,&ct)) {
cerr << "Problem reflecting across spine" << endl;
exit(1);
}
else {
gen dei = K.inverse(de);
vecteur coeffs;
coeffs.push_back(dei*(M[1][1]*b[0]-M[0][1]*b[1]));
coeffs.push_back(dei*(-M[1][0]*b[0]+M[0][0]*b[1]));
gen Y = K.myconj(coeffs[0])*A.apex.coords + K.myconj(coeffs[1])*A.apexProjection;
K.vectred(Y);
return Y;
}
}
Prism Polytope::createPimage(Prism A) {
Prism A1;
A1.toporder = A.toporder;
A1.toppower = A.toppower;
gen m = P*A.mirror.coords;
K.vectred(m);
vector<int> w1;
if (is_symmetric) {
w1 = conjugateword(word_p1,shiftIndicesUp(A.mirror.word));
}
else {
w1 = conjugateword(word_123,A.mirror.word);
}
useRelations(w1);
A1.mirror = WVector(m,w1);
if (is_symmetric) {
A1.apex = WVector(P*A.apex.coords, conjugateword(word_p1,shiftIndicesUp(A.apex.word)));
}
else {
A1.apex = WVector(P*A.apex.coords, conjugateword(word_123,A.apex.word));
}
K.vectred(A1.apex.coords);
useRelations(A1.apex.word);
A1.apexProjection = P*A.apexProjection;
K.vectred(A1.apexProjection);
A1.cspine = P*A.cspine;
K.vectred(A1.cspine);
A1.X0 = P*A.X0;
A1.X1 = P*A.X1;
K.vectred(A1.X0);
K.vectred(A1.X1);
for (int k=0; k<A.sides.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = conjugateword(word_p1,shiftIndicesUp(A.sides[k].word));
}
else {
wk = conjugateword(word_123,A.sides[k].word);
}
gen sk = P*A.sides[k].coords;
K.vectred(sk);
A1.sides.push_back(WVector(sk,wk));
}
for (int k=0; k<A.bottomface.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = conjugateword(word_p1,shiftIndicesUp(A.bottomface[k].word));
}
else {
wk = conjugateword(word_123,A.bottomface[k].word);
}
gen sk = P*A.bottomface[k].coords;
K.vectred(sk);
A1.bottomface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.topface.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = conjugateword(word_p1,shiftIndicesUp(A.topface[k].word));
}
else {
wk = conjugateword(word_123,A.topface[k].word);
}
gen sk = P*A.topface[k].coords;
K.vectred(sk);
A1.topface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.midvertices.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = conjugateword(word_p1,shiftIndicesUp(A.midvertices[k].word));
}
else {
wk = conjugateword(word_123,A.midvertices[k].word);
}
gen sk = P*A.midvertices[k].coords;
K.vectred(sk);
A1.midvertices.push_back(WVector(sk,wk));
A1.midvertindices.push_back(A.midvertindices[k]);
}
A1.isSurrounded = false;
for (int k=0; k<A1.sides.size(); k++) {
A1.freeRidges.push_back(k);
}
A1.jstart = A.jstart;
return A1;
}
Prism Polytope::createPinvimage(Prism A) {
Prism A1;
A1.toporder = A.toporder;
A1.toppower = A.toppower;
gen m = Pi*A.mirror.coords;
K.vectred(m);
vector<int> w1;
if (is_symmetric) {
w1 =shiftIndicesDown(conjugateword(word_m1,A.mirror.word));
}
else {
w1 = conjugateword(word_321,A.mirror.word);
}
A1.mirror = WVector(m,w1);
useRelations(A1.mirror.word);
if (is_symmetric) {
A1.apex = WVector(Pi*A.apex.coords,shiftIndicesDown(conjugateword(word_m1,A.apex.word)));
}
else {
A1.apex = WVector(Pi*A.apex.coords,conjugateword(word_321,A.apex.word));
}
K.vectred(A1.apex.coords);
useRelations(A1.apex.word);
A1.apexProjection = Pi*A.apexProjection;
K.vectred(A1.apexProjection);
A1.cspine = Pi*A.cspine;
K.vectred(A1.cspine);
A1.X0 = Pi*A.X0;
A1.X1 = Pi*A.X1;
K.vectred(A1.X0);
K.vectred(A1.X1);
for (int k=0; k<A.sides.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = shiftIndicesDown(conjugateword(word_m1,A.sides[k].word));
}
else {
wk = conjugateword(word_321,A.sides[k].word);
}
gen sk = Pi*A.sides[k].coords;
K.vectred(sk);
A1.sides.push_back(WVector(sk,wk));
}
for (int k=0; k<A.bottomface.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = shiftIndicesDown(conjugateword(word_m1,A.bottomface[k].word));
}
else {
wk = conjugateword(word_321,A.bottomface[k].word);
}
gen sk = Pi*A.bottomface[k].coords;
K.vectred(sk);
A1.bottomface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.topface.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = shiftIndicesDown(conjugateword(word_m1,A.topface[k].word));
}
else {
wk = conjugateword(word_m1,A.topface[k].word);
}
gen sk = Pi*A.topface[k].coords;
K.vectred(sk);
A1.topface.push_back(WVector(sk,wk));
}
for (int k=0; k<A.midvertices.size(); k++) {
vector<int> wk;
if (is_symmetric) {
wk = shiftIndicesDown(conjugateword(word_m1,A.midvertices[k].word));
}
else {
wk = conjugateword(word_m1,A.midvertices[k].word);
}
gen sk = Pi*A.midvertices[k].coords;
K.vectred(sk);
A1.midvertices.push_back(WVector(sk,wk));
A1.midvertindices.push_back(A.midvertindices[k]);
}
A1.isSurrounded = false;
for (int k=0; k<A1.sides.size(); k++) {
A1.freeRidges.push_back(k);
}
A1.jstart = A.jstart;
return A1;
}
// this is better when P has infinite order, but here it doesn't make much sense...
void Polytope::addFaceOrbit(Prism A) {
if (isPrismNew(A)) {
vector<Prism> facestoadd;
faces.push_back(A);
faceReps.push_back(A);
cout << "Adding " << A << endl;
updateFreeRidges();
bool done = false;
Prism Ak = A.mycopy();
Prism Aki = A.mycopy();
int k=0;
while (!done && k<100) {
Ak = createPimage(Ak);
done = comparePrisms(Ak,Aki);
if (!done) {
useRelations(Ak);
facestoadd.push_back(Ak);
Aki = createPinvimage(Aki);
done = comparePrisms(Aki,Ak);
if (!done) {
useRelations(Aki);
facestoadd.push_back(Aki);
}
}
k++;
}
if (!done) {
cerr << "P does not have finite order? (its order is at least 100) " << endl;
exit(1);
}
vector<int> inds;
int u = facestoadd.size();
if (u%2!=0) {
u--;
inds.push_back(u);
}
while (u>1) {
u--;
inds.push_back(u);
u--;
inds.insert(inds.begin(),u);
}
vector<int> inds2;
int nf = faces.size();
inds2.push_back(nf-1);
for (int k=0; k<inds.size(); k++) {
inds2.push_back(nf+k);
}
facePOrbits.push_back(inds2);
for (int k=0; k<inds.size(); k++) {
faces.push_back(facestoadd[inds[k]]);
cout << "Adding " << facestoadd[inds[k]] << endl;
updateFreeRidges();
}
}
else {
cout << "Should not add this prism, it's already in the list!" << endl;
}
}
vector<WVector> Polytope::findMirrors(gen V) {
vector<WVector> res;
for (int k=0; k<faces.size(); k++) {
if (isOnMirror(V,faces[k])) {
if (findInList(faces[k].mirror,res)<0) {
res.push_back(faces[k].mirror);
}
}
if (isOnTopFace(V,faces[k])) {
if (findInList(faces[k].apex,res)<0) {
res.push_back(faces[k].apex);
}
}
}
return res;
}
vector<WVector> Polytope::findMirrors(WVector v) {
return findMirrors(v.coords);
}
vector<int> Polytope::findFaces(gen V) {
vector<int> res;
gen te = SqNorm(V);
if (operator_equal(te,K.zeronumber,&ct)) {
res.push_back(-1);
}
for (int k=0; k<faces.size(); k++) {
if (isOnPrism(V,faces[k])) {
bool fd = false;
int u=0;
while (!fd && u<faces[k].topface.size()) {
fd = K.areDep(V,faces[k].topface[u].coords);
u++;
}
if (!fd) {
u=0;
while (!fd && u<faces[k].midvertices.size()) {
fd = K.areDep(V,faces[k].midvertices[u].coords);
u++;
}
if (!fd) {
u=0;
while (!fd && u<faces[k].bottomface.size()) {
fd = K.areDep(V,faces[k].bottomface[u].coords);
u++;
}
if (fd) {
res.push_back(k);
}
}
else {
res.push_back(k);
}
}
else {
res.push_back(k);
}
}
}
return res;
}
// beware this finds more faces than "findFaces", in general
vector<int> Polytope::findBisectors(gen V) {
vector<int> res;
gen te = SqNorm(V);
if (operator_equal(te,K.zeronumber,&ct)) {
res.push_back(-1);
}
for (int k=0; k<faces.size(); k++) {
if (isOnPrism(V,faces[k])) {
res.push_back(k);
}
}
return res;
}
vector<int> Polytope::findFaces(WVector v) {
return findFaces(v.coords);
}
vector<int> Polytope::findBisectors(WVector v) {
return findBisectors(v.coords);
}
void Polytope::useRelations(vector<int> &w) {
int n = w.size();
bool reduced = false;
while (n>0 && !reduced) {
int ns = w.size();
for (int k=0; k<relations.size(); k++) {
vector<int> rel = relations[k];
if (2*w.size()>rel.size()) {
simplifyword(w,rel);
}
}
reduced = ns==w.size();
}
}
void Polytope::useRelations(Prism &A) {
useRelations(A.mirror.word);
for (int k=0; k<A.sides.size(); k++) {
useRelations(A.sides[k].word);
}
for (int k=0; k<A.bottomface.size(); k++) {
useRelations(A.bottomface[k].word);
}
for (int k=0; k<A.topface.size(); k++) {
useRelations(A.topface[k].word);
}
for (int k=0; k<A.midvertices.size(); k++) {
useRelations(A.midvertices[k].word);
}
}
void Polytope::studyVertexStabilizers() {
for (int k=0; k<vertReps.size(); k++) {
orbitsToVisit.push_back(k);
}
while (orbitsToVisit.size()>0) {
int k = orbitsToVisit[0];
cout << "TEST k=" << k << endl;
currentVertexOrbit.clear();
findNextVertexInCycle(k);
}
for (int k=0; k<vertexOrbits.size(); k++) {
cout << "Vertex orbit #" << k << ": " << vertexOrbits[k] << endl;
}
}
void Polytope::findNextVertexInCycle(int k) {
currentVertexOrbit.push_back(k);
cout << "Current vertex orbit " << currentVertexOrbit << endl;
cout << "Orbits to visit: " << orbitsToVisit << endl;
bool fd = false;
int kt = 0;
while (!fd && kt<orbitsToVisit.size()) {
fd = orbitsToVisit[kt]==k;
kt++;
}
if (!fd) {
cerr << "Problem..." << endl;
exit(1);
}
else {
orbitsToVisit.erase(orbitsToVisit.begin()+(kt-1));
}
cout << "Orbits to visit (after): " << orbitsToVisit << endl;
vector<int> te = findFaces(vertReps[k]);
cout << endl;
int yo = findInList(vertReps[k],vertices);
cout << "Vertex rep #" << k << " (#" << yo << " in list) is on bisectors " << te << endl;
for (int l=0; l<te.size(); l++) {
if (te[l]>-1) {
cout << "Applying pairing for face #" << te[l] << endl;
if (verbose) {
cout << "te=" << te << endl;
}
gen vimage = faces[te[l]].pairing*vertReps[k].coords;
K.vectred(vimage);
int m = findInList(vimage,vertices);
if (m>-1) {
cout << "Image by pairing is vertex #" << m << ", which is on: " << findFaces(vimage) << endl;
bool foundOrb = false;
int u = 0;
while (!foundOrb && u<vertexPOrbits.size()) {
foundOrb = find(vertexPOrbits[u].begin(), vertexPOrbits[u].end(), m)!=vertexPOrbits[u].end();
u++;
}
if (!foundOrb) {
cerr << "Image is in none of the orbits?!" << endl;
exit(1);
}
else {
cout << "Image is in orbit #" << (u-1) << endl;
bool fd = false;
int kt = 0;
while (!fd && kt<currentVertexOrbit.size()) {
fd = currentVertexOrbit[kt]==(u-1);
kt++;
}
if (!fd) {
cout << " this was not visited yet..." << endl;
findNextVertexInCycle(u-1);
}
else {
cout << " this was already visited!" << endl;
}
}
}
else {
cerr << "Problem with vertex cycles... " << endl;
exit(1);
}
}
}
cout << "Registering orbit: " << currentVertexOrbit << endl;
cout << "Clearing current vertex orbit..." << endl;
vertexOrbits.push_back(currentVertexOrbit);
currentVertexOrbit.clear();
cout << "Done with findNextVertex, k=" << k << endl;
}
void Polytope::computeStabilizer(int k) {
// stab of vertex representative #k
vector<int> te = vertices[vertexPOrbits[k][0]].faceindices;
// I hope this was computed before!!
cout << endl;
cout << "vertex #" << vertexPOrbits[k][0] << " is on: " << te << endl;
for (int l=0; l<te.size(); l++) {
if (te[l]>-1) {
cout << "Applying pairing for face #" << te[l] << endl;
gen vimage = faces[te[l]].pairing*vertReps[k].coords;
K.vectred(vimage);
int m = findInList(vimage,vertices);
if (m!=-1) {
cout << " image by pairing is vertex #" << m << ", which is on: " << vertices[m].faceindices << endl;
// I hope this was computed before!!
vector<int> vp;
vp.push_back(vertexPOrbits[k][0]);
vp.push_back(te[l]);
vp.push_back(m);
vertexPairings.push_back(vp);
cout << "v#" << vp[0] << " --(" << vp[1] << ")--> v#" << vp[2] << endl;
vector<int> vpi;
vpi.push_back(m);
vpi.push_back(facePairings[te[l]]);
vpi.push_back(vertexPOrbits[k][0]);
vertexPairings.push_back(vpi);
cout << "v#" << vpi[0] << " --(" << vpi[1] << ")--> v#" << vpi[2] << endl;
// probably would like to include its P-conjugates?
bool fdm = false;
int v = -1;
int w;
while (!fdm && v!=vertexPOrbits.size()-1) {
v++;
w=-1;
while (!fdm && w!=vertexPOrbits[v].size()-1) {
w++;
fdm = m==vertexPOrbits[v][w];
}
}
if (!fdm) {
cerr << "Problem finding vertex in some orbit!" << endl;
exit(1);
}
bool fdm1 = false;
int v1 = -1;
int w1;
while (!fdm1 && v1!=facePOrbits.size()-1) {
v1++;
w1=-1;
while (!fdm1 && w1!=facePOrbits[v1].size()-1) {
w1++;
fdm1 = te[l]==facePOrbits[v1][w1];
}
}
if (!fdm1) {
cerr << "Problem finding face index in some orbit!" << endl;
exit(1);
}
int n = vertexPOrbits[v].size();
int n1 = facePOrbits[v1].size();
if (n>n1) {
cout << "Interesting, a vertex has smaller P-orbit than the face.." << endl;
}
for (int u=1; u<n; u++) {
vector<int> vpu;
vpu.push_back(vertexPOrbits[k][u]);
vpu.push_back(facePOrbits[v1][(w1+u)%n1]);
vpu.push_back(vertexPOrbits[v][(w+u)%n]);
vertexPairings.push_back(vpu);
cout << "v#" << vpu[0] << " --(" << vpu[1] << ")--> v#" << vpu[2] << endl;
vector<int> vpui;
vpui.push_back(vertexPOrbits[v][(w+u)%n]);
vpui.push_back(facePairings[facePOrbits[v1][(w1+u)%n1]]);
vpui.push_back(vertexPOrbits[k][u]);
vertexPairings.push_back(vpui);
cout << "v#" << vpui[0] << " --(" << vpui[1] << ")--> v#" << vpui[2] << endl;
}
bool foundOrb = false;
int u = 0;
int vv;
while (!foundOrb && u<vertexPOrbits.size()) {
vv = -1;
while (!foundOrb && vv!=vertexPOrbits[u].size()-1) {
vv++;
foundOrb = vertexPOrbits[u][vv]==m;
}
u++;
}
if (!foundOrb) {
cerr << "Image is in none of the orbits?!" << endl;
exit(1);
}
else {
vector<int> pa;
pa.push_back(k);
pa.push_back(u-1);
vertexPOrbitPairings.push_back(pa);
vector<int> w;
if (faces[te[l]].invertpairing) {
w = invertword(faces[te[l]].mirror.word);
}
else {
w = concat(w,faces[te[l]].mirror.word);
}
if (vv>orderofp/2) {
for (int zz=0; zz<orderofp-vv; zz++) { // could do better, if v is more than order of P
w.insert(w.begin(),4);
}
}
else {
for (int zz=0; zz<vv; zz++) { // could do better, if v is more than order of P
w.insert(w.begin(),-4);
}
}
vertexPOrbitPairingMaps.push_back(w);
cout << " (image is in orbit #" << (u-1) << ")" << endl;
}
}
else {
cerr << "Problem with vertex cycles... " << endl;
exit(1);
}
}
}
}
gen Polytope::evalWord(vector<int> w) {
gen res = K.Id;
int k=0;
while (k<w.size()) {
int l = w[k];
if (l==1) {
res = res*R1;
}
else {
if (l==2) {
res = res*R2;
}
else {
if (l==3) {
res = res*R3;
}
else {
if (l==-1) {
res = res*R1i;
}
else {
if (l==-2) {
res = res*R2i;
}
else {
if (l==-3) {
res = res*R3i;
}
else {
if (l==4) {
res = res*P;
}
else {
if (l==-4) {
res = res*Pi;
}
else {
cerr << "Wrong index in word?" << endl;
exit(1);
}
}
}
}
}
}
}
}
K.matred(res);
k++;
}
return res;
}
gen Polytope::evalWordAsRootOf(vector<int> w) {
gen res = K.Id;
gen R1ro,R1iro,R2ro,R2iro,R3ro,R3iro,Pro,Piro;
vector<int>::iterator it = find(w.begin(),w.end(),1);
if (it!=w.end()){
gen R1ro = _subst(makesequence(R1,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(R1ro);
cout << "reduced R1: " << R1ro << endl;
}
it = find(w.begin(),w.end(),-1);
if (it!=w.end()){
gen R1iro = _subst(makesequence(R1i,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(R1iro);
cout << "reduced R1^-1: " << R1iro << endl;
}
it = find(w.begin(),w.end(),2);
if (it!=w.end()){
gen R2ro = _subst(makesequence(R2,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(R2ro);
cout << "reduced R2: " << R2 << endl;
}
it = find(w.begin(),w.end(),-2);
if (it!=w.end()){
gen R2iro = _subst(makesequence(R2i,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(R2iro);
cout << "reduced R2^-1: " << R2iro << endl;
}
it = find(w.begin(),w.end(),3);
if (it!=w.end()){
gen R3ro = _subst(makesequence(R3,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(R3ro);
cout << "reduced R3: " << R3ro << endl;
}
it = find(w.begin(),w.end(),-3);
if (it!=w.end()){
gen R3iro = _subst(makesequence(R3i,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(R3iro);
cout << "reduced R3^-1: " << R3iro << endl;
}
it = find(w.begin(),w.end(),4);
if (it!=w.end()){
gen Pro = _subst(makesequence(P,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(Pro);
cout << "reduced P: " << Pro << endl;
}
it = find(w.begin(),w.end(),-4);
if (it!=w.end()){
gen Piro = _subst(makesequence(Pi,x__IDNT_e,K.genasrootof),&ct);
reduce_degree_mat(Piro);
cout << "reduced P^-1: " << Piro << endl;
}
int k=0;
while (k<w.size()) {
int l = w[k];
if (l==1) {
res = res*R1ro;
reduce_degree_mat(res);
}
else {
if (l==2) {
res = res*R2ro;
reduce_degree_mat(res);
}
else {
if (l==3) {
res = res*R3ro;
reduce_degree_mat(res);
}
else {
if (l==-1) {
res = res*R1iro;
reduce_degree_mat(res);
}
else {
if (l==-2) {
res = res*R2iro;
reduce_degree_mat(res);
}
else {
if (l==-3) {
res = res*R3iro;
reduce_degree_mat(res);
}
else {
if (l==4) {
res = res*Pro;
reduce_degree_mat(res);
}
else {
if (l==-4) {
res = res*Piro;
reduce_degree_mat(res);
}
else {
cerr << "Wrong index in word?" << endl;
exit(1);
}
}
}
}
}
}
}
}
k++;
}
return res;
}
void Polytope::createBraidRelation(vector<int> w1, vector<int> w2) {
gen A = evalWord(w1);
gen B = evalWord(w2);
cout << "Creating braid relation for " << w1 << " and " << w2 << endl;
int bo = K.braidOrder(A,B);
int bo2 = bo/2;
cout << convertword(w1) << " and " << convertword(w2) << " braid with order " << bo << endl;
vector<int> w1i = invertword(w1);
vector<int> w2i = invertword(w2);
vector<int> r1;
for (int k=0; k<bo2; k++) {
r1 = concat(r1,w1);
r1 = concat(r1,w2);
}
if (bo%2!=0) {
r1 = concat(r1,w1);
r1 = concat(r1,w2i);
}
for (int k=0; k<bo2; k++) {
r1 = concat(r1,w1i);
r1 = concat(r1,w2i);
}
vector<int> r2;
for (int k=0; k<bo2; k++) {
r2 = concat(r2,w2);
r2 = concat(r2,w1);
}
if (bo%2!=0) {
r2 = concat(r2,w2);
r2 = concat(r2,w1i);
}
for (int k=0; k<bo2; k++) {
r2 = concat(r2,w2i);
r2 = concat(r2,w1i);
}
relations.push_back(r1);
relations.push_back(r2);
if (is_symmetric) {
relations.push_back(shiftIndicesUp(r1));
relations.push_back(shiftIndicesUp(r2));
relations.push_back(shiftIndicesDown(r1));
relations.push_back(shiftIndicesDown(r2));
}
}
bool Polytope::isVertexSafe(WVector V, Prism A) {
for (int j=0; j<A.topface.size(); j++) {
if (testSame(V,A.topface[j])) {
return true;
}
}
for (int j=0; j<A.midvertices.size(); j++) {
if (testSame(V,A.midvertices[j])) {
return true;
}
}
for (int j=0; j<A.bottomface.size(); j++) {
if (testSame(V,A.bottomface[j])) {
return true;
}
}
return false;
}
// this is repeated under another name (small caps for t)
int Polytope::applyPToVertex(int pow, int jvertex) {
// locate jvertex in a P-orbit, then shift
bool fd = false;
int j=-1;
int n;
int k;
while (!fd && j+1!=vertexPOrbits.size()) {
j++;
fd = false;
n = vertexPOrbits[j].size();
k=-1;
while (!fd && k+1!=n) {
k++;
fd = (vertexPOrbits[j][k]==jvertex);
}
}
if (!fd) {
cerr << "Trouble locating vertex in a P-orbit" << endl;
exit(1);
}
else {
return vertexPOrbits[j][(k+pow)%n];
}
}
int Polytope::applyPToEdge(int pow, int jedge) {
int jo = applyPToVertex(pow, edges[jedge].origin);
int je = applyPToVertex(pow, edges[jedge].end);
if (jo<0 || je<0) {
cerr << "Trouble computing P-image of a 1-face (vertices are already a problem)!" << endl;
exit(1);
}
else {
bool fd = false;
int u = -1;
while (!fd && u!=edges.size()) {
u++;
fd = ( (edges[u].origin==jo && edges[u].end==je) || (edges[u].origin==je && edges[u].end==jo) ) ;
}
if (!fd) {
cerr << "Trouble computing image of a 1-face!" << endl;
exit(1);
}
else {
return u;
}
}
}
int Polytope::applyPToRidge(int pow, int j) {
int nv = ridges[j].verts.size();
vector<int> verteximages;
for (int u=0; u<nv; u++) {
int jo = applyPToVertex(pow, ridges[j].verts[u]);
if (jo<0) {
cerr << "Trouble computing image of a ridge!" << endl;
exit(1);
}
else {
verteximages.push_back(jo);
}
}
vector<int> commoninds;
for (int u=0; u<vertices[verteximages[0]].faceindices.size(); u++) {
commoninds.push_back(vertices[verteximages[0]].faceindices[u]);
}
for (int u=1; u<verteximages.size(); u++) {
commoninds = intersect(commoninds,vertices[verteximages[u]].faceindices);
}
if (commoninds[0]==-1) {
commoninds.erase(commoninds.begin());
}
if (commoninds.size()!=2) {
cerr << "Trouble identifying image of a ridge (nb of indices containing verts: "<<commoninds.size()<<")" << endl;
exit(1);
}
else {
bool fd = false;
int v=-1;
while (!fd && v!=ridges.size()-1) {
v++;
fd = ( (ridges[v].faceindices[0]==commoninds[0] && ridges[v].faceindices[1]==commoninds[1]) || (ridges[v].faceindices[1]==commoninds[0] && ridges[v].faceindices[0]==commoninds[1]));
}
if (!fd) {
cerr << "Trouble identifying image of a ridge." << endl;
exit(1);
}
else {
return v;
}
}
}
int Polytope::applyPinvToVertex(int pow, int jvertex) {
// locate jvertex in a P-orbit, then shift
bool fd = false;
int j=-1;
int n, k;
while (!fd && j+1!=vertexPOrbits.size()) {
j++;
k=-1;
bool fd = false;
n = vertexPOrbits[j].size();
while (!fd && k+1!=n) {
k++;
fd = (vertexPOrbits[j][k]==jvertex);
}
}
if (!fd) {
cerr << "Trouble locating vertex in a P-orbit" << endl;
exit(1);
}
else {
return vertexPOrbits[j][(k-pow)%n];
}
}
int Polytope::applyPinvToEdge(int pow, int jedge) {
int jo = applyPinvToVertex(pow, edges[jedge].origin);
int je = applyPinvToVertex(pow, edges[jedge].end);
if (jo<0 || je<0) {
cerr << "Trouble computing P-image of a 1-face (vertices are already a problem)!" << endl;
exit(1);
}
else {
bool fd = false;
int u = -1;
while (!fd && u!=edges.size()) {
u++;
fd = ( (edges[u].origin==jo && edges[u].end==je) || (edges[u].origin==je && edges[u].end==jo) ) ;
}
if (!fd) {
cerr << "Trouble computing image of a 1-face!" << endl;
exit(1);
}
else {
return u;
}
}
}
int Polytope::applyPinvToRidge(int pow, int j) {
int nv = ridges[j].verts.size();
vector<int> verteximages;
for (int u=0; u<nv; u++) {
int jo = applyPinvToVertex(pow, ridges[j].verts[u]);
if (jo<0) {
cerr << "Trouble computing image of a ridge!" << endl;
exit(1);
}
else {
verteximages.push_back(jo);
}
}
vector<int> commoninds;
for (int u=0; u<vertices[verteximages[0]].faceindices.size(); u++) {
commoninds.push_back(vertices[verteximages[0]].faceindices[u]);
}
for (int u=1; u<verteximages.size(); u++) {
commoninds = intersect(commoninds,vertices[verteximages[u]].faceindices);
}
if (commoninds[0]==-1) {
commoninds.erase(commoninds.begin());
}
if (commoninds.size()!=2) {
cerr << "Trouble identifying image of a ridge (nb of indices containing verts: "<<commoninds.size()<<")" << endl;
exit(1);
}
else {
bool fd = false;
int v=-1;
while (!fd && v!=ridges.size()-1) {
v++;
fd = ( (ridges[v].faceindices[0]==commoninds[0] && ridges[v].faceindices[1]==commoninds[1]) || (ridges[v].faceindices[1]==commoninds[0] && ridges[v].faceindices[0]==commoninds[1]));
}
if (!fd) {
cerr << "Trouble identifying image of a ridge." << endl;
exit(1);
}
else {
return v;
}
}
}
int Polytope::applyPairingToVertex(int jface, int jvertex) {
bool fd = false;
int u = -1;
while (!fd && u!=vertexPairings.size()-1) {
u++;
fd = ( vertexPairings[u][0]==jvertex && vertexPairings[u][1]==jface );
}
if (fd) {
return vertexPairings[u][2];
}
else {
return -1;
}
}
int Polytope::applyPairingToEdge(int jface, int j) {
int jo = applyPairingToVertex(jface, edges[j].origin);
int je = applyPairingToVertex(jface, edges[j].end);
cout << "jo=" << jo << endl;
cout << "je=" << je << endl;
if (jo<0 || je<0) {
cerr << "Trouble computing image of a 1-face (vertices are already a problem)!" << endl;
exit(1);
}
else {
bool fd = false;
int u = -1;
while (!fd && u!=edges.size()) {
u++;
fd = ( (edges[u].origin==jo && edges[u].end==je) || (edges[u].origin==je && edges[u].end==jo) ) ;
}
if (!fd) {
cerr << "Trouble computing image of a 1-face!" << endl;
exit(1);
}
else {
return u;
}
}
}
int Polytope::applyPairingToRidge(int jface, int j) {
int nv = ridges[j].verts.size();
vector<int> verteximages;
for (int u=0; u<nv; u++) {
int jo = applyPairingToVertex(jface, ridges[j].verts[u]);
if (jo<0) {
cerr << "Trouble computing image of a ridge!" << endl;
exit(1);
}
else {
verteximages.push_back(jo);
}
}
vector<int> commoninds;
for (int u=0; u<vertices[verteximages[0]].faceindices.size(); u++) {
commoninds.push_back(vertices[verteximages[0]].faceindices[u]);
}
for (int u=1; u<verteximages.size(); u++) {
commoninds = intersect(commoninds,vertices[verteximages[u]].faceindices);
}
if (commoninds[0]==-1) {
commoninds.erase(commoninds.begin());
}
if (commoninds.size()!=2) {
cerr << "Trouble identifying image of a ridge (nb of indices containing verts: "<<commoninds.size()<<")" << endl;
exit(1);
}
else {
bool fd = false;
int v=-1;
while (!fd && v!=ridges.size()-1) {
v++;
fd = ( (ridges[v].faceindices[0]==commoninds[0] && ridges[v].faceindices[1]==commoninds[1]) || (ridges[v].faceindices[1]==commoninds[0] && ridges[v].faceindices[0]==commoninds[1]));
}
if (!fd) {
cerr << "Trouble identifying image of a ridge." << endl;
exit(1);
}
else {
return v;
}
}
}
void Polytope::checkCycles(){
ofstream file;
string filename = "pres/pres"+K.tag+".g";
file.open(filename.c_str());
file << "F:=FreeGroup(\"R1\",\"R2\",\"R3\",\"P\");" << endl;
file << "R1:=F.1; R2:=F.2; R3:=F.3; P:=F.4;" << endl;
stringstream ops;
ops << orderofp;
if (is_symmetric) {
file << "G:=F/[P*R3*P^-1*R1^-1, P*R1*P^-1*R1*R2^-1*R1^-1, P^" << ops.str();
}
else {
// don't know if the first relation always appears in cycles...
file << "G:=F/[P^-1*R1*R2*R3,P^" << ops.str();
}
vector<string> rels;
vector<int> ridgeorbitstocheck;
for (int k=0; k<ridgePOrbits.size(); k++) {
ridgeorbitstocheck.push_back(k);
}
while (ridgeorbitstocheck.size()>0) {
if (verbose) {
cout << "Ridge orbits to check: " << convertword(ridgeorbitstocheck) << endl;
cout << "ridgePOrbits[ridgeorbitstocheck[0]]= " << ridgePOrbits[ridgeorbitstocheck[0]] << endl;
}
cout << "Computing cycle for ridge on faces " << ridges[ridgePOrbits[ridgeorbitstocheck[0]][0]] << endl;
gen C;
vector<int> cw;
gen p0orbit = p0;
// could probably replace p0 by some vector inside the polytope,
// and check whether it comes back inside the polytope too early
int init_orbit_index = ridgeorbitstocheck[0];
if (verbose) {
cout << "Initial ridge orbit: " << init_orbit_index << endl;
}
int jstart = ridges[ridgePOrbits[init_orbit_index][0]].faceindices[0];
int kstart = ridges[ridgePOrbits[init_orbit_index][0]].faceindices[1];
gen mi0;
bool iscomplex = isRidgeComplex(ridgePOrbits[init_orbit_index][0],mi0);
gen Xt, angle_sum;
angle_sum = K.zeronumber;
if (iscomplex) {
if (verbose) {
cout << "mi0: " << mi0 << endl;
cout << "genasrootof: " << K.genasrootof << endl;
}
cout << "Should compute angles!" << endl;
Prism P1 = faces[jstart];
Xt = BoxProd(mi0,P1.cspine); // should take apex projection? does this depend on sign?
gen UU = P1.apexProjection;
if (verbose) {
cout << "Sq nm of apex projection: " << K.evali(SqNorm(UU)) << endl;
cout << "Sq nm of cspine: " << K.evali(SqNorm(P1.cspine)) << endl;
cout << "P1.cspine=" << P1.cspine << endl;
cout << "Xt=" << Xt << endl;
}
gen angle_fraction = computeAngle(ridgePOrbits[init_orbit_index][0], Xt);
if (verbose) {
cout << "angle: 1/" << K.onenumber/angle_fraction << endl;
}
angle_sum = angle_sum + angle_fraction;
}
if (faces[jstart].invertpairing) {
cw = invertword(faces[jstart].mirror.word);
}
else {
cw = faces[jstart].mirror.word;
}
C = faces[jstart].pairing;
Xt = C*Xt;
K.vectred(Xt);
p0orbit = C*p0orbit;
K.vectred(p0orbit);
int tp0 = testPoint(p0orbit);
if (!tp0>0) {
cout << "Orbit pt is inside polytope!" << endl;
}
if (K.areDep(p0orbit,p0)) {
if (verbose) {
cout << "C=" << C << endl;
cout << "p0=" << p0 << endl;
}
gen te = K.inverse((*p0orbit._VECTptr)[1]);
gen vt = te*p0orbit;
K.vectred(vt);
if (verbose) {
cout << "p0orbit=" << vt << endl;
}
cout << "Got back to p0, word so far is " << convertword(cw) << endl;
if (!isPPower(C)) {
cout << "Cycle is not in <P>, seems there is no local tiling!" << endl;
exit(1);
}
}
int current_ridge = ridgePOrbits[init_orbit_index][0];
// SHOULDN'T WE DO THIS?
// ridgeorbitstocheck.erase(remove(ridgeorbitstocheck.begin(),ridgeorbitstocheck.end(),init_orbit_index),ridgeorbitstocheck.end());
cout << ridges[current_ridge].faceindices[0] << ", " << ridges[current_ridge].faceindices[1] << endl;
int j = jstart;
bool back = false; // probably not what we want?
while (!back) {
current_ridge = applyPairingToRidge(j,current_ridge);
bool fd = false;
int u = -1;
int v;
while (!fd && u!=ridgePOrbits.size()-1) {
u++;
v = -1;
while (!fd && v!=ridgePOrbits[u].size()-1) {
v++;
fd = current_ridge == ridgePOrbits[u][v];
}
}
if (!fd) {
cerr << "Trouble finding image ridge in a ridge P-orbit" << endl;
exit(1);
}
else {
if (verbose) {
cout << "u=" << u << endl;
cout << "v=" << v << endl;
}
cout << ridges[current_ridge].faceindices[0] << ", " << ridges[current_ridge].faceindices[1] << endl;
ridgeorbitstocheck.erase(remove(ridgeorbitstocheck.begin(),ridgeorbitstocheck.end(),u),ridgeorbitstocheck.end());
if (ridges[current_ridge].faceindices[0]==facePairings[j]) {
j = ridges[current_ridge].faceindices[1];
}
else {
if (ridges[current_ridge].faceindices[1]==facePairings[j]) {
j = ridges[current_ridge].faceindices[0];
}
else {
cerr << "Trouble finding next pairing" << endl;
exit(1);
}
}
back = (u==init_orbit_index);
if (!back) {
if (faces[j].invertpairing) {
cw = concat(invertword(faces[j].mirror.word),cw);
}
else {
cw = concat(faces[j].mirror.word,cw);
}
C = faces[j].pairing*C;
K.matred(C);
Xt = faces[j].pairing*Xt;
K.vectred(Xt);
p0orbit = faces[j].pairing*p0orbit;
K.vectred(p0orbit);
if (K.areDep(p0orbit,p0)) {
if (verbose) {
cout << "C=" << C << endl;
cout << "p0=" << p0 << endl;
}
gen te = K.inverse((*p0orbit._VECTptr)[1]);
gen vt = te*p0orbit;
K.vectred(vt);
if (verbose) {
cout << "p0orbit=" << vt << endl;
cout << "Got back to p0, word so far is " << convertword(cw) << endl;
}
if (!isPPower(C)) {
cout << "Cycle is not in <P>, seems there is no local tiling!" << endl;
exit(1);
}
}
if (iscomplex) {
cout << "Suspicious place" << endl;
gen angle_fraction = computeAngle(current_ridge, Xt);
cout << "angle: 1/" << K.onenumber/angle_fraction << endl;
angle_sum = angle_sum + angle_fraction;
}
}
else {
vector<int> power_of_p;
if (2*v<orderofp) {
for (int k=0; k<v; k++) {
power_of_p.push_back(-4);
C = Pi*C;
K.matred(C);
Xt = Pi*Xt;
K.vectred(Xt);
p0orbit = Pi*p0orbit;
K.vectred(p0orbit);
if (K.areDep(p0orbit,p0)) {
if (verbose) {
cout << "C=" << C << endl;
cout << "p0=" << p0 << endl;
}
gen te = K.inverse((*p0orbit._VECTptr)[1]);
gen vt = te*p0orbit;
K.vectred(vt);
if (verbose) {
cout << "p0orbit=" << vt << endl;
}
cout << "Got back to p0";
if (!isPPower(C)) {
cout << "Cycle is not in <P>, seems there is no local tiling!" << endl;
exit(1);
}
}
}
}
else {
int v2 = orderofp-v;
for (int k=0; k<v2; k++) {
power_of_p.push_back(4);
C = P*C;
K.matred(C);
Xt = P*Xt;
K.vectred(Xt);
p0orbit = P*p0orbit;
K.vectred(p0orbit);
if (K.areDep(p0orbit,p0)) {
if (verbose) {
cout << "C=" << C << endl;
cout << "p0=" << p0 << endl;
}
gen te = K.inverse((*p0orbit._VECTptr)[1]);
gen vt = te*p0orbit;
K.vectred(vt);
if (verbose) {
cout << "p0orbit=" << vt << endl;
cout << "Got back to p0" << endl;
}
if (!isPPower(C)) {
cout << ", but cycle is not in <P>, there is no local tiling!" << endl;
cout << "The shell may still work, but the symmetry group is larger than just the cyclic <P>" << endl;
exit(1);
}
}
}
}
cw = concat(power_of_p,cw);
if (verbose) {
cout << ", word so far is " << convertword(cw) << endl;
}
}
}
}
if (!back) {
cerr << "Trouble with some ridge cycle" << endl;
exit(1);
}
else {
cout << "Got back to the same ridge, word so far is " << convertword(cw) << endl;
// start by checking if p0 goes back to itself under powers of C..
bool p0back = false;
gen p0copy = p0;
gen Ctest = K.Id;
int pow0 = 0;
while (!p0back && pow0<100) {
Ctest = Ctest*C;
K.matred(Ctest);
p0copy = C*p0copy;
K.vectred(p0copy);
p0back = K.areDep(p0,p0copy);
pow0++;
}
if (!p0back) {
cerr << "Did not find a small power of cycle tsf that's the identity (tried powers up to 100)" << endl;
exit(1);
}
else {
cout << "Power " << pow0 << " brings p0 back" << endl;
if (!isPPower(Ctest)) {
cout << "Some cycle tsf fixes p0, but it is not a power of P, Poincare may fail!" << endl;
exit(1);
}
else {
cout << "Corresponding power is in <P>" << endl;
}
}
bool isid = false;
gen tv_start1 = vertices[ridges[ridgePOrbits[init_orbit_index][0]].verts[0]].coords;
gen tv_start2 = vertices[ridges[ridgePOrbits[init_orbit_index][0]].verts[1]].coords;
gen tv1 = tv_start1;
gen tv2 = tv_start2;
int pow = 0;
vector<int> cwp;
gen Cp = K.Id;
while (!isid && pow<100) {
cwp = concat(cwp,cw);
Cp = Cp*C;
K.matred(Cp);
tv1 = C*tv1;
K.vectred(tv1);
tv2 = C*tv2;
K.vectred(tv2);
isid = K.areDep(tv1,tv_start1) && K.areDep(tv2,tv_start2); // If two points are fixed, sure to be the identity on the ridge (?)
pow++;
}
if (!isid) {
cerr << "Did not find a small power of cycle tsf that's the identity on the ridge (tried powers up to 100)" << endl;
exit(1);
}
else {
if (verbose) {
cout << "C=" << C << endl;
cout << "Order of C: " << K.order(C) << endl;
cout << "Cp=" << Cp << endl;
cout << "Order of Cp: " << K.order(Cp) << endl;
}
int o = K.order(Cp);
int op = o*pow;
cout << "(" << convertword(cw) << ")^" << pow << "=id on the ridge" << endl; // not sure we care about that
if (op>2) {
cout << "(" << convertword(cw) << ")^" << op << "=id (need to check angles)" << endl;
}
else {
cout << "(" << convertword(cw) << ")^" << op << "=id" << endl;
}
if (iscomplex) {
if (verbose) {
cout << "Complex line" << endl;
}
/*
* In some cases, there may be two angles to check:
* one always needs to compare
* - the rotation angle of C^p in the direction orthogonal to the ridge
* - the angle between the faces
* if the isolated fixed point is a vertex, also need to compare
* - the angle between the edges in the ridge adjacent to that vertex
* - the rotation angle in the direction
* So far, the second one was NOT implemented...
*/
// ALSO NEED TO INCLUDE COMMUTATION RELATION, BETWEEN CYCLE TSF AND Ppower, IF RELEVANT!
int oc = K.order(C);
if (oc<3) {
if (oc==2) {
cout << "Order 2, nothing to check for local tiling" << endl;
}
}
else {
// The following will not work when C is a complex reflection!
// should start by checking if that is the case or not (to first approx, this is pow=1?)
if (pow==1) {
gen XtImage = C*Xt;
K.vectred(XtImage);
if (!K.areDep(Xt,XtImage)) {
cerr << "Xt=" << Xt << " is not fixed, but pow=1, this makes no sense" << endl;
exit(1);
}
else {
// compare rotation angle with angle between the bisectors?
// one positive eigenvector is the polar to the ridge
gen miImage = C*mi0;
K.vectred(miImage);
if (!K.areDep(mi0,miImage)) {
cerr << "Mirror perp is not fixed, oops!" << endl;
exit(1);
}
else {
// want to compute the rotation angle from mi0 and Xt, it is given by the ratio of their eigenvalues...
int mik;
bool fd = false;
int ik = -1;
while (ik!=2 && !fd) {
ik++;
fd = !operator_equal(mi0[ik],K.zeronumber,&ct);
}
if (!fd) {
cerr << "This vector should not be zero!" << endl;
exit(1);
}
gen ev2 = miImage[ik]*K.inverse(mi0[ik]);
K.red(ev2);
if (verbose) {
cout << "This should be negative: "<<K.evali(SqNorm(Xt))<<endl;
}
int Xk;
fd = false;
ik = -1;
while (ik!=2 && !fd) {
ik++;
fd = !operator_equal(Xt[ik],K.zeronumber,&ct);
}
if (!fd) {
cerr << "This vector should not be zero!" << endl;
exit(1);
}
gen ev1 = XtImage[ik]*K.inverse(Xt[ik]);
K.red(ev1);
gen an = ev2*K.inverse(ev1);
K.red(an);
if (verbose) {
cout << "an=" << an << endl;
cout << "genasrootof=" << K.genasrootof << endl;
}
gen anro = eval(_subst(makesequence(an,x__IDNT_e,K.genasrootof),&ct),&ct);
if (verbose) {
cout << "pmin(anro): " << _pmin(anro,&ct) << endl;
cout << "Rotation angle of cx refl is arg of " << anro << endl;
}
if (operator_equal(anro,K.onenumber,&ct)) {
cout << "Rotation by angle 0 (this should not happen!?)" << endl;
}
else {
if (operator_equal(anro,gen("-1",&ct),&ct)) {
cout << "Rotation by pi (for complex refl)" << endl;
}
else {
gen po = _simplify(_pmin(anro,&ct) - ipmin,&ct);
if (verbose) {
cout << "po=" << po << endl;
}
if (is_zero(po,&ct)) {
if (is_greater(_evalf(im(anro,&ct),&ct),K.zeronumber,&ct)) {
cout << "Rotation by pi/2 (for complex refl)" << endl;
}
else {
if (is_greater(K.zeronumber,_evalf(im(anro,&ct),&ct),&ct)) {
cout << "Rotation by -pi/2 (for complex refl)" << endl;
}
}
}
else {
if (verbose) {
cout << "anro=" << anro << endl;
cout << _evalf(anro,&ct) << endl;
}
gen te0 = _simplify(_eval(anro,&ct),&ct);
if (verbose) {
cout << "te0=" << te0 << endl;
cout << "convert te0 interval: " << convert_interval(te0,K.nd,&ct) << endl;
cout << "arg/2pi: " << arg(convert_interval(te0,K.nd,&ct),&ct)/(2*gen("pi",&ct)) << endl;
}
gen te = K.onenumber/re(arg(convert_interval(eval(te0,1,&ct),K.nd,&ct),&ct)/(2*gen("pi",&ct)),&ct);
gen width = _right(te,&ct) - _left(te,&ct);
if (is_greater(width,K.onenumber,&ct)) {
cerr << "Ambiguous angle computations, interval contains several integers!" << endl;
}
else {
if (verbose) {
cout << "te=" << te << endl;
cout << "(will take right, then floor)" << endl;
}
gen i = _floor(_right(te,&ct),&ct);
if (verbose) {
cout << "i=" << i << endl;
}
if (!is_greater(i,_left(te,&ct),&ct)) {
cerr << "The angle interval contains no inverse of an integer, perhaps the integrality condition fails!" << endl;
cout << "The angle interval contains no inverse of an integer, perhaps the integrality condition fails!" << endl;
exit(1);
}
else {
cout << "Rotation by 2*pi/" << i << " (for complex refl)" << endl;
}
}
// }
// }
}
}
}
}
}
}
else {
/* gen Hv = normal(_subst(makesequence(H,x__IDNT_e,K.genasrootof),&ct),&ct);
if (verbose) {
cout << "H=" << Hv << endl;
}
gen Ct = normal(_subst(makesequence(C,x__IDNT_e,K.genasrootof),&ct),&ct);
if (verbose) {
cout << "Ct=" << Ct << endl;
}*/
// A priori, the following will only work if Ct has distinct eigenvalues
// (could easily be fixed, it should be easier if it is a complex reflection)
bool success = false;
int count = 0;
int savend = K.nd;
while (!success && count<10) {
vecteur U,evs;
int ct_it = 0;
int loc = K.linearorder(C);
if (my_jordan_knowing_linear_order_alt(C,loc,U,evs)) {
// In new version, the rational numbers encoding angles are already computed, they are in the vecteur "evs"
// while interval versions of the corresponding eigenvectors are in the vecteur "U"
// note that U[0] is the negative vector
// Still need to compare U[1] and U[2] with the mirror perp
// the angle inside mirror is given by the eigenvalues for the mirror perp
// the angle transverse to the mirror is the other one
bool ambiguous = false;
if (verbose) {
cout << "xvi=" << K.xvi << endl;
}
gen Vi = conj(convert_interval(_subst(makesequence(mi0,x__IDNT_e,K.xvi),&ct),K.nd,&ct),&ct);
// I don't know if mi0 is correct at this stage, hopefully this is the mirror perp for the ridge
if (verbose) {
cout << "mi0 num: " << Vi << endl;
}
gen Hi = convert_interval(_subst(makesequence(H,x__IDNT_e,K.xvi),&ct),K.nd,&ct);
if (verbose) {
cout << "Hi=" << Hi << endl;
}
gen ip1 = Vi*Hi*U[1];
gen n1 = re(ip1,&ct)*re(ip1,&ct) + im(ip1,&ct)*im(ip1,&ct);
gen ip2 = Vi*Hi*U[2];
gen n2 = re(ip2,&ct)*re(ip2,&ct) + im(ip2,&ct)*im(ip2,&ct);
if (verbose) {
cout << "n1=" << n1 << endl;
cout << "n2=" << n2 << endl;
}
// One (and only one) of these should be zero, the other one strictly positive
gen longitudinal_angle, transversal_angle;
bool test1 = (is_greater(_left(n1,&ct),K.prec,&ct) && is_greater(K.zeronumber,_left(n2,&ct),&ct));
// test1 means n1 can be zero
bool test2 = (is_greater(_left(n2,&ct),K.prec,&ct) && is_greater(K.zeronumber,_left(n1,&ct),&ct));
// test1 means n2 can be zero
if(verbose) {
cout << "evs= " << evs << endl;
}
if (test1) {
if (!test2) {
// U[1] is Vi (?)
gen al = evs[2]-evs[0];
if (verbose) {
cout << "al=" << al << endl;
}
int aln = _numer(al,&ct).val;
int ald = _denom(al,&ct).val;
if (verbose) {
cout << "(" << aln << "/" << ald << ")" << endl;
}
if (2*ald<-aln) { // do we want to allow negative angles?
aln = aln+ald;
}
if (verbose) {
cout << " after modif (" << aln << "/" << ald << ")" << endl;
}
longitudinal_angle = aln*K.onenumber/ald;
gen tl = evs[1]-evs[0];
if (verbose) {
cout << "tl=" << tl << endl;
}
int tln = _numer(tl,&ct).val;
int tld = _denom(tl,&ct).val;
if (verbose) {
cout << "(" << tln << "/" << tld << ")" << endl;
}
if (2*tld<-tln) {
tln = tln+tld;
}
if (verbose) {
cout << " after modif (" << tln << "/" << tld << ")" << endl;
}
transversal_angle = tln*K.onenumber/tld;
}
else {
cout << "Interval computations are ambiguous, you may want to try using better precision" << endl;
ambiguous = true;
}
}
else {
if (test2) {
// U[2] is Vi
gen al = evs[1]-evs[0];
if (verbose){
cout << "al=" << al << endl;
}
int aln = _numer(al,&ct).val;
int ald = _denom(al,&ct).val;
if (verbose) {
cout << "(" << aln << "/" << ald << ")" << endl;
}
if (2*ald<-aln) { // do we want to allow negative angles?
aln = aln+ald;
}
if (verbose){
cout << " after modif (" << aln << "/" << ald << ")" << endl;
}
longitudinal_angle = aln*K.onenumber/ald;
gen tl = evs[2]-evs[0];
if (verbose) {
cout << "tl=" << tl << endl;
}
int tln = _numer(tl,&ct).val;
int tld = _denom(tl,&ct).val;
if (verbose) {
cout << "(" << tln << "/" << tld << ")" << endl;
}
if (2*tld<-tln) {
tln = tln+tld;
}
if (verbose) {
cout << " after modif (" << tln << "/" << tld << ")" << endl;
}
transversal_angle = tln*K.onenumber/tld;
}
else {
cout << "Interval computations are ambiguous, you may want to try using better precision" << endl;
ambiguous = true;
}
}
if (!ambiguous) {
success = true;
cout << "Longitudinal angle 2*pi*(" << longitudinal_angle << ")" << endl;
cout << "Transversal angle 2*pi*(" << transversal_angle << ")" << endl;
gen tapow = pow*transversal_angle;
if (verbose) {
cout << "tapow=" << tapow << endl;
}
int tapow_num = _abs(_numer(tapow,&ct),&ct).val;
int tapow_den = _denom(tapow,&ct).val;
if (verbose) {
cout << "(" << tapow_num << "/" << tapow_den << ")" << endl;
}
if (tapow_num!=1) {
cout << "Numerator is not equal to one, integrality condition fails" << endl;
exit(1);
}
else {
if (tapow_den!=o) {
cout << "The angle is not consistent with the order of the cycle transformation" << endl;
cout << " Integrality condition fails" << endl;
exit(1);
}
else {
cout << "Integrality condition holds on this ridge!" << endl;
}
}
if (K.nd>savend) {
K.nd = savend;
K.lowerPrecision();
}
}
}
if (!success) {
cout << "Found ambiguity in interval computations (of angles of cycle tsf), will now increase precision and try again" << endl;
cout << " count=" << count << endl;
K.increasePrecision();
}
count++;
}
if (!success) {
cout << "Found ambiguity in interval computations even after significantly increasing precision" << endl;
cout << " I will stop now, sorry" << endl;
exit(1);
}
}
}
}
string rel;
if (op==1) {
rel = convertwordgap(cw);
bool isnew = true;
int uu = 0;
while (isnew && uu<rels.size()) {
isnew = (rel!=rels[uu]);
uu++;
}
if (isnew) {
rels.push_back(rel);
}
}
else {
stringstream powstring;
powstring << op;
rel = "(" + convertwordgap(cw) + ")^" + powstring.str();
bool isnew = true;
int uu = 0;
while (isnew && uu<rels.size()) {
isnew = (rel!=rels[uu]);
uu++;
}
if (isnew) {
rels.push_back(rel);
}
}
gen D = Cp;
for (int u=1; u<o; u++) {
D = D*Cp;
K.matred(D);
}
if (K.isScalar(D)) {
cout << "Check matrix OK" << endl;
}
else {
cerr << "Problem with cycle tsf, found a non-scalar matrix!" << endl;
exit(1);
}
// may need to include a commutation relation?
// * check id ridge is preserved by power of P
// * if so, check whether this power commutes with C
// * (if it doesn't, QUIT, at least for now)
int j0 = ridgePOrbits[init_orbit_index][0];
int j1 = applyPToRidge(orderofppower,j0);
bool testInvariance = (j0==j1);
if (testInvariance) {
cout << "Ridge is invariant by P^" << orderofppower << endl;
if (verbose) {
cout << "C=" << C << endl;
cout << "Ppower=" << Ppower << endl;
cout << "C^-1=" << K.matinverse(C) << endl;
cout << "Ppower^-1=" << K.matinverse(Ppower) << endl;
}
gen M = C*Ppower*K.matinverse(C)*K.matinverse(Ppower);
K.matred(M);
if (K.isScalar(M)) {
stringstream powstring1;
powstring1 << orderofppower;
vector<int> cwi = invertword(cw);
string commrel = "P^" + powstring1.str() + "*" + convertwordgap(cw) + "*P^-" + powstring1.str() + "*" + convertwordgap(cwi);
bool isnew = true;
int uu = 0;
while (isnew && uu<rels.size()) {
isnew = (commrel!=rels[uu]);
uu++;
}
if (isnew) {
rels.push_back(commrel);
}
cout << "Adding commutation relation with power of P: " << commrel << endl;
}
else {
cerr << "P power does not commute with cycle tsf, don't know what to do" << endl;
exit(1);
}
}
cout << "" << endl;
}
}
}
for (int uu=0; uu<rels.size(); uu++) {
file << "," << rels[uu];
}
file << "];" << endl;
file.close();
cout << "Wrote the presentation in GAP style in the file: " << filename << endl;
}
void Polytope::drawFace(int j) {
ofstream file;
stringstream ss;
ss << j;
string filename = "pics/pic"+K.tag+"_face"+ss.str()+".asy";
file.open(filename.c_str());
file << "import graph3;" << endl;
file << "import three;" << endl;
file << "size(7.5cm,0);" << endl;
file << "pen p=black+1;" << endl;
file << "draw(unithemisphere,white+opacity(0.1));" << endl;
gen Hn = K.matevaln(H);
gen V0 = faces[j].apexProjection;
gen V1 = Proj(faces[j].apex.coords,faces[j].apexProjection);
gen V2 = faces[j].cspine;
gen W0 = K.vectevaln(V0) / sqrt(re(-K.evaln(Inn(V0,V0)),&ct),&ct);
gen W1 = K.vectevaln(V1) / sqrt(re(K.evaln(Inn(V1,V1)),&ct),&ct);
gen W2 = K.vectevaln(V2) / sqrt(re(K.evaln(Inn(V2,V2)),&ct),&ct);
vecteur te;
te.push_back(W0);
te.push_back(W1);
te.push_back(W2);
gen A = _tran(gen(te),&ct);
gen Ai = _inverse(A,&ct);
int k1 = 0;
int l1 = faces[j].sides[0].word.size();
for (int k=1; k<faces[j].sides.size(); k++) {
int l = faces[j].sides[k].word.size();
if (l<l1) {
l1 = l;
k1 = k;
}
}
int k2;
if (k1==0) {
if (faces[j].sides[faces[j].sides.size()-1].word.size()<faces[j].sides[1].word.size()) {
k2 = faces[j].sides.size()-1;
}
else {
k2 = 1;
}
}
else {
k2 = (k1+1)%faces[j].sides.size();
}
gen zo,to,zt,tt;
gen U = Ai*K.vectevaln(faces[j].bottomface[k1].coords);
gen zu = U[2]/U[0];
gen tu = re(U[1]/U[0],&ct);
gen V = Ai*K.vectevaln(faces[j].bottomface[k2].coords);
gen zv = V[2]/V[0];
gen tv = re(V[1]/V[0],&ct);
zo = (zu+zv)/2;
to = (tu+tv)/2;
int n = faces[j].sides.size();
if (n%2==0) {
int k3 = (k1 + n/2)%n;
int k4 = (k2 + n/2)%n;
U = Ai*K.vectevaln(faces[j].bottomface[k3].coords);
zu = U[2]/U[0];
tu = re(U[1]/U[0],&ct);
V = Ai*K.vectevaln(faces[j].bottomface[k4].coords);
zv = V[2]/V[0];
tv = re(V[1]/V[0],&ct);
zt = (zu+zv)/2;
tt = (tu+tv)/2;
}
else {
int k3;
if (k2>k1) {
k3 = (k2 + n/2)%n;
}
else {
k3 = (k1 + n/2)%n;
}
gen U = Ai*K.vectevaln(faces[j].bottomface[k3].coords);
zt = U[2]/U[0];
tt = re(U[1]/U[0],&ct);
}
gen Xp = Ai*K.vectevaln(faces[j].topface[0].coords);
gen top_level = re(Xp[1]/Xp[0],&ct);
gen zk = zo-zt;
zk = zk/abs(zk,&ct);
file << "currentprojection=orthographic((" << re(zk,&ct) << "," << im(zk,&ct) << "," << 0.3 << "));" << endl;
string norm = "(0,0,1)";
string ccw = "false";
gen z1,z2,den,X;
if (faces[j].topface.size()>1) {
vecteur top_verts;
gen X = Ai*K.vectevaln(faces[j].topface[0].coords);
gen top_rv = K.onenumber - top_level*top_level;;
top_verts.push_back(X[2]/X[0]);
for (int k=1; k<faces[j].topface.size(); k++) {
X = Ai*K.vectevaln(faces[j].topface[k].coords);
top_verts.push_back(X[2]/X[0]);
}
for (int k=0; k<top_verts.size()-1; k++) {
z1 = top_verts[k];
z2 = top_verts[k+1];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),p);" << endl;
}
else {
gen ctr = (top_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<top_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
}
}
z1 = top_verts[top_verts.size()-1];
z2 = top_verts[0];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct) && is_greater(abs(z1-z2,&ct),1e-4,&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),p);" << endl;
}
else {
gen ctr = (top_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<top_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
}
}
for (int k=0; k<faces[j].midvertices.size(); k++) {
X = Ai*K.vectevaln(faces[j].midvertices[k].coords);
}
vecteur bottom_verts;
X = Ai*K.vectevaln(faces[j].bottomface[0].coords);
gen bottom_level = re(X[1]/X[0],&ct);
gen bottom_rv = K.onenumber - bottom_level*bottom_level;
bottom_verts.push_back(X[2]/X[0]);
for (int k=1; k<faces[j].bottomface.size(); k++) {
X = Ai*K.vectevaln(faces[j].bottomface[k].coords);
bottom_verts.push_back(X[2]/X[0]);
}
for (int k=0; k<bottom_verts.size()-1; k++) {
z1 = bottom_verts[k];
z2 = bottom_verts[k+1];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << bottom_level << "));" << endl;
}
}
else {
gen ctr = (bottom_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<bottom_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen zma = ctr + (zm-ctr)*abs(z1-ctr,&ct)/abs(zm-ctr,&ct);
file << "$\",(" << re(zma,&ct) << "," << im(zma,&ct) << "," << bottom_level << "));" << endl;
}
}
}
z1 = bottom_verts[bottom_verts.size()-1];
z2 = bottom_verts[0];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << bottom_level << "));" << endl;
}
}
else {
gen ctr = (bottom_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<bottom_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen zma = ctr + (zm-ctr)*abs(z1-ctr,&ct)/abs(zm-ctr,&ct);
file << "$\",(" << re(zma,&ct) << "," << im(zma,&ct) << "," << bottom_level << "));" << endl;
}
}
// then draw vertical edges...
if (faces[j].topface.size()>1) {
for (int l=0; l<faces[j].bottomface.size(); l++) {
if (find(faces[j].midvertindices.begin(),faces[j].midvertindices.end(),l)==faces[j].midvertindices.end()) {
// draw straight line from tf[l] to bf[l]
gen X1 = Ai*K.vectevaln(faces[j].topface[l].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].bottomface[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
vector<int> w = faces[j].sides[l].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen tm = (t1+t2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
}
}
else {
for (int l=0; l<faces[j].bottomface.size(); l++) {
if (find(faces[j].midvertindices.begin(),faces[j].midvertindices.end(),l)==faces[j].midvertindices.end()) {
// draw straight line from bf[l] to tf[0]
gen X1 = Ai*K.vectevaln(faces[j].topface[0].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].bottomface[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
vector<int> w = faces[j].sides[l].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen tm = (t1+t2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
}
}
for (int l=0; l<faces[j].midvertices.size(); l++) {
if (faces[j].topface.size()>1) {
gen X1 = Ai*K.vectevaln(faces[j].bottomface[faces[j].midvertindices[l]].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].midvertices[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
gen X3 = Ai*K.vectevaln(faces[j].topface[faces[j].midvertindices[l]].coords);
gen z3 = X3[2]/X3[0];
gen t3 = re(X3[1]/X3[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
file << "draw(("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<")--("<<re(z3,&ct)<<","<<im(z3,&ct)<<","<<t3<<"),p);" << endl;
vector<int> w = faces[j].sides[faces[j].midvertindices[l]].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z2+z3)/2;
gen tm = (t2+t3)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
else {
gen X1 = Ai*K.vectevaln(faces[j].bottomface[faces[j].midvertindices[l]].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].midvertices[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
gen X3 = Ai*K.vectevaln(faces[j].topface[0].coords);
gen z3 = X3[2]/X3[0];
gen t3 = re(X3[1]/X3[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
file << "draw(("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<")--("<<re(z3,&ct)<<","<<im(z3,&ct)<<","<<t3<<"),p);" << endl;
vector<int> w = faces[j].sides[faces[j].midvertindices[l]].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z2+z3)/2;
gen tm = (t2+t3)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
}
file << "pen dp = blue+4;"<< endl;
file << "pen dpi = red+4;"<< endl;
for (int k=0; k<faces[j].topface.size(); k++) {
gen X = Ai*K.vectevaln(faces[j].topface[k].coords);
gen z = X[2]/X[0];
gen t = re(X[1]/X[0],&ct);
gen te = SqNorm(faces[j].topface[k].coords);
if (operator_equal(te,K.zeronumber,&ct)) {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dpi);" << endl;
}
else {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dp);" << endl;
}
}
for (int k=0; k<faces[j].bottomface.size(); k++) {
gen X = Ai*K.vectevaln(faces[j].bottomface[k].coords);
gen z = X[2]/X[0];
gen t = re(X[1]/X[0],&ct);
gen te = SqNorm(faces[j].bottomface[k].coords);
if (operator_equal(te,K.zeronumber,&ct)) {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dpi);" << endl;
}
else {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dp);" << endl;
}
}
for (int k=0; k<faces[j].midvertices.size(); k++) {
gen X = Ai*K.vectevaln(faces[j].midvertices[k].coords);
gen z = X[2]/X[0];
gen t = re(X[1]/X[0],&ct);
gen te = SqNorm(faces[j].midvertices[k].coords);
if (operator_equal(te,K.zeronumber,&ct)) {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dpi);" << endl;
}
else {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dp);" << endl;
}
}
file.close();
}
void Polytope::drawFaceSector(int j, int kv1, int kv2) {
// draw face j, marking sector between kv1 and kv2
ofstream file;
stringstream ss;
ss << j;
string filename = "pics/pic"+K.tag+"_face"+ss.str()+"_alt.asy";
file.open(filename.c_str());
file << "import graph3;" << endl;
file << "import three;" << endl;
file << "size(7.5cm,0);" << endl;
file << "pen p=black+1;" << endl;
file << "draw(unithemisphere,white+opacity(0.1));" << endl;
gen Hn = K.matevaln(H);
gen V0 = faces[j].apexProjection;
gen V1 = Proj(faces[j].apex.coords,faces[j].apexProjection);
gen V2 = faces[j].cspine;
gen W0 = K.vectevaln(V0) / sqrt(re(-K.evaln(Inn(V0,V0)),&ct),&ct);
gen W1 = K.vectevaln(V1) / sqrt(re(K.evaln(Inn(V1,V1)),&ct),&ct);
gen W2 = K.vectevaln(V2) / sqrt(re(K.evaln(Inn(V2,V2)),&ct),&ct);
vecteur te;
te.push_back(W0);
te.push_back(W1);
te.push_back(W2);
gen A = _tran(gen(te),&ct);
gen Ai = _inverse(A,&ct);
int k1 = 0;
int l1 = faces[j].sides[0].word.size();
for (int k=1; k<faces[j].sides.size(); k++) {
int l = faces[j].sides[k].word.size();
if (l<l1) {
l1 = l;
k1 = k;
}
}
int k2;
if (k1==0) {
if (faces[j].sides[faces[j].sides.size()-1].word.size()<faces[j].sides[1].word.size()) {
k2 = faces[j].sides.size()-1;
}
else {
k2 = 1;
}
}
else {
k2 = (k1+1)%faces[j].sides.size();
}
gen zo,to,zt,tt;
gen U = Ai*K.vectevaln(faces[j].bottomface[k1].coords);
gen zu = U[2]/U[0];
gen tu = re(U[1]/U[0],&ct);
gen V = Ai*K.vectevaln(faces[j].bottomface[k2].coords);
gen zv = V[2]/V[0];
gen tv = re(V[1]/V[0],&ct);
zo = (zu+zv)/2;
to = (tu+tv)/2;
int n = faces[j].sides.size();
if (n%2==0) {
int k3 = (k1 + n/2)%n;
int k4 = (k2 + n/2)%n;
U = Ai*K.vectevaln(faces[j].bottomface[k3].coords);
zu = U[2]/U[0];
tu = re(U[1]/U[0],&ct);
V = Ai*K.vectevaln(faces[j].bottomface[k4].coords);
zv = V[2]/V[0];
tv = re(V[1]/V[0],&ct);
zt = (zu+zv)/2;
tt = (tu+tv)/2;
}
else {
int k3;
if (k2>k1) {
k3 = (k2 + n/2)%n;
}
else {
k3 = (k1 + n/2)%n;
}
gen U = Ai*K.vectevaln(faces[j].bottomface[k3].coords);
zt = U[2]/U[0];
tt = re(U[1]/U[0],&ct);
}
gen Xp = Ai*K.vectevaln(faces[j].topface[0].coords);
gen top_level = re(Xp[1]/Xp[0],&ct);
gen zk = zo-zt;
zk = zk/abs(zk,&ct);
file << "currentprojection=orthographic((" << re(zk,&ct) << "," << im(zk,&ct) << "," << 0.3 << "));" << endl;
string norm = "(0,0,1)";
string ccw = "false";
// cout << "Top" << endl;
gen z1,z2,den,X;
if (faces[j].topface.size()>1) {
vecteur top_verts;
gen X = Ai*K.vectevaln(faces[j].topface[0].coords);
gen top_rv = K.onenumber - top_level*top_level;;
top_verts.push_back(X[2]/X[0]);
for (int k=1; k<faces[j].topface.size(); k++) {
X = Ai*K.vectevaln(faces[j].topface[k].coords);
top_verts.push_back(X[2]/X[0]);
}
for (int k=0; k<top_verts.size()-1; k++) {
z1 = top_verts[k];
z2 = top_verts[k+1];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),p);" << endl;
}
else {
gen ctr = (top_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<top_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
}
}
z1 = top_verts[top_verts.size()-1];
z2 = top_verts[0];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct) && is_greater(abs(z1-z2,&ct),1e-4,&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),p);" << endl;
}
else {
gen ctr = (top_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<top_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<top_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<top_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
}
}
for (int k=0; k<faces[j].midvertices.size(); k++) {
X = Ai*K.vectevaln(faces[j].midvertices[k].coords);
}
vecteur bottom_verts;
X = Ai*K.vectevaln(faces[j].bottomface[0].coords);
gen bottom_level = re(X[1]/X[0],&ct);
gen bottom_rv = K.onenumber - bottom_level*bottom_level;
bottom_verts.push_back(X[2]/X[0]);
for (int k=1; k<faces[j].bottomface.size(); k++) {
X = Ai*K.vectevaln(faces[j].bottomface[k].coords);
bottom_verts.push_back(X[2]/X[0]);
}
for (int k=0; k<bottom_verts.size()-1; k++) {
z1 = bottom_verts[k];
z2 = bottom_verts[k+1];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << bottom_level << "));" << endl;
}
}
else {
gen ctr = (bottom_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<bottom_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen zma = ctr + (zm-ctr)*abs(z1-ctr,&ct)/abs(zm-ctr,&ct);
file << "$\",(" << re(zma,&ct) << "," << im(zma,&ct) << "," << bottom_level << "));" << endl;
}
}
}
z1 = bottom_verts[bottom_verts.size()-1];
z2 = bottom_verts[0];
den = conj(z1,&ct)*z2 - z1*conj(z2,&ct);
if (is_greater(1e-4,abs(den,&ct),&ct)) {
// draw straight line
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << bottom_level << "));" << endl;
}
}
else {
gen ctr = (bottom_rv*(z2-z1) + abs(z1,&ct)*abs(z1,&ct)*z2 - abs(z2,&ct)*abs(z2,&ct)*z1 )/den;
gen xc = re(ctr,&ct);
gen yc = im(ctr,&ct);
file << "draw(Arc(("<<xc<<","<<yc<<","<<bottom_level<<"),("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<bottom_level<<"),("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<bottom_level<<"),"<<norm<<","<<ccw<<"),p);" << endl;
vector<int> w = faces[j].mirror.word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen zma = ctr + (zm-ctr)*abs(z1-ctr,&ct)/abs(zm-ctr,&ct);
file << "$\",(" << re(zma,&ct) << "," << im(zma,&ct) << "," << bottom_level << "));" << endl;
}
}
// then draw vertical edges...
if (faces[j].topface.size()>1) {
for (int l=0; l<faces[j].bottomface.size(); l++) {
if (find(faces[j].midvertindices.begin(),faces[j].midvertindices.end(),l)==faces[j].midvertindices.end()) {
// draw straight line from tf[l] to bf[l]
gen X1 = Ai*K.vectevaln(faces[j].topface[l].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].bottomface[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
vector<int> w = faces[j].sides[l].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen tm = (t1+t2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
}
}
else {
for (int l=0; l<faces[j].bottomface.size(); l++) {
if (find(faces[j].midvertindices.begin(),faces[j].midvertindices.end(),l)==faces[j].midvertindices.end()) {
// draw straight line from bf[l] to tf[0]
gen X1 = Ai*K.vectevaln(faces[j].topface[0].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].bottomface[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
vector<int> w = faces[j].sides[l].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z1+z2)/2;
gen tm = (t1+t2)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
}
}
for (int l=0; l<faces[j].midvertices.size(); l++) {
if (faces[j].topface.size()>1) {
gen X1 = Ai*K.vectevaln(faces[j].bottomface[faces[j].midvertindices[l]].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].midvertices[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
gen X3 = Ai*K.vectevaln(faces[j].topface[faces[j].midvertindices[l]].coords);
gen z3 = X3[2]/X3[0];
gen t3 = re(X3[1]/X3[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
file << "draw(("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<")--("<<re(z3,&ct)<<","<<im(z3,&ct)<<","<<t3<<"),p);" << endl;
vector<int> w = faces[j].sides[faces[j].midvertindices[l]].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z2+z3)/2;
gen tm = (t2+t3)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
else {
gen X1 = Ai*K.vectevaln(faces[j].bottomface[faces[j].midvertindices[l]].coords);
gen z1 = X1[2]/X1[0];
gen t1 = re(X1[1]/X1[0],&ct);
gen X2 = Ai*K.vectevaln(faces[j].midvertices[l].coords);
gen z2 = X2[2]/X2[0];
gen t2 = re(X2[1]/X2[0],&ct);
gen X3 = Ai*K.vectevaln(faces[j].topface[0].coords);
gen z3 = X3[2]/X3[0];
gen t3 = re(X3[1]/X3[0],&ct);
file << "draw(("<<re(z1,&ct)<<","<<im(z1,&ct)<<","<<t1<<")--("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<"),p);" << endl;
file << "draw(("<<re(z2,&ct)<<","<<im(z2,&ct)<<","<<t2<<")--("<<re(z3,&ct)<<","<<im(z3,&ct)<<","<<t3<<"),p);" << endl;
vector<int> w = faces[j].sides[faces[j].midvertindices[l]].word;
if (w.size()<10) {
file << "label(\"$";
for (int u=0; u<w.size(); u++) {
if (w[u]<0) {
file << "\\bar" << -w[u];
}
else {
file << w[u];
}
}
gen zm = (z2+z3)/2;
gen tm = (t2+t3)/2;
file << "$\",(" << re(zm,&ct) << "," << im(zm,&ct) << "," << tm << "),align=right);" << endl;
}
}
}
file << "pen dp = blue+4;"<< endl;
file << "pen dpi = red+4;"<< endl;
for (int k=0; k<faces[j].topface.size(); k++) {
gen X = Ai*K.vectevaln(faces[j].topface[k].coords);
gen z = X[2]/X[0];
gen t = re(X[1]/X[0],&ct);
gen te = SqNorm(faces[j].topface[k].coords);
if (operator_equal(te,K.zeronumber,&ct)) {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dpi);" << endl;
}
else {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dp);" << endl;
}
}
for (int k=0; k<faces[j].bottomface.size(); k++) {
gen X = Ai*K.vectevaln(faces[j].bottomface[k].coords);
gen z = X[2]/X[0];
gen t = re(X[1]/X[0],&ct);
gen te = SqNorm(faces[j].bottomface[k].coords);
if (operator_equal(te,K.zeronumber,&ct)) {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dpi);" << endl;
}
else {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dp);" << endl;
}
}
for (int k=0; k<faces[j].midvertices.size(); k++) {
gen X = Ai*K.vectevaln(faces[j].midvertices[k].coords);
gen z = X[2]/X[0];
gen t = re(X[1]/X[0],&ct);
gen te = SqNorm(faces[j].midvertices[k].coords);
if (operator_equal(te,K.zeronumber,&ct)) {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dpi);" << endl;
}
else {
file << "dot(("<<re(z,&ct)<<","<<im(z,&ct)<<","<<t<<"),dp);" << endl;
}
}
gen Xt = Ai*K.vectevaln(faces[j].topface[0].coords);
gen top_lev = re(Xt[1]/Xt[0],&ct);
file << "draw((0,0,0)--(0,0," << top_lev << "),black+dashed);" << endl;
if (faces[j].topface.size()>1) {
gen Xt1 = Ai*K.vectevaln(faces[j].topface[kv1].coords);
gen Xt2 = Ai*K.vectevaln(faces[j].topface[kv2].coords);
gen zt1 = Xt1[2]/Xt1[0];
gen tt1 = re(Xt1[1]/Xt1[0],&ct);
gen zt2 = Xt2[2]/Xt2[0];
gen tt2 = re(Xt2[1]/Xt2[0],&ct);
file << "draw(("<<re(zt1,&ct)<<","<<im(zt1,&ct)<<","<<tt1<<")--(0,0,"<<top_lev<<"),black+dashed);" << endl;
file << "draw(("<<re(zt2,&ct)<<","<<im(zt2,&ct)<<","<<tt2<<")--(0,0,"<<top_lev<<"),black+dashed);" << endl;
}
gen Xb1 = Ai*K.vectevaln(faces[j].bottomface[kv1].coords);
gen Xb2 = Ai*K.vectevaln(faces[j].bottomface[kv2].coords);
gen zb1 = Xb1[2]/Xb1[0];
gen tb1 = re(Xb1[1]/Xb1[0],&ct);
gen zb2 = Xb2[2]/Xb2[0];
gen tb2 = re(Xb2[1]/Xb2[0],&ct);
file << "draw(("<<re(zb1,&ct)<<","<<im(zb1,&ct)<<","<<tb1<<")--(0,0,0),black+dashed);" << endl;
file << "draw(("<<re(zb2,&ct)<<","<<im(zb2,&ct)<<","<<tb2<<")--(0,0,0),black+dashed);" << endl;
file.close();
}
void Polytope::drawProjection(int axis) {
if (axis!=1 && axis!=2) {
axis = 1;
}
ofstream file;
string ax = static_cast<ostringstream*>( &(ostringstream() << axis) )->str();
string filename = "pics/pic"+K.tag+"_"+ax+".asy";
file.open(filename.c_str());
file << "import graph;" << endl;
file << "size(7.5cm,0);" << endl;
gen Hn = K.matevaln(H);
gen Qn = K.matevaln(Q);
gen D = _tran(conj(Qn,&ct),&ct)*Hn*Qn;
vecteur te;
te.push_back(K.onenumber/sqrt(-re(D[0][0],&ct),&ct));
te.push_back(K.onenumber/sqrt(-re(D[1][1],&ct),&ct));
te.push_back(K.onenumber/sqrt(-re(D[2][2],&ct),&ct));
gen KK = _diag(te,&ct);
Qn = Qn*KK;
Qn = _inverse(Qn,&ct);
gen fa = gen("180/pi",&ct);
for (int k=0; k<edges.size(); k++) {
gen X = _subst(makesequence(vertices[edges[k].origin].coords,x__IDNT_e,K.xv),&ct);
gen Y = _subst(makesequence(vertices[edges[k].end].coords,x__IDNT_e,K.xv),&ct);
gen te = _subst(makesequence(Inn(vertices[edges[k].origin].coords,vertices[edges[k].end].coords),x__IDNT_e,K.xv),&ct);
gen Y1 = -Y*te/abs(te);
gen X2 = Qn*X;
gen Y2 = Qn*Y1;
gen a1 = X2[axis]/X2[0];
gen a3 = Y2[axis]/Y2[0];
if (is_greater(abs(a1-a3,&ct),1e-4,&ct)) {
gen a2 = (X2[axis]+Y2[axis])/(X2[0]+Y2[0]);
gen b1 = conj(a2-a1,&ct);
gen b2 = conj(a3-a1,&ct);
gen l1 = abs(a2)*abs(a2)-abs(a1)*abs(a1);
gen l2 = abs(a3)*abs(a3)-abs(a1)*abs(a1);
gen denc = (b1*conj(b2,&ct)-conj(b1,&ct)*b2);
// cout << "denc=" << denc << endl;
if (is_greater(abs(denc),1e-4,&ct)) {
gen c = (conj(b2,&ct)*l1-conj(b1,&ct)*l2)/denc;
gen r = sqrt(abs(a1)*abs(a1)-2*re(a1*conj(c,&ct),&ct)+abs(c)*abs(c),&ct);
gen u1 = a1-c;
gen u3 = a3-c;
gen th1 = arg(u1,&ct)*fa;
gen th2 = arg(u3,&ct)*fa;
if (is_greater(th2,th1,&ct)) {
if (is_greater(th2-th1,180,&ct)) {
th2 = th2-360;
}
}
else {
if (is_greater(th1-th2,180,&ct)) {
th1 = th1-360;
}
}
if (is_greater(abs(th1-th2,&ct),180,&ct)) {
cout << "OOPS, unexpected situation.. this is not a serious problem" << endl;
cout << " (some pictures may be wrong)" << endl;
}
file << "draw(arc(("<<re(c,&ct)<<","<<im(c,&ct)<<"),"<<r<<","<<th1<<","<<th2<<"),black);" << endl;
}
else {
file << "draw(("<<re(a1,&ct)<<","<<im(a1,&ct)<<")--("<<re(a3,&ct)<<","<<im(a3,&ct)<<"),black);" << endl;
}
}
}
file.close();
}
bool Polytope::checkSide() {
vector<int> inds;
for (int k=0; k<faces.size(); k++) {
inds.push_back(k);
}
while (inds.size()>0) {
int k = inds[0];
bool foundbuddy = false;
int u = 0;
while (!foundbuddy && u<inds.size()-1) {
u++;
gen X = BoxProd(faces[k].cspine,faces[inds[u]].cspine);
if (!operator_equal(X,K.zerovector,&ct)) {
int sx;
if (K.checkSign(SqNorm(X),sx)) {
foundbuddy = sx<0;
if (foundbuddy) {
faces[k].X0 = X;
faces[k].X1 = reflectAcrossSpine(X,faces[k]);
faces[inds[u]].X0 = X;
faces[inds[u]].X1 = reflectAcrossSpine(X,faces[inds[u]]);
}
}
}
}
if (!foundbuddy) {
// may have to use other faces as buddies...
u=-1;
while (!foundbuddy && u!=faces.size()-1) {
u++;
gen X = BoxProd(faces[k].cspine,faces[u].cspine);
if (!operator_equal(X,K.zerovector,&ct)) {
int sx;
if (K.checkSign(SqNorm(X),sx)) {
foundbuddy = sx<0;
if (foundbuddy) {
faces[k].X0 = X;
faces[k].X1 = reflectAcrossSpine(X,faces[k]);
}
}
}
}
if (!foundbuddy) {
cerr << "Face #" << k << " is not coequidistant from anyone..." << endl;
cerr << " this may not be a serious issue, but I will stop now." << endl;
exit(1);
}
else {
inds.erase(inds.begin());
}
}
else {
inds.erase(inds.begin()+u);
if (u!=0) {
inds.erase(inds.begin());
}
else {
cerr << "Trouble in checkSide()" << endl;
exit(1);
}
}
}
gen Hn = K.evali(H);
gen p0n = evalf(p0,20,&ct);
bool res = true;
for (int k=0; k<faces.size() && res; k++) {
gen u1 = K.evali(faces[k].X0);
gen v1 = K.evali(faces[k].X1);
gen te = abs( conj(p0n,&ct)*Hn*u1 ) - abs( conj(p0n,&ct)*Hn*v1 );
res = is_greater(K.zeronumber,_right(te,&ct),&ct);
if (!res) {
cout << "Test face " << k << ": " << te << endl;
}
}
return res;
}
void Polytope::checkEdge(int j) {
cout << "Studying edge #" << j << ", whose endpoints are vertices of: " << convertword(edges[j].faceindices) << "... ";
gen X = vertices[edges[j].origin].coords;
gen Y = vertices[edges[j].end].coords;
gen te = Inn(X,Y);
Y = -te*Y;
K.vectred(Y);
gen Z = (1-K.t1)*X+K.t1*Y;
K.vectred(Z);
vector<int> inds;
for (int k=0; k<faces.size(); k++) {
if (find(edges[j].faceindices.begin(),edges[j].faceindices.end(),k)==edges[j].faceindices.end()) {
inds.push_back(k);
}
}
for (int k=0; k<inds.size(); k++) {
gen eq = simplify(Inn(Z,faces[inds[k]].X0)*Inn(faces[inds[k]].X0,Z) - Inn(Z,faces[inds[k]].X1)*Inn(faces[inds[k]].X1,Z),&ct);
K.red(eq);
eq = K.convertToReal(eq);
if (operator_equal(eq,K.zeronumber,&ct)) {
cout << "Equation is 0, edge is on a bisector of which it is not a facet (maybe because of reflections of order 2)" << endl;
}
else {
gen eq0 = _coeff(makesequence(eq,K.t1,0),&ct);
gen eq1 = simplify(_subst(makesequence(eq,K.t1,K.onenumber),&ct),&ct);
simplify(eq1,&ct);
K.red(eq1);
int sgn0, sgn1;
if (!K.checkSign(eq0,sgn0)){
cerr << "Problem checking sign of equation at origin, in edge check" << endl;
exit(1);
}
if (!K.checkSign(eq1,sgn1)){
cerr << "Problem checking sign of equation at endpt, in edge check" << endl;
exit(1);
}
if (sgn0>0 || sgn1>0) {
cout << "Edge is on WRONG side! (found this at an endpoint)" << endl;
cerr << "Edge is on WRONG side! (found this at an endpoint)" << endl;
exit(1);
}
if (sgn0==0){
if (sgn1==0){
cerr << "Both t=0 and t=1 are roots, this should mean edge is in the bisector!" << endl;
// ACTUALLY NOT QUITE, JUST WANT TO CHECK MIDPOINT!
gen tet = simplify(_subst(makesequence(eq,K.t1,K.onenumber/2),&ct),&ct);
int sgn2;
if (!K.checkSign(tet,sgn2)) {
cerr << "Problem checking sign of equation at midpt, in edge check" << endl;
exit(1);
}
if (sgn2>0) {
cout << "Edge is on WRONG side! (found this at an midpoint)" << endl;
cerr << "Edge is on WRONG side! (found this at an midpoint)" << endl;
exit(1);
}
}
else {
gen a = _coeff(makesequence(eq,K.t1,2),&ct);
if (operator_equal(a,K.zeronumber,&ct)) {
// cout << "Only t=0 gives a root" << endl;
// cout << "Edge is on negative side" << endl;
// return true;
}
else {
// check if te=-b/a is in [0,1]
gen te = -_coeff(makesequence(eq,K.t1,1),&ct)*K.inverse(a);
K.red(te);
// cout << "te=" << te << endl;
// cout << "Need to check if " << K.evali(te) << " is in [0,1]..." << endl;
int sc;
if (!K.checkSign(te,sc)) {
cerr << "Problem checking sign of t-value in edge parameter" << endl;
exit(1);
}
else {
if (sc>0) {
if (!K.checkSign(te-1,sc)) {
cerr << "Problem checking whether t<=1 in edge parameter" << endl;
exit(1);
}
else {
if (sc<0) {
cerr << "The 1-skeleton is not embedded!" << endl;
exit(1);
}
}
}
else {
// cout << "Only t=0 gives a root in [0,1]" << endl;
// cout << "Edge is on negative side" << endl;
// return true;
}
}
}
}
}
else {
// sgn0 != 0
if (sgn1==0){
// cout << "t=1 is a root" << endl;
gen a = _coeff(makesequence(eq,K.t1,2),&ct);
if (operator_equal(a,K.zeronumber,&ct)) {
// cout << "Only t=1 gives a root" << endl;
// return true;
}
else {
// check if te=-1-b/a is in [0,1]
gen te = -1-_coeff(makesequence(eq,K.t1,1),&ct)*K.inverse(a);
K.red(te);
// cout << "Need to check if " << K.evali(te) << " is in [0,1]..." << endl;
int sc;
if (!K.checkSign(te,sc)) {
cerr << "Problem checking sign of t-value in edge parameter" << endl;
exit(1);
}
else {
if (sc>0) {
if (!K.checkSign(te-1,sc)) {
cerr << "Problem checking whether t<=1 in edge parameter" << endl;
exit(1);
}
else {
if (sc<0) {
cerr << "The 1-skeleton is not embedded!" << endl;
exit(1);
}
else {
// cout << "Only t=1 gives a root in [0,1]" << endl;
// cout << "Edge is on negative side" << endl;
// return true;
}
}
}
else {
// cout << "Only t=1 gives a root in [0,1]" << endl;
// cout << "Edge is on negative side" << endl;
// return true;
}
}
}
}
else {
// no endpoint is on bisector, need to work harder?
// no, will simply evaluate value at maximum? //2at+b -> -b/2a
gen a = _coeff(makesequence(eq,K.t1,2),&ct);
int sga;
if (!K.checkSign(a,sga)) {
cerr << "Problem checking sign of a, in edge check" << endl;
exit(1);
}
if (sga==0) {
// cout << "Linear equation, enough to check endpoints!" << endl;
// cout << "Edge is on negative side" << endl;
// return true;
}
else {
if (sga>0) {
// cout << "Concavity is up, checking endpoints is enough..." << endl;
// cout << "Edge is on negative side" << endl;
// return true;
}
else {
gen tm = -_coeff(makesequence(eq,K.t1,1),&ct)*K.inverse(2*a);
K.red(tm);
// cout << "t-max: " << K.evali(tm) << endl;
// check if max is in [0,1], and if so, check that the max value is negative
int sg;
if (!K.checkSign(tm,sg)) {
cerr << "Problem checking sign of t-value of max of parabola, in edge check" << endl;
exit(1);
}
else {
if (sg>0) {
// tmax is > 0
if (!K.checkSign(tm-1,sg)) {
cerr << "Problem checking t-value of max of parabola, in edge check" << endl;
exit(1);
}
else {
if (sg<0) {
// t-max is between 0 and 1...
gen yo = _subst(makesequence(eq,K.t1,tm),&ct);
if (!K.checkSign(yo,sg)) {
cerr << "Problem checking sign of max value, in edge check" << endl;
exit(1);
}
else {
if (sg<=0) {
// cout << "Max of parabola occurs in [0,1], but value is negative." << endl;
// cout << "Edge is on negative side" << endl;
// return true;
}
else {
cout << "Edge is on WRONG side! (found this at an endpoint)" << endl;
cerr << "Edge is on WRONG side! (found this at an endpoint)" << endl;
exit(1);
}
}
}
else {
// tmax is >1
// cout << "t-max is > 1" << endl;
// cout << "Edge is on negative side" << endl;
}
}
}
else {
// tmax is < 0
// cout << "t-max is < 0" << endl;
// cout << "Edge is on negative side" << endl;
}
}
}
}
}
}
}
}
cout << " check!" << endl;
}
void Polytope::checkRidge(int i) {
int j = ridges[i].faceindices[0];
int k = ridges[i].faceindices[1];
cout << endl;
cout << "Checking ridge on faces #" << j << " and " << k << endl;
bool genparam = true;
gen X0 = BoxProd(faces[j].cspine,faces[k].cspine);
gen V0, W0, Z0; // Orthogonal (but not orthonormal) basis, with V0, W0 spanning common slice
// not sure I use this later...
if (operator_equal(X0,K.zerovector,&ct)) {
// cospinal
genparam = false;
gen Xte = BoxProd(faces[j].mirror.coords,faces[k].mirror.coords);
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Same mirror, this gives the common slice" << endl;
V0 = faces[j].apexProjection;
W0 = Proj(faces[j].bottomface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
Xte = BoxProd(faces[j].mirror.coords,faces[k].apex.coords);
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Mirror of face#" << j << " is same as top face of #" << k << endl;
cout << " this gives the common slice" << endl;
V0 = faces[j].apexProjection;
W0 = Proj(faces[j].bottomface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
Xte = BoxProd(faces[k].mirror.coords,faces[j].apex.coords);
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Mirror of face#" << k << " is same as top face of #" << j << endl;
cout << " this gives the common slice" << endl;
V0 = faces[k].apexProjection;
W0 = Proj(faces[k].bottomface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
Xte = BoxProd(faces[j].apex.coords,faces[k].apex.coords);
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Top of face#" << k << " is same as top face of #" << j << endl;
cout << " this gives the common slice" << endl;
V0 = BoxProd(faces[j].cspine,faces[j].apex.coords);
W0 = Proj(faces[j].topface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
cerr << "There is probably no common slice, will need to check this.." << endl;
cout << "There is probably no common slice, will need to check this.." << endl;
gen vj, wj, vk, wk;
wj = faces[j].apexProjection;
vj = faces[j].apex.coords;
vj = Inn(wj,vj)*vj;
K.vectred(vj);
vj = Proj(vj,wj);
gen vt = vj + K.t1*wj;
// take vj+t*wj, and find t-values for this to be on face k
//
gen eq = Inn(vt,faces[k].X0)*Inn(faces[k].X0,vt) - Inn(vt,faces[k].X1)*Inn(faces[k].X1,vt);
K.red(eq);
eq = K.convertToReal(eq);
K.red(eq);
cout << "Equation to solve: " << eq << endl;
gen eqro = eval(_subst(makesequence(eq,s__IDNT_e,K.realgenasrootof),&ct),1,&ct);
cout << "eqro:" << eqro << endl;
cout << "realgenasrootof: " << K.realgenasrootof << endl;
cout << " " << _evalf(K.realgenasrootof,&ct) << endl;
gen fa = _factors(makesequence(eqro,K.realgenasrootof),&ct);
for (int l=0; 2*l<(*fa._VECTptr).size(); l++) {
cout << "fa[" << (2*l) << "]=" << fa[2*l] << endl;
int deg = _degree(makesequence(fa[2*l],K.t1),&ct).val;
if (deg>1) {
cout << "Intersection of the real spines is not defined over the ambient number field" << endl;
cout << " (more programming to do!)" << endl;
exit(1);
}
else {
if (deg>0) {
gen te = normal(-_coeff(makesequence(fa[2*l],K.t1,0),&ct)/_coeff(makesequence(fa[2*l],K.t1,1),&ct),&ct);
if (verbose) {
cout << "te=" << te << endl;
cout << " (" << _evalf(te,&ct) << ")" << endl;
}
}
}
}
gen expr = SqNorm(vt);
K.red(expr);
expr = K.convertToReal(expr);
K.red(expr);
cout << "Then need to check sign of: " << expr << endl;
}
}
}
}
}
else {
// complex spines intersect in projective space, need to check if they intersect on the real spines
if (isOnPrism(X0,faces[j])) {
cout << "Extended real spine of face #" << j << " intersects extor #" << k << endl;
if (isOnPrism(X0,faces[k])) {
cout << "Extended real spine of face #" << k << " intersects extor #" << j << endl;
cout << "Real spines intersect... "; //either cotranchal, or linear?
int sx;
if (!K.checkSign(SqNorm(X0),sx)) {
cerr << "Trouble computing sign of square norm (in checkRidge)" << endl;
exit(1);
}
else {
if (sx>0) {
cout << "Cotranchal pair" << endl;
gen Y1 = faces[j].apexProjection;
Y1 = Inn(X0,Y1)*Y1;
K.red(Y1);
Y1 = Proj(Y1,X0);
gen Y2 = faces[k].apexProjection;
Y2 = Inn(X0,Y2)*Y2;
K.red(Y2);
Y2 = Proj(Y2,X0);
gen tee = Inn(Y1,faces[j].X0)*Inn(faces[j].X0,Y1)-Inn(Y1,faces[j].X1)*Inn(faces[j].X1,Y1);
K.red(tee);
tee = Inn(Y2,faces[k].X0)*Inn(faces[k].X0,Y2)-Inn(Y2,faces[k].X1)*Inn(faces[k].X1,Y2);
K.red(tee);
gen tt = (Inn(Y1,Y2)+Inn(Y2,Y1))/2;
gen te = SqNorm(Y1)*SqNorm(Y2) - tt*tt;
K.red(te);
te = K.convertToReal(te);
int sgn;
if (!K.checkSign(te,sgn)) {
cerr << "Trouble checking sign (is intersection is slice only)" << endl;
exit(1);
}
else {
if (sgn<0) {
cerr << "Intersection is not just the common slice!?" << endl;
// exit(1);
genparam = false; // THIS IS NOT WHAT WE WANT, ONLY OK IF WE DON'T NEED TO CHECK EXTRA COMPONENT...
}
else {
cout << "intersection is slice only!" << endl;
genparam = false;
}
}
V0 = X0;
if (K.areDep(X0,faces[j].apex.coords)) {
cout << "Common slice is top face of face #" << j << endl;
W0 = Proj(faces[j].topface[0].coords,V0);
}
else {
if (K.areDep(X0,faces[j].mirror.coords)) {
cout << "Common slice is mirror of face #" << j << endl;
W0 = Proj(faces[j].bottomface[0].coords,V0);
}
else {
cerr << "Unidentified common slice, this is odd.." << endl;
exit(1);
}
}
Z0 = BoxProd(V0,W0); // not clear if we need this
if (K.areDep(X0,faces[k].apex.coords)) {
cout << "Common slice is top face of face #" << k << endl;
}
else {
if (K.areDep(X0,faces[k].mirror.coords)) {
cout << "Common slice is mirror of face #" << k << endl;
}
else {
cerr << "Unidentified common slice, this is odd.." << endl;
exit(1);
}
}
}
else {
if (sx==0) {
cerr << "Strange, real spines intersect at infinity..." << endl;
exit(1);
}
else {
// cerr << "Real spines intersect inside, linear intersection (not implemented yet)" << endl;
if (K.areDep(faces[j].cspine,faces[k].cspine)) {
cout << "Same complex spine!" << endl;
exit(1);
}
gen te = Inn(faces[j].cspine,faces[k].cspine);
if (is_zero(te,&ct)) {
cout << "Orthogonal complex spines" << endl;
}
genparam = true;
}
}
}
}
else {
cout << "Real spines don't intersect" << endl;
genparam = true;
}
}
else {
cout << "Real spines don't intersect" << endl;
genparam = true;
}
}
if (genparam) {
gen vj, wj, vk, wk, vl, wl;
wj = faces[j].apexProjection;
vj = faces[j].apex.coords;
vj = Inn(wj,vj)*vj;
K.vectred(vj);
vj = Proj(vj,wj);
wk = faces[k].apexProjection;
vk = faces[k].apex.coords;
vk = Inn(wk,vk)*vk;
K.vectred(vk);
vk = Proj(vk,wk);
// need vl and wl, for third bisector in Giraud's theorem!
cout << "Will construct third bisector (Giraud)" << endl;
bool fd = false;
int u1=-1;
while (!fd && u1!=faces[j].sides.size()-1) {
u1++;
fd = K.areDep(faces[j].sides[u1].coords,faces[k].mirror.coords);
}
if (!fd) {
cerr << "Trouble findind third bisector (mirror)" << endl;
exit(1);
}
int u2=-1;
int v;
fd = false;
while (!fd && u2!=faces[j].sides.size()-1) {
u2++;
v=-1;
while (!fd && v!=faces[k].sides.size()-1) {
v++;
fd = K.areDep(faces[j].sides[u2].coords,faces[k].sides[v].coords);
}
}
if (!fd) {
cerr << "Trouble findind third bisector (side)" << endl;
exit(1);
}
// mirror and apex of third bisector
gen mi = faces[j].sides[u2].coords;
gen ap = BoxProd(faces[j].sides[u1].coords,faces[j].mirror.coords);
gen app = Proj(ap,mi);
wl = app;
vl = Inn(app,ap)*ap;
K.vectred(vl);
vl = Proj(vl,wl);
gen t1min, t1max, t2min, t2max, t3min, t3max;
for (int z=0; z<ridges[i].verts.size(); z++) {
gen t1v = -Inn(vj,vertices[ridges[i].verts[z]].coords)*K.inverse(Inn(wj,vertices[ridges[i].verts[z]].coords));
gen t2v = -Inn(vk,vertices[ridges[i].verts[z]].coords)*K.inverse(Inn(wk,vertices[ridges[i].verts[z]].coords));
gen t3v = -Inn(vl,vertices[ridges[i].verts[z]].coords)*K.inverse(Inn(wl,vertices[ridges[i].verts[z]].coords));
K.red(t1v);
K.red(t2v);
K.red(t3v);
t1v = K.convertToReal(t1v);
t2v = K.convertToReal(t2v);
t3v = K.convertToReal(t3v);
if (z==0) {
t1min = t1v;
t1max = t1v;
t2min = t2v;
t2max = t2v;
t3min = t3v;
t3max = t3v;
}
else {
int sg;
if (!K.checkSign(t1v-t1min,sg)) {
cerr << "Problem checking sign (t1min)" << endl;
}
else {
if (sg<0) {
t1min = t1v;
}
}
if (!K.checkSign(t1v-t1max,sg)) {
cerr << "Problem checking sign (t1max)" << endl;
}
else {
if (sg>0) {
t1max = t1v;
}
}
if (!K.checkSign(t2v-t2min,sg)) {
cerr << "Problem checking sign (t2min)" << endl;
}
else {
if (sg<0) {
t2min = t2v;
}
}
if (!K.checkSign(t2v-t2max,sg)) {
cerr << "Problem checking sign (t2max)" << endl;
}
else {
if (sg>0) {
t2max = t2v;
}
}
if (!K.checkSign(t3v-t3min,sg)) {
cerr << "Problem checking sign (t3min)" << endl;
}
else {
if (sg<0) {
t3min = t3v;
}
}
if (!K.checkSign(t3v-t3max,sg)) {
cerr << "Problem checking sign (t3max)" << endl;
}
else {
if (sg>0) {
t3max = t3v;
}
}
}
}
// take (vj+t1*wj)x(vk+t2*wk)
gen v0, v1, v2, v3;
v0 = BoxProd(vj,vk);
v1 = BoxProd(wj,vk);
v2 = BoxProd(vj,wk);
v3 = BoxProd(wj,wk);
gen vt = v0 + K.t1*v1 + K.t2*v2 + K.t1*K.t2*v3;
gen t3n = -Inn(vt,vl);
gen t3d = Inn(vt,wl);
for (int l=0; l<faces.size(); l++) {
gen eq = Inn(vt,faces[l].X0)*Inn(faces[l].X0,vt) - Inn(vt,faces[l].X1)*Inn(faces[l].X1,vt);
K.red(eq);
eq = K.convertToReal(eq);
K.red(eq);
if (verbose) {
cout << "eq=" << eq << endl;
}
if (operator_equal(eq,K.zeronumber,&ct)) {
cout << "Eq #" << l << " is 0..." << endl;
}
else {
gen eq1 = _derive(makesequence(eq,K.t1),&ct);
gen eq2 = _derive(makesequence(eq,K.t2),&ct);
/* // need to check if one of these is 0, in which case the third bisector intersects the ridge in (one or two) line(s)...
if ( operator_equal(eq1,K.zeronumber,&ct) ) {
cout << "Equation depends only on t2, need to handle this differently" << endl;
// need to know if eq is positive between t2min and t2max
int d2 = _degree(makesequence(eq,K.t2),&ct).val;
gen lc = _coeff(makesequence(eq,K.t2,d2),&ct);
cout << "Leading coeff: " << lc << endl;
int slc;
if (!K.checkSign(lc,slc)) {
cout << "Trouble checking sign of leading coefficient" << endl;
exit(1);
}
cout << "Sign of leading coeff: " << slc << endl;
if (d2==1) {
if (slc>0) {
gen temin = _subst(makesequence(eq,K.t2,t2min),&ct);
int smin;
if (!K.checkSign(temin,smin)) {
cout << "Trouble checking sign of value at t2min" << endl;
exit(1);
}
if (smin<0) {
}
}
}
gen temax = _subst(makesequence(eq,K.t2,t2max),&ct);
int smin, smax;
if (!K.checkSign(temin,smin) || !K.checkSign(temax,smax)) {
cout << "Trouble checking sign of leading coefficient" << endl;
exit(1);
}
cout << "Sgn of value at tmin: " << smin << endl;
cout << "Sgn of value at tmax: " << smax << endl;
// if degree 1 in t2min, solve the equation, compare with t2min + sign of leading coeff?
// if degree 2 in t2min, check if t2min
cout << "t1min:" << t1min << endl;
cout << "t1max:" << t1max << endl;
cout << "t2min:" << t2min << endl;
cout << "t2max:" << t2max << endl;
exit(1);
}
if ( operator_equal(eq2,K.zeronumber,&ct) ) {
cout << "Equation depends only on t1, need to handle this differently" << endl;
cout << "t1min:" << t1min << endl;
cout << "t1max:" << t1max << endl;
cout << "t2min:" << t2min << endl;
cout << "t2max:" << t2max << endl;
gen te = _solve(makesequence(eq,K.vars2d[1]),&ct);
cout << "te=" << te << endl;
exit(1);
}
*/
// cout << "Realminpol: " << K.realminpol << endl;
vecteur eqs_rur;
eqs_rur.push_back(eq1);
eqs_rur.push_back(eq2);
eqs_rur.push_back(K.realminpol);
if (verbose) {
cout << "K.vars2d: " << K.vars2d << endl;
cout << "eqs_rur: " << eqs_rur << endl;
}
// cout << "Start rur" << endl;
gen gb1 = _gbasis(makesequence(eqs_rur,K.vars2d,change_subtype(_RUR_REVLEX,_INT_GROEBNER)),&ct);
// cout << "Done rur" << endl;
if (gb1[0]==-4) {
// cout << "gb1=" << gb1 << endl;
gen varprov = lidnt(gb1[2])[0];
// cout << "varprov=" << varprov << endl;
gb1 = _subst(makesequence(gb1,varprov,s__IDNT_e),&ct);
// cout << "gb1=" << gb1 << endl;
vecteur valpars;
if (!K.safeSift(gb1,valpars)) {
cerr << "Problem sifting RUR values... (crit pts)" << endl;
exit(1);
}
else {
cout << "For eq#" << l << ", found " << valpars.size() << " critical point(s).. " << endl;
if (verbose) {
cout << "gb1: " << gb1 << endl;
cout << "valpars: " << valpars << endl;
}
// cout << "valpars: " << valpars << endl;
for (int u = 0; u<valpars.size(); u++) {
// cout << "Checking crit pt #" << u << ".. ";
// cout << "valpars[u]=" << valpars[u] << endl;
// cout << "Horner" << endl;
gen t1vi = _horner(makesequence(gb1[5],valpars[u],s__IDNT_e),&ct)/_horner(makesequence(gb1[3],valpars[u],s__IDNT_e),&ct);
gen t2vi = _horner(makesequence(gb1[6],valpars[u],s__IDNT_e),&ct)/_horner(makesequence(gb1[3],valpars[u],s__IDNT_e),&ct);
// cout << "Done with horner" << endl;
int stest;
if (!checkt1val(gb1,valpars[u],t1min,stest)) {
cerr << "Trouble comparing with t1min" << endl;
exit(1);
}
if (stest<0) {
cout << "outside (t1<t1min)" << endl;
}
else {
if (!checkt1val(gb1,valpars[u],t1max,stest)) {
cerr << "Trouble comparing with t1max" << endl;
exit(1);
}
if (stest>0) {
cout << "outside (t1>t1max)" << endl;
}
else {
if (!checkt2val(gb1,valpars[u],t2min,stest)) {
cerr << "Trouble comparing with t2min" << endl;
exit(1);
}
if (stest<0) {
cout << "outside (t2<t2min)" << endl;
}
else {
if (!checkt2val(gb1,valpars[u],t2max,stest)) {
cerr << "Trouble comparing with t2max" << endl;
exit(1);
}
if (stest>0) {
cout << "outside (t2>t2max)" << endl;
}
else {
if (!checkt3val(gb1,valpars[u],t3min,vl,wl,vt,stest)) {
cerr << "Trouble comparing with t3min" << endl;
exit(1);
}
if (stest<0) {
cout << "outside (t3<t3min)" << endl;
}
else {
if (!checkt3val(gb1,valpars[u],t3max,vl,wl,vt,stest)) {
cerr << "Trouble comparing with t3max" << endl;
exit(1);
}
if (stest>0) {
cout << "outside (t3>t3max)" << endl;
}
else {
if (!checkEqSign(gb1,valpars[u],eq,stest)) {
cerr << "Trouble checking sign of equation" << endl;
exit(1);
}
if (eq>0) {
cerr << "Equation is positive inside the G-polygon..." << endl;
cerr << "There seems to be an isolated component!!!!!!!" << endl;
exit(1);
}
else {
cout << "CRITICAL POINT IS INSIDE, but the equation is negative there!" << endl;
}
}
}
}
}
}
}
}
}
}
else {
if(! operator_equal(normal(gb1[0]-K.onenumber,&ct),K.zeronumber,&ct)) {// otherwise, groebner basis contains 1, no solution
cout << "Non isolated critical points? the system is not 0-dim" << endl;
// could either check if eqn for geodesics give (multiple) factors, or
// use factorization over a number field, or factorization by hand...
// For now, I choose the last option.
bool needmore = false;
gen co = _coeff(makesequence(eq,K.t2),&ct);
int d2 = _degree(co,&ct).val;
// eq may have lower degree in t2!!
if (d2==2) {
gen co1 = _coeff(makesequence(eq,K.t1),&ct);
int d1 = _degree(co1,&ct).val;
if (_degree(_coeff(makesequence(co[0],K.t1),&ct),&ct).val==d1
&& _degree(_coeff(makesequence(co[1],K.t1),&ct),&ct).val==d1
&& _degree(_coeff(makesequence(co[2],K.t1),&ct),&ct).val==d1 ) {
cout << "a,b,c all have degree " << d1 << endl;
}
else {
cerr << "Non-isolated critical point, unexpected behaviour" << endl;
exit(1);
}
// some of these may be 0, in which case I'm quite sure what follows is wrong!
// CHECK
gen a = _coeff(makesequence(co[0],K.t1,d1),&ct);
gen b = _coeff(makesequence(co[1],K.t1,d1),&ct);
gen c = _coeff(makesequence(co[2],K.t1,d1),&ct);
gen te1,te2;
te1 = _rem(makesequence(a*co[1]-b*co[0],K.realminpol,s__IDNT_e),&ct);
if (operator_equal(te1,K.zeronumber,&ct)) {
te2 = _rem(makesequence(a*co[2]-c*co[0],K.realminpol,s__IDNT_e),&ct);
if (operator_equal(te2,K.zeronumber,&ct)) {
gen discr = _rem(makesequence(b*b-4*a*c,K.realminpol,s__IDNT_e),&ct);
if (operator_equal(discr,K.zeronumber,&ct)) {
cout << "There is a square factor of the form (t2-r)^2" << endl;
gen r = -b*K.inverse(2*a);
K.red(r);
cout << " r = " << r << endl;
int sg;
gen zz = r-t2min;
K.red(zz);
if (K.checkSign(zz,sg)){
if (sg>0) {
cout << "r>t2min" << endl;
zz = r-t2max;
K.red(zz);
if (K.checkSign(zz,sg)){
if (sg<0) {
cout << "r<t2max" << endl;
cout << "Horizontal line crosses the interior of the ridge!" << endl;
exit(1);
}
}
else {
cerr << "Trouble comparing r with t2max" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing r with t2min" << endl;
exit(1);
}
// need to check sign of co[0], check it is positive in [t1min,t1max]!
gen yo1 = _subst(makesequence(co[0],K.t1,t1min),&ct);
K.red(yo1);
if (K.checkSign(yo1,sg)) {
if (sg>0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
cout << "g(t1)==eq/(t2-r)^2 is <=0 at t1min" << endl;
gen yo2 = _subst(makesequence(co[0],K.t1,t1max),&ct);
K.red(yo2);
// cout << "yo2=" << yo2 << endl;
if (K.checkSign(yo2,sg)) {
if (sg>0) {
cout << "g(t1)==eq/(t2-r)^2 is <=0 at t1max" << endl;
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
// co[0] negative at enpoints, if degree two then still something to do!
cout << "co[0] is neg at endpoints, but need to check more" << endl;
cout << "co[0]=" << co[0] << endl;
gen de = _degree(makesequence(co[0],K.t1),&ct);
cout << "degree: " << de << endl;
if (operator_equal(de,K.twonumber,&ct)) {
gen aa = _coeff(makesequence(co[0],K.t1,2),&ct);
K.red(aa);
if (K.checkSign(aa,sg)) {
if (sg<0) {
cout << "coeff of t1^2 is <0, will check tv = t1 of vertex of parabola" << endl;
gen tmax = _coeff(makesequence(co[0],K.t1,1),&ct)*K.inverse(2*_coeff(makesequence(co[0],K.t1,2),&ct));
K.red(tmax);
gen zzz = tmax-t1min;
K.red(zzz);
if (K.checkSign(zzz,sg)) {
if (sg>0) {
cout << "tv>t1min" << endl;
zzz = tmax-t1max;
K.red(zzz);
if (K.checkSign(zzz,sg)) {
if (sg<0) {
cout << "tv<t1max" << endl;
gen val = _subst(makesequence(co[0],K.t1,tmax),&ct);
cout << "val=" << val << endl;
K.red(val);
if (K.checkSign(val,sg)) {
if (sg>0) {
cout << "Value at tv is > 0!!!" << endl;
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
else {
cout << "Value at tv is <= 0, OK." << endl;
}
}
else {
cerr << "Trouble checking sign at vertex of parabola." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1max." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1min." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff." << endl;
exit(1);
}
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1min" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1min" << endl;
exit(1);
}
}
else {
needmore = true;
}
}
else {
needmore = true;
}
}
else {
needmore = true;
}
if (needmore) {
// start over with other variable!
bool needevenmore = false;
gen co = _coeff(makesequence(eq,K.t1),&ct);
int d1 = _degree(co,&ct).val;
if (d1==2) {
gen a = _coeff(makesequence(co[0],K.t2,2),&ct);
gen b = _coeff(makesequence(co[1],K.t2,2),&ct);
gen c = _coeff(makesequence(co[2],K.t2,2),&ct);
gen te1,te2;
te1 = _rem(makesequence(a*co[1]-b*co[0],K.realminpol,s__IDNT_e),&ct);
if (operator_equal(te1,K.zeronumber,&ct)) {
te2 = _rem(makesequence(a*co[2]-c*co[0],K.realminpol,s__IDNT_e),&ct);
if (operator_equal(te2,K.zeronumber,&ct)) {
gen discr = _rem(makesequence(b*b-4*a*c,K.realminpol,s__IDNT_e),&ct);
if (operator_equal(discr,K.zeronumber,&ct)) {
cout << "There is a square factor of the form (t1-r)^2" << endl;
gen r = -b*K.inverse(2*a);
K.red(r);
cout << " r = " << r << endl;
int sg;
gen zzzz = r-t1min;
K.red(zzzz);
if (K.checkSign(zzzz,sg)){
if (sg>0) {
zzzz = r-t1max;
K.red(zzzz);
if (K.checkSign(zzzz,sg)){
if (sg<0) {
cout << "Vertical line crosses the interior of the ridge!" << endl;
exit(1);
}
}
else {
cerr << "Trouble comparing r with t1max" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing r with t1min" << endl;
exit(1);
}
// need to check sign of co[0], check it is positive in [t1min,t1max]!
gen yo1 = _subst(makesequence(co[0],K.t2,t2min),&ct);
K.red(yo1);
if (K.checkSign(yo1,sg)) {
if (sg>0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
gen yo2 = _subst(makesequence(co[0],K.t2,t2max),&ct);
K.red(yo2);
if (K.checkSign(yo2,sg)) {
if (sg>0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
// co[0] negative at enpoints, if degree two then still something to do!
gen de = _degree(makesequence(co[0],K.t2),&ct);
if (operator_equal(de,K.twonumber,&ct)) {
gen aa = _coeff(makesequence(co[0],K.t2,2),&ct);
K.red(aa);
if (K.checkSign(aa,sg)) {
if (sg<0) {
gen tmax = _coeff(makesequence(co[0],K.t2,1),&ct)*K.inverse(2*_coeff(makesequence(co[0],K.t2,2),&ct));
K.red(tmax);
gen zzzzz = tmax-t2min;
K.red(zzzzz);
if (K.checkSign(tmax-t2min,sg)) {
if (sg>0) {
zzzzz = tmax-t2max;
K.red(zzzzz);
// cout << "tmax-t2max=" << zzzzz << endl;
if (K.checkSign(tmax-t2max,sg)) {
if (sg<0) {
gen val = _subst(makesequence(co[0],K.t2,tmax),&ct);
K.red(val);
cout << "Val at vert: " << val << endl;
if (K.checkSign(val,sg)) {
if (sg>0) {
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
}
else {
cerr << "Trouble checking sign at vertex of parabola." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1max." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1min." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff." << endl;
exit(1);
}
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1min" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1min" << endl;
exit(1);
}
}
else {
needevenmore = true;
}
}
else {
needevenmore = true;
}
}
else {
needevenmore = true;
}
if (needevenmore) {
cerr << "Factors (t1-r)^2 or (t2-r)^2 did not explain not 0-dim" << endl;
cerr << "It may help to factor over number field, or use t3?" << endl;
exit(1);
}
}
else {
if (d1==1) {
cout << "Equation has degree 1 in t1" << endl;
exit(1);
}
else {
cout << "Equation does not contain t1!" << endl;
exit(1);
}
}
}
}
else { // d2!=2
if (d2==1) {
cout << "Equation has degree 1 in t2" << endl;
int da = _degree(makesequence(co[0],K.t1),&ct).val;
int db = _degree(makesequence(co[1],K.t1),&ct).val;
cout << "co=" << co << endl;
cout << "da=" << da << endl;
cout << "db=" << db << endl;
if (da==db) {
gen a = _coeff(makesequence(co[0],K.t1,da),&ct);
gen b = _coeff(makesequence(co[1],K.t1,da),&ct);
// check degrees??
cout << "a=" << a << endl;
cout << "b=" << b << endl;
gen te1,te2;
te1 = _rem(makesequence(a*co[1]-b*co[0],K.realminpol,s__IDNT_e),&ct);
if (operator_equal(te1,K.zeronumber,&ct)) {
cout << "There is a single (t2-r) factor" << endl;
gen r = -b*K.inverse(a);
K.red(r);
// equation looks like (t2-r)*p(t1), need to:
// * check sign of p(t1) in the polygon
// * compare r with t2min and t2max
cout << " r = " << r << endl;
int sg;
gen zzzz = r-t2min;
K.red(zzzz);
if (K.checkSign(zzzz,sg)){
// could check sign of r-t2min
if (sg>0) {
// r>t2min
zzzz = r-t2max;
K.red(zzzz);
if (K.checkSign(zzzz,sg)){
// could check sign of r-t2max
if (sg<0) {
cout << "Vertical line crosses the interior of the ridge!" << endl;
exit(1);
}
else {
// r>=t2max, so the t2-r factor is negative
// need to check that p(t1)>=0 on [t1min,t1max]
// CHECKING p>0
gen yo1 = _subst(makesequence(co[0],K.t1,t1min),&ct);
K.red(yo1);
if (K.checkSign(yo1,sg)) {
if (sg<0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
gen yo2 = _subst(makesequence(co[0],K.t1,t1max),&ct);
K.red(yo2);
if (K.checkSign(yo2,sg)) {
if (sg<0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
// co[0] positive at enpoints, if degree two then still something to do!
gen de = _degree(makesequence(co[0],K.t1),&ct);
if (operator_equal(de,K.twonumber,&ct)) {
// otherwise nothing to do!
gen aa = _coeff(makesequence(co[0],K.t1,2),&ct);
K.red(aa);
if (K.checkSign(aa,sg)) {
if (sg>0) {
gen tmax = _coeff(makesequence(co[0],K.t1,1),&ct)*K.inverse(2*_coeff(makesequence(co[0],K.t1,2),&ct));
K.red(tmax);
gen zzzzz = tmax-t1min;
K.red(zzzzz);
if (K.checkSign(tmax-t1min,sg)) {
if (sg>0) {
zzzzz = tmax-t1max;
K.red(zzzzz);
if (K.checkSign(tmax-t1max,sg)) {
if (sg<0) { // tmax is in the interval [t1min,t1max]
gen val = _subst(makesequence(co[0],K.t1,tmax),&ct);
K.red(val);
cout << "Val at vert: " << val << endl;
if (K.checkSign(val,sg)) {
if (sg<0) {
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
else {
if (sg==0) {
cout << "Equation cuts face in vertical line (tangency)!" << endl;
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign at vertex of parabola." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1max." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1min." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff." << endl;
exit(1);
}
}
}
}
else {
cerr << "Trouble checking sign at t1max" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign at t1min" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing r with t2max" << endl;
exit(1);
}
}
else {
// r<=t2min, so the t2-r factor is positive
// need to check that p(t1)<=0 on [t1min,t1max]
// CHECKING SIGN OF p(t1)
gen yo1 = _subst(makesequence(co[0],K.t1,t1min),&ct);
K.red(yo1);
if (K.checkSign(yo1,sg)) {
if (sg>0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
gen yo2 = _subst(makesequence(co[0],K.t1,t1max),&ct);
K.red(yo2);
// cout << "yo2=" << yo2 << endl;
if (K.checkSign(yo2,sg)) {
if (sg>0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
// co[0] negative at enpoints, if degree two then still something to do!
gen de = _degree(makesequence(co[0],K.t1),&ct);
if (operator_equal(de,K.twonumber,&ct)) {
gen aa = _coeff(makesequence(co[0],K.t1,2),&ct);
K.red(aa);
if (K.checkSign(aa,sg)) {
if (sg<0) {
gen tmax = _coeff(makesequence(co[0],K.t1,1),&ct)*K.inverse(2*_coeff(makesequence(co[0],K.t1,2),&ct));
K.red(tmax);
gen zzzzz = tmax-t1min;
K.red(zzzzz);
if (K.checkSign(tmax-t1min,sg)) {
if (sg>0) {
zzzzz = tmax-t1max;
K.red(zzzzz);
// cout << "tmax-t2max=" << zzzzz << endl;
if (K.checkSign(tmax-t1max,sg)) {
if (sg<0) { // tmax is in the interval [t1min,t1max]
gen val = _subst(makesequence(co[0],K.t1,tmax),&ct);
K.red(val);
cout << "Val at vert: " << val << endl;
if (K.checkSign(val,sg)) {
if (sg>0) {
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
else {
if (sg==0) {
cout << "Equation cuts face in vertical line (tangency)!" << endl;
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign at vertex of parabola." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1max." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1min." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff." << endl;
exit(1);
}
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1max" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1min" << endl;
exit(1);
}
// done with checking p(t1)<0
}
}
else {
cerr << "Trouble comparing r with t2min" << endl;
exit(1);
}
}
else {
cerr << "Unexpected case, ask Martin to fix this (coeffs are not multiples of each other)!" << endl;
cerr << " (degree in t2 is 1, but no t2=r factor)" << endl;
exit(1);
}
}
else {
cout << "Degrees are not the same" << endl;
cout << "co[1]=" << co[1] << endl;
if (is_zero(co[1],&ct)) {
cout << "Term constant in t2 is 0" << endl;
gen r = K.zeronumber;
// equation looks like t2*p(t1), need to:
// * check sign of p(t1) in the polygon
// * compare 0 with t2min and t2max
cout << " r = 0 " << endl;
int sg;
gen zzzz = r-t2min;
K.red(zzzz);
if (K.checkSign(zzzz,sg)){
if (sg>0) {
zzzz = r-t2max;
K.red(zzzz);
if (K.checkSign(zzzz,sg)){
if (sg<0) {
cout << "Vertical line crosses the interior of the ridge!" << endl;
exit(1);
}
else {
// r>=t2max, so the t2-r factor is negative
// need to check that p(t1)>=0 on [t1min,t1max]
}
}
else {
cerr << "Trouble comparing r with t1max" << endl;
exit(1);
}
}
else {
// r<=t2min, so the t2-r factor is positive
// need to check that p(t1)<=0 on [t1min,t1max]
}
}
else {
cerr << "Trouble comparing r with t1min" << endl;
exit(1);
}
}
else {
cerr << "Ask Martin to fix this!" << endl;
cerr << " (degree in t2 is 1, but no t2=r factor)" << endl;
exit(1);
}
}
}
else {
cout << "Equation does not contain t2!" << endl;
// equation looks like p(t1), need to check sign of p(t1) in [t1min,t1max]
int sg;
gen yo1 = _subst(makesequence(co[0],K.t1,t1min),&ct);
K.red(yo1);
if (K.checkSign(yo1,sg)) {
if (sg>0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
gen yo2 = _subst(makesequence(co[0],K.t1,t1max),&ct);
K.red(yo2);
if (K.checkSign(yo2,sg)) {
if (sg>0) {
cerr << "Equation seems to cut into the ridge, have you checked edges?" << endl;
exit(1);
}
else {
// co[0] negative at enpoints, if degree two then still something to do!
gen de = _degree(makesequence(co[0],K.t1),&ct);
if (operator_equal(de,K.twonumber,&ct)) {
gen aa = _coeff(makesequence(co[0],K.t1,2),&ct);
K.red(aa);
if (K.checkSign(aa,sg)) {
if (sg<0) {
gen tmax = _coeff(makesequence(co[0],K.t1,1),&ct)*K.inverse(2*_coeff(makesequence(co[0],K.t1,2),&ct));
K.red(tmax);
gen zzzzz = tmax-t1min;
K.red(zzzzz);
if (K.checkSign(tmax-t1min,sg)) {
if (sg>0) {
zzzzz = tmax-t1max;
K.red(zzzzz);
if (K.checkSign(tmax-t1max,sg)) {
if (sg<0) { // tmax is in the interval [t1min,t1max]
gen val = _subst(makesequence(co[0],K.t1,tmax),&ct);
K.red(val);
cout << "Val at vert: " << val << endl;
if (K.checkSign(val,sg)) {
if (sg>0) {
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
else {
if (sg==0) {
cout << "Equation cuts face in vertical line (tangency)!" << endl;
cout << "Polytope does not seem embedded, sorry!" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign at vertex of parabola." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1max." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble comparing t-vertex with t1min." << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff." << endl;
exit(1);
}
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1max" << endl;
exit(1);
}
}
}
else {
cerr << "Trouble checking sign of coeff at t1min" << endl;
exit(1);
}
// done checking sign of p(t1)
}
}
}
}
}
}
}
else {
// use V0, W0, Z0
cout << "For this ridge there is nothing to do, it is enough to check the 1-skeleton!" << endl;
}
}
void Polytope::drawRidgePic(int i) {
int j = ridges[i].faceindices[0];
int k = ridges[i].faceindices[1];
cout << "Trying to draw pic of ridge on faces #" << j << " and " << k << endl;
cout << " (I will only do it provided this ridge is a complex disk)" << endl;
bool genparam;
gen X0 = BoxProd(faces[j].cspine,faces[k].cspine);
gen V0, W0, Z0; // Orthogonal (but not orthonormal) basis, with V0, W0 spanning common slice
if (operator_equal(X0,K.zerovector,&ct)) {
// cospinal
genparam = false;
gen Xte = BoxProd(faces[j].mirror.coords,faces[k].mirror.coords);
cout << "Same mirror?" << endl;
cout << "Xte=" << Xte << endl;
cout << " " << K.evali(Xte) << endl;
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Same mirror, this gives the common slice" << endl;
V0 = faces[j].apexProjection;
W0 = Proj(faces[j].bottomface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
Xte = BoxProd(faces[j].mirror.coords,faces[k].apex.coords);
cout << "Mirror with top?" << endl;
cout << "Xte=" << Xte << endl;
cout << " " << K.evali(Xte) << endl;
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Mirror of face#" << j << " is same as top face of #" << k << endl;
cout << " this gives the common slice" << endl;
V0 = faces[j].apexProjection;
W0 = Proj(faces[j].bottomface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
Xte = BoxProd(faces[k].mirror.coords,faces[j].apex.coords);
cout << "Top with mirror?" << endl;
cout << "Xte=" << Xte << endl;
cout << " " << K.evali(Xte) << endl;
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Mirror of face#" << k << " is same as top face of #" << j << endl;
cout << " this gives the common slice" << endl;
V0 = faces[k].apexProjection;
W0 = Proj(faces[k].bottomface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
Xte = BoxProd(faces[j].apex.coords,faces[k].apex.coords);
if (operator_equal(Xte,K.zerovector,&ct)) {
cout << "Top of face#" << k << " is same as top face of #" << j << endl;
cout << " this gives the common slice" << endl;
V0 = BoxProd(faces[j].cspine,faces[j].apex.coords);
W0 = Proj(faces[j].topface[0].coords,V0);
Z0 = BoxProd(V0,W0); // not clear if we need this
}
else {
cerr << "There is probably no common slice, will need to check this.." << endl;
cout << "There is probably no common slice, will need to check this.." << endl;
gen vj, wj, vk, wk;
wj = faces[j].apexProjection;
vj = faces[j].apex.coords;
vj = Inn(wj,vj)*vj;
K.vectred(vj);
vj = Proj(vj,wj);
gen vt = vj + K.t1*wj;
// take vj+t*wj, and find t-values for this to be on face k
//
gen eq = Inn(vt,faces[k].X0)*Inn(faces[k].X0,vt) - Inn(vt,faces[k].X1)*Inn(faces[k].X1,vt);
K.red(eq);
eq = K.convertToReal(eq);
K.red(eq);
cout << "Equation to solve: " << eq << endl;
gen eqro = eval(_subst(makesequence(eq,s__IDNT_e,K.realgenasrootof),&ct),1,&ct);
cout << "eqro:" << eqro << endl;
cout << "realgenasrootof: " << K.realgenasrootof << endl;
cout << " " << _evalf(K.realgenasrootof,&ct) << endl;
gen fa = _factors(makesequence(eqro,K.realgenasrootof),&ct);
for (int l=0; 2*l<(*fa._VECTptr).size(); l++) {
cout << "fa[" << (2*l) << "]=" << fa[2*l] << endl;
int deg = _degree(makesequence(fa[2*l],K.t1),&ct).val;
if (deg>1) {
cout << "Intersection of the real spines is not defined over the ambient number field" << endl;
cout << " (more programming to do!)" << endl;
exit(1);
}
else {
if (deg>0) {
gen te = normal(-_coeff(makesequence(fa[2*l],K.t1,0),&ct)/_coeff(makesequence(fa[2*l],K.t1,1),&ct),&ct);
if (verbose) {
cout << "te=" << te << endl;
cout << " (" << _evalf(te,&ct) << ")" << endl;
}
}
}
}
gen expr = SqNorm(vt);
K.red(expr);
expr = K.convertToReal(expr);
K.red(expr);
cout << "Then need to check sign of: " << expr << endl;
}
}
}
}
}
else {
// complex spines intersect in projective space, need to check if they intersect on the real spines
if (isOnPrism(X0,faces[j])) {
cout << "Extended real spine of face #" << j << " intersects extor #" << k << endl;
if (isOnPrism(X0,faces[k])) {
cout << "Extended real spine of face #" << k << " intersects extor #" << j << endl;
cout << "Real spines intersect... "; //either cotranchal, or linear?
int sx;
if (!K.checkSign(SqNorm(X0),sx)) {
cerr << "Trouble computing sign of square norm (in checkRidge)" << endl;
exit(1);
}
else {
if (sx>0) {
cout << "Cotranchal pair" << endl;
gen Y1 = faces[j].apexProjection;
Y1 = Inn(X0,Y1)*Y1;
K.red(Y1);
Y1 = Proj(Y1,X0);
gen Y2 = faces[k].apexProjection;
Y2 = Inn(X0,Y2)*Y2;
K.red(Y2);
Y2 = Proj(Y2,X0);
gen tee = Inn(Y1,faces[j].X0)*Inn(faces[j].X0,Y1)-Inn(Y1,faces[j].X1)*Inn(faces[j].X1,Y1);
K.red(tee);
tee = Inn(Y2,faces[k].X0)*Inn(faces[k].X0,Y2)-Inn(Y2,faces[k].X1)*Inn(faces[k].X1,Y2);
K.red(tee);
gen tt = (Inn(Y1,Y2)+Inn(Y2,Y1))/2;
gen te = SqNorm(Y1)*SqNorm(Y2) - tt*tt;
K.red(te);
te = K.convertToReal(te);
int sgn;
if (!K.checkSign(te,sgn)) {
cerr << "Trouble checking sign (is intersection is slice only)" << endl;
exit(1);
}
else {
if (sgn<0) {
cerr << "Intersection is not just the common slice!?" << endl;
// exit(1);
genparam = false; // THIS IS NOT WHAT WE WANT, ONLY OK IF WE DON'T NEED TO CHECK EXTRA COMPONENT...
}
else {
cout << "intersection is slice only!" << endl;
genparam = false;
}
}
V0 = X0;
if (K.areDep(X0,faces[j].apex.coords)) {
cout << "Common slice is top face of face #" << j << endl;
W0 = Proj(faces[j].topface[0].coords,V0);
}
else {
if (K.areDep(X0,faces[j].mirror.coords)) {
cout << "Common slice is mirror of face #" << j << endl;
W0 = Proj(faces[j].bottomface[0].coords,V0);
}
else {
cerr << "Unidentified common slice, this is odd.." << endl;
exit(1);
}
}
Z0 = BoxProd(V0,W0); // not clear if we need this
if (K.areDep(X0,faces[k].apex.coords)) {
cout << "Common slice is top face of face #" << k << endl;
}
else {
if (K.areDep(X0,faces[k].mirror.coords)) {
cout << "Common slice is mirror of face #" << k << endl;
}
else {
cerr << "Unidentified common slice, this is odd.." << endl;
exit(1);
}
}
}
else {
if (sx==0) {
cerr << "Strange, real spines intersect at infinity..." << endl;
exit(1);
}
else {
// cerr << "Real spines intersect inside, linear intersection (not implemented yet)" << endl;
// This is actually OK, the Giraud parametrization still works!
if (K.areDep(faces[j].cspine,faces[k].cspine)) {
cout << "Same complex spine!" << endl;
}
gen te = Inn(faces[j].cspine,faces[k].cspine);
if (is_zero(te,&ct)) {
cout << "Orthogonal complex spines" << endl;
}
genparam = true;
// exit(1);
}
}
}
}
else {
cerr << "Real spines don't intersect" << endl;
genparam = true;
}
}
else {
cerr << "Real spines don't intersect" << endl;
genparam = true;
}
}
if (genparam) {
cout << "This is a generic ridge, picture not implemented yet" << endl;
}
else {
ofstream file;
string jc = static_cast<ostringstream*>( &(ostringstream() << j) )->str();
string kc = static_cast<ostringstream*>( &(ostringstream() << k) )->str();
string filename = "pics/pic-ridge"+K.tag+"_"+jc+"-"+kc+".asy";
file.open(filename.c_str());
file << "import graph;" << endl;
file << "size(7.5cm,0);" << endl;
file << "draw(circle((0,0),1),red);" << endl;
vector<int> inds = findFaces(V0);
gen V0n = K.evali(V0);
gen W0n = K.evali(W0);
gen Hn = K.evali(H);
gen X1 = K.evali(vertices[ridges[i].verts[0]].coords);
gen X2 = K.evali(vertices[ridges[i].verts[3]].coords);
X1 = X1/sqrt(-re(conj(X1,&ct)*Hn*X1,&ct),&ct);
X2 = X2/sqrt(-re(conj(X2,&ct)*Hn*X2,&ct),&ct);
gen yo = conj(X2,&ct)*Hn*X1;
X2 = (-yo/abs(yo,&ct))*X2;
gen MP = X1+X2;
gen mpz = (-conj(MP,&ct)*Hn*W0n)/(conj(MP,&ct)*Hn*V0n);
W0n = (conj(mpz,&ct)/abs(mpz,&ct))*W0n;
V0n = V0n/sqrt(-re(conj(V0n,&ct)*Hn*V0n,&ct),&ct);
W0n = W0n/sqrt(re(conj(W0n,&ct)*Hn*W0n,&ct),&ct);
gen mpz2 = (-conj(MP,&ct)*Hn*W0n)/(conj(MP,&ct)*Hn*V0n);
for (int u=0; u<faces.size(); u++) {
if (u!=j && u!=k) {
cout << "Working on face #" << u << endl;
gen X0i = K.evali(faces[u].X0);
gen X1i = K.evali(faces[u].X1);
gen a = conj(X0i,&ct)*Hn*W0n;
gen b = conj(X0i,&ct)*Hn*V0n;
gen c = conj(X1i,&ct)*Hn*W0n;
gen d = conj(X1i,&ct)*Hn*V0n;
gen den = a*conj(a,&ct)-c*conj(c,&ct);
den = re(den,&ct);
if (is_greater(K.zeronumber,_left(den,&ct),&ct) && is_greater(_right(den,&ct),K.zeronumber,&ct)) {
cerr << "Interval for denominator contains 0, maybe a line?" << endl;
}
else {
gen ctr = (conj(c,&ct)*d-conj(a,&ct)*b)/den;
cout << "ctr=" << ctr << endl;
gen radsq = re( ctr*conj(ctr,&ct) , &ct ) - re( b*conj(b,&ct)-d*conj(d,&ct) , &ct )/den;
if (is_greater(_left(radsq,&ct),K.zeronumber,&ct)) {
gen rad = sqrt(radsq,&ct);
cout << "rad = " << rad << endl;
if (is_greater(1000,rad,&ct)) {
file << "draw(circle(("<<_left(re(ctr,&ct),&ct)<<","<<_left(im(ctr,&ct),&ct)<<"),"<<_left(rad,&ct)<<"),black);" << endl;
gen tee = ctr*(1-rad/abs(ctr,&ct));
file << "label(\"$" << u << "$\",(" << re(tee,&ct) << "," << im(tee,&ct) << "),black+fontsize(8));" << endl;
}
}
else {
if (is_greater(K.zeronumber,_right(radsq,&ct),&ct)) {
cout << "No intersection, radius of circle is negative" << endl;
}
else {
cout << "Doubtful intersection, the interval for radius contains 0" << endl;
cout << "Will simply draw nothing..." << endl;
}
}
}
}
}
// then draw the geodesic polygon through vertices...
cout << "Drawing polygon" << endl;
vector<gen> verts_num;
gen ii = gen("exp(pi*i/2)",&ct);
gen fa = gen("180/pi",&ct);
for (int u=0; u<ridges[i].verts.size(); u++) {
gen X = K.evali(vertices[ridges[i].verts[u]].coords);
gen rat = -(conj(X,&ct)*Hn*W0n)/(conj(X,&ct)*Hn*V0n);
verts_num.push_back(_left(re(rat,&ct),&ct)+ii*_left(im(rat,&ct),&ct));
}
int si = verts_num.size();
file << "path pol = ";
for (int u=0; u<si; u++) {
gen alp = verts_num[u];
gen bet = verts_num[(u+1)%si];
gen den = conj(alp,&ct)*bet - alp*conj(bet,&ct);
gen ctr = (alp*(alp*conj(alp,&ct)-bet*conj(bet,&ct)) + (bet-alp)*(1+alp*conj(alp,&ct)))/den;
gen rad = sqrt(ctr*conj(ctr,&ct)-1,&ct);
gen u1 = alp-ctr;
gen u3 = bet-ctr;
gen th1 = arg(u1,&ct)*fa;
gen th2 = arg(u3,&ct)*fa;
if (is_greater(th2,th1,&ct)) {
if (is_greater(th2-th1,180,&ct)) {
th2 = th2-360;
}
}
else {
if (is_greater(th1-th2,180,&ct)) {
th1 = th1-360;
}
}
file << "arc(("<<re(ctr,&ct)<<","<<im(ctr,&ct)<<"),"<<rad<<","<<th1<<","<<th2<<")--" << endl;
}
file << "cycle;" << endl;
file << "filldraw(pol,gray);" << endl;
file << "limits((-1.1,-1.1),(1.1,1.1),Crop);";
file.close();
}
}
bool Polytope::checkt1val(gen rur, gen par, gen t1v, int &res) {
gen par_refined;
if (checkt1valAttempt(rur,par,t1v,res)) {
return true;
}
else {
if (checkEqualt1val(rur,par,t1v)) {
res = 0;
return true;
}
else {
int savend = K.nd;
bool done = false;
while (K.nd<K.ndmax && !done) {
// compute par_refined?
gen sols =_realroot(makesequence(rur[2],K.prec),&ct);
int count = 0;
int ksave;
for (int k=0; k<(*sols._VECTptr).size(); k++) {
gen rt = convert_interval(sols[k][0],K.nd,&ct);
/* gen rt;
if (sols[k][0].type==8) {
rt = convert_interval(sols[k][0],K.nd,&ct);
}
else {
rt = sols[k][0];
}*/
// cout << "par=" << par << endl;
gen Jt = _intersect(makesequence(rt,par),&ct);
// cout << "Jt.type==3? " << (Jt.type==3) << endl;
// gen Jt = _intersect(makesequence(sols[k][0],par),&ct);
// changed nov 21, 2019 because for some trivial equations, realroots are not intervals...
if (Jt.type==3) {
par_refined = rt;
count++;
ksave = k;
}
}
if (count!=1) {
cout << "Could not identify par from rur (count=" << count << ")" << endl;
return false;
}
// else {
// par_refined = sols[ksave][0];
// }
// cout << "par_refined=" << par_refined << endl;
done = checkt1valAttempt(rur, par_refined, t1v, res);
if (!done) {
K.increasePrecision();
}
}
K.nd = savend;
K.lowerPrecision();
return done;
}
}
}
bool Polytope::checkt1valAttempt(gen rur, gen par, gen t1v, int &res) {
gen t1vi = K.evali(t1v);
gen t1_from_rur = _horner(makesequence(rur[5],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
t1_from_rur = convert_interval(t1_from_rur,K.nd,&ct);
// added next line to fix m6-1%3...
// t1_from_rur = convert_interval(t1_from_rur,K.nd,&ct);
// cout << "t1vi=" << t1vi << endl;
// cout << "t1_from_rur=" << t1_from_rur << endl;
// in some case the solutions are integers, then the result is not an interval...
if (operator_equal(t1_from_rur,K.zeronumber,&ct)) {
t1_from_rur = convert_interval(K.onenumber,K.nd,&ct)-K.onenumber;
}
if (is_greater(_left(t1vi,&ct),_right(t1_from_rur,&ct),&ct)) {
res = -1;
return true;
}
else {
if (is_greater(_left(t1_from_rur,&ct),_right(t1vi,&ct),&ct)) {
res = 1;
return true;
}
else {
return false;
}
}
}
bool Polytope::checkEqualt1val(gen rur, gen par, gen t1v) {
// cout << "checkEqualt1val" << endl;
gen te = _subst(makesequence(t1v,s__IDNT_e,rur[4]/rur[3]),&ct);
te = _simplify(te - rur[5]/rur[3],&ct);
te = _numer(te,&ct);
// cout << "te=" << te << endl;
// cout << "rur[2]=" << rur[2] << endl;
te = _rem(makesequence(te,rur[2],s__IDNT_e),&ct);
// cout << "rem:" << te << endl;
if (operator_equal(te,K.zeronumber,&ct)) {
return true;
}
else {
// need to check if par is a root of te!
gen g = _gcd(makesequence(te,rur[2]),&ct);
// cout << "gcd=" << g << endl;
gen sols = _realroot(makesequence(g,K.prec),&ct);
// cout << "sols=" << sols << endl;
// gen sols = _realroot(makesequence(te,K.prec),&ct);
// int count = 0;
bool fdd = false;
int ku = 0;
while (!fdd && ku<(*sols._VECTptr).size()) {
// for (int k=0; k<(*sols._VECTptr).size(); k++) {
gen rt = convert_interval(sols[ku][0],K.nd,&ct);
/* gen rt;
if (sols[ku][0].type==8) {
rt = convert_interval(sols[ku][0],K.nd,&ct);
}
else {
rt = sols[ku][0];
}*/
gen Jt = _intersect(makesequence(rt,par),&ct);
// if (Jt.type==3) {
// count++;
// }
fdd = Jt.type==3;
ku++;
}
/* if (count==0) {
return false;
}
else {
if (count==1) {
return true;
}
else {
cout << "Intervals are not isolating, will need to work harder" << endl;
exit(1);
}
}*/
return fdd;
}
}
bool Polytope::checkt2val(gen rur, gen par, gen t2v, int &res) {
// cout << "checkt2val" << endl;
gen par_refined;
if (checkt2valAttempt(rur,par,t2v,res)) {
return true;
}
else {
if (checkEqualt2val(rur,par,t2v)) {
res = 0;
return true;
}
else {
int savend = K.nd;
bool done = false;
while (K.nd<K.ndmax && !done) {
// compute par_refined?
gen sols =_realroot(makesequence(rur[2],K.prec),&ct);
int count = 0;
int ksave;
for (int k=0; k<(*sols._VECTptr).size(); k++) {
gen rt = convert_interval(sols[k][0],K.nd,&ct);
/* gen rt;
if (sols[k][0].type==8) {
rt = convert_interval(sols[k][0],K.nd,&ct);
}
else {
rt = sols[k][0];
}*/
gen Jt = _intersect(makesequence(rt,par),&ct);
if (Jt.type==3) {
count++;
ksave = k;
}
}
if (count!=1) {
cout << "Could not identify par from rur (count=" << count << ")" << endl;
return false;
}
else {
par_refined = sols[ksave][0];
}
done = checkt2valAttempt(rur, par_refined, t2v, res);
if (!done) {
K.increasePrecision();
}
}
K.nd = savend;
K.lowerPrecision();
return done;
}
}
}
bool Polytope::checkt2valAttempt(gen rur, gen par, gen t2v, int &res) {
// cout << "checkt2valAttempt" << endl;
gen t2vi = K.evali(t2v);
gen t2_from_rur = _horner(makesequence(rur[6],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
t2_from_rur = convert_interval(t2_from_rur,K.nd,&ct);
// in some case the solutions are integers, then the result is not an interval...
// cout << "t2_from_rur before trick: " << t2_from_rur << endl;
if (operator_equal(t2_from_rur,K.zeronumber,&ct)) {
t2_from_rur = convert_interval(K.onenumber,K.nd,&ct)-K.onenumber;
}
// cout << "t2vi=" << t2vi << endl;
// cout << "t2_from_rur=" << t2_from_rur << endl;
if (is_greater(_left(t2vi,&ct),_right(t2_from_rur,&ct),&ct)) {
res = -1;
return true;
}
else {
if (is_greater(_left(t2_from_rur,&ct),_right(t2vi,&ct),&ct)) {
res = 1;
return true;
}
else {
return false;
}
}
}
bool Polytope::checkEqualt2val(gen rur, gen par, gen t2v) {
// cout << "checkEqualt2val" << endl;
gen te = _subst(makesequence(t2v,s__IDNT_e,rur[4]/rur[3]),&ct);
te = _simplify(te - rur[6]/rur[3],&ct);
te = _numer(te,&ct);
te = _rem(makesequence(te,rur[2],s__IDNT_e),&ct);
if (operator_equal(te,K.zeronumber,&ct)) {
return true;
}
else {
// need to check if par is a root of te!
gen g = _gcd(makesequence(te,rur[2]),&ct);
gen sols = _realroot(makesequence(g,K.prec),&ct);
// gen sols = _realroot(makesequence(te,K.prec),&ct);
// int count = 0;
bool fd = false;
int k = 0;
while (!fd && k<(*sols._VECTptr).size()) {
// for (int k=0; k<(*sols._VECTptr).size(); k++) {
// cout << "sols[" << k << "][0]=" << sols[k][0] << endl;
gen rt = convert_interval(sols[k][0],K.nd,&ct);
/* gen rt;
if (sols[k][0].type==8) {
rt = convert_interval(sols[k][0],K.nd,&ct);
}
else {
rt = sols[k][0];
}*/
gen Jt = _intersect(makesequence(rt,par),&ct);
/* if (Jt.type==3) {
count++;
}*/
fd = Jt.type==3;
k++;
}
/* if (count==0) {
return false;
}
else {
if (count==1) {
return true;
}
else {
cout << "Intervals are not isolating, will need to work harder" << endl;
exit(1);
}
}*/
return fd;
}
}
bool Polytope::checkt3val(gen rur, gen par, gen t3v, gen vl, gen wl, gen vt, int &res) {
/* cout << "checkt3val" << endl;
cout << "par=" << par << endl;
cout << "t3v=" << t3v << endl;
cout << "vl=" << vl << endl;
cout << "wl=" << wl << endl;
cout << "vt=" << vt << endl;*/
gen par_refined;
if (checkt3valAttempt(rur,par,t3v,vl,wl,vt,res)) {
return true;
}
else {
if (checkEqualt3val(rur,par,t3v,vl,wl,vt)) {
res = 0;
return true;
}
else {
int savend = K.nd;
bool done = false;
while (K.nd<K.ndmax && !done) {
gen sols =_realroot(makesequence(rur[2],K.prec),&ct);
int count = 0;
int ksave;
for (int k=0; k<(*sols._VECTptr).size(); k++) {
// gen rt = convert_interval(sols[k][0],K.nd,&ct);
// not sure what type==8 means, and why the next conditional statement...
gen rt = convert_interval(sols[k][0],K.nd,&ct);
/* gen rt;
if (sols[k][0].type==8) {
rt = convert_interval(sols[k][0],K.nd,&ct);
}
else {
rt = sols[k][0];
}*/
gen Jt = _intersect(makesequence(rt,par),&ct);
if (Jt.type==3) {
count++;
ksave = k;
}
}
if (count!=1) {
cout << "Could not identify par from rur (count=" << count << ")" << endl;
return false;
}
else {
par_refined = convert_interval(sols[ksave][0],K.nd,&ct);
}
done = checkt3valAttempt(rur, par_refined, t3v,vl,wl,vt,res);
if (!done) {
K.increasePrecision();
}
}
K.nd = savend;
K.lowerPrecision();
return done;
}
}
}
bool Polytope::checkt3valAttempt(gen rur, gen par, gen t3v, gen vl, gen wl, gen vt, int &res) {
// cout << "checkt3valattempt" << endl;
// cout << "par=" << par << endl;
// Changed this line on Nov 28, 2019, looks like a very silly typo
gen svvi = _horner(makesequence(rur[4],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
// gen svvi = _horner(makesequence(rur[5],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
gen t1vi = _horner(makesequence(rur[5],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
gen t2vi = _horner(makesequence(rur[6],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
// in some case the solutions are integers, then the result is not an interval...
if (operator_equal(t1vi,K.zeronumber,&ct)) {
t1vi = convert_interval(K.onenumber,K.nd,&ct)-K.onenumber;
}
if (operator_equal(t2vi,K.zeronumber,&ct)) {
t2vi = convert_interval(K.onenumber,K.nd,&ct)-K.onenumber;
}
gen alp = -Inn(vt,vl);
gen bet = Inn(vt,wl);
alp = (alp*K.myconj(bet)+K.myconj(alp)*bet)/2;
bet = bet*K.myconj(bet);
K.red(alp);
K.red(bet);
alp = K.convertToReal(alp);
bet = K.convertToReal(bet);
// cout << "alp=" << alp << endl;
// cout << "bet=" << bet << endl;
// cout << "svvi=" << svvi << endl;
alp = _subst(makesequence(alp,s__IDNT_e,svvi),&ct);
alp = _subst(makesequence(alp,K.t1,t1vi),&ct);
alp = _subst(makesequence(alp,K.t2,t2vi),&ct);
// cout << "alp=" << alp << endl;
bet = _subst(makesequence(bet,s__IDNT_e,svvi),&ct);
bet = _subst(makesequence(bet,K.t1,t1vi),&ct);
bet = _subst(makesequence(bet,K.t2,t2vi),&ct);
// cout << "bet=" << bet << endl;
gen t3_from_rur = alp/bet;
gen t3vi = K.evali(t3v);
if (is_greater(_left(t3vi,&ct),_right(t3_from_rur,&ct),&ct)) {
res = -1;
return true;
}
else {
if (is_greater(_left(t3_from_rur,&ct),_right(t3vi,&ct),&ct)) {
res = 1;
return true;
}
else {
// cout << "t3_from_rur=" << t3_from_rur << endl;
// cout << "t3vi=" << t3vi << endl;
return false;
}
}
}
bool Polytope::checkEqualt3val(gen rur, gen par, gen t3v, gen vl, gen wl, gen vt) {
// cout << "checkEqualt3val" << endl;
// cout << "par=" << par << endl;
gen alp = -Inn(vt,vl);
gen bet = Inn(vt,wl);
alp = (alp*K.myconj(bet)+K.myconj(alp)*bet)/2;
bet = bet*K.myconj(bet);
K.red(alp);
K.red(bet);
alp = K.convertToReal(alp);
bet = K.convertToReal(bet);
// cout << "alp=" << alp << endl;
// cout << "bet=" << bet << endl;
alp = _simplify(_subst(makesequence(alp,s__IDNT_e,rur[4]/rur[3]),&ct),&ct);
alp = _simplify(_subst(makesequence(alp,K.t1,rur[5]/rur[3]),&ct),&ct);
alp = _simplify(_subst(makesequence(alp,K.t2,rur[6]/rur[3]),&ct),&ct);
bet = _simplify(_subst(makesequence(bet,s__IDNT_e,rur[4]/rur[3]),&ct),&ct);
bet = _simplify(_subst(makesequence(bet,K.t1,rur[5]/rur[3]),&ct),&ct);
bet = _simplify(_subst(makesequence(bet,K.t2,rur[6]/rur[3]),&ct),&ct);
// cout << "after subst" << endl;
// cout << "alp=" << alp << endl;
// cout << "bet=" << bet << endl;
// cout << "t3v=" << t3v << endl;
gen t3v_rur = _simplify(_subst(makesequence(t3v,s__IDNT_e,rur[4]/rur[3]),&ct),&ct);
gen t3v_num = _numer(t3v_rur,&ct);
gen t3v_den = _denom(t3v_rur,&ct);
t3v_num = _rem(makesequence(t3v_num,rur[2],s__IDNT_e),&ct);
t3v_den = _rem(makesequence(t3v_den,rur[2],s__IDNT_e),&ct);
// cout << "t3v_rur: " << t3v_rur << endl;
// cout << "t3v_num: " << t3v_num << endl;
// cout << "t3v_den: " << t3v_den << endl;
gen te = alp*t3v_den - bet*t3v_num;
gen te_num = _numer(te,&ct);
gen te_den = _denom(te,&ct);
// cout << "te_num=" << te_num << endl;
// cout << "te_den=" << te_den << endl;
te_num = _rem(makesequence(te_num,rur[2],s__IDNT_e),&ct);
te_den = _rem(makesequence(te_den,rur[2],s__IDNT_e),&ct);
/* cout << "after rem:" << endl;
cout << "te_num=" << te_num << endl;
cout << "te_den=" << te_den << endl;*/
te = te_num;
// cout << "te before rem: " << te << endl;
// gen te =alp/bet - _subst(makesequence(t3v,s__IDNT_e,rur[4]/rur[3]),&ct);
// cout << "te before factor" << te << endl;
// te = _factor(te,&ct);
// cout << "te after factor: " << te << endl;
// te = _numer(te,&ct);
// cout << "te after numer: " << te << endl;
// te = _rem(makesequence(te,rur[2],s__IDNT_e),&ct);
// cout << "te after rem: " << te << endl;
if (operator_equal(te,K.zeronumber,&ct)) {
return true;
}
else {
// need to check if par is a root of te!
gen g = _gcd(makesequence(te,rur[2]),&ct);
// cout << "te=" << te << endl;
// cout << "rur[2]=" << rur[2] << endl;
// cout << "gcd=" << g << endl;
gen sols = _realroot(makesequence(g,K.prec),&ct);
// gen sols = _realroot(makesequence(te,K.prec),&ct);
// int count = 0;
bool fd = false;
int k = 0;
while (!fd && k<(*sols._VECTptr).size()) {
// for (int k = 0; k<(*sols._VECTptr).size(); k++) {
gen rt = convert_interval(sols[k][0],K.nd,&ct);
// cout << "rt=" << rt << endl;
/* gen rt;
if (sols[k][0].type==8) {
rt = convert_interval(sols[k][0],K.nd,&ct);
}
else {
rt = sols[k][0];
}*/
gen Jt = _intersect(makesequence(rt,par),&ct);
fd = Jt.type==3;
/* if (Jt.type==3) {
count++;
}*/
k++;
}
/* if (count==0) {
return false;
}
else {
if (count==1) {
return true;
}
else {
cout << "Intervals are not isolating, will need to work harder" << endl;
exit(1);
}
}*/
return fd;
}
}
bool Polytope::checkEqSign(gen rur, gen par, gen eq, int &res) {
// cout << "checkEqSign" << endl;
gen par_refined;
if (checkEqSignAttempt(rur,par,eq,res)) {
return true;
}
else {
if (checkEqZero(rur,par,eq)) {
res = 0;
return true;
}
else {
// cout << "Eq is not zero" << endl;
int savend = K.nd;
bool done = false;
while (K.nd<K.ndmax && !done) {
// cout << "Will use realroot... " << endl;
gen sols =_realroot(makesequence(rur[2],K.prec),&ct);
// cout << " ... done realroot" << endl;
int count = 0;
int ksave;
for (int k=0; k<(*sols._VECTptr).size(); k++) {
// cout << "using root #" << k << endl;
gen rt = convert_interval(sols[k][0],K.nd,&ct);
/* gen rt;
if (sols[k][0].type==8) {
rt = convert_interval(sols[k][0],K.nd,&ct);
}
else {
rt = sols[k][0];
}*/
gen Jt = _intersect(makesequence(rt,par),&ct);
if (Jt.type==3) {
count++;
ksave = k;
}
}
if (count!=1) {
cout << "Could not identify par from rur (count=" << count << ")" << endl;
return false;
}
else {
par_refined = sols[ksave][0];
}
done = checkEqSignAttempt(rur,par_refined,eq,res);
if (!done) {
// cout << "Increasing precision" << endl;
K.increasePrecision();
}
}
K.nd = savend;
K.lowerPrecision();
// cout << "done with checkeqsign" << endl;
return done;
}
}
}
bool Polytope::checkEqSignAttempt(gen rur, gen par, gen eq, int &res) {
gen svvi = _horner(makesequence(rur[5],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
gen t1vi = _horner(makesequence(rur[5],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
gen t2vi = _horner(makesequence(rur[6],par,s__IDNT_e),&ct)/_horner(makesequence(rur[3],par,s__IDNT_e),&ct);
gen eq_eval = _subst(makesequence(eq,s__IDNT_e,svvi),&ct);
eq_eval = _subst(makesequence(eq_eval,K.t1,t1vi),&ct);
eq_eval = _subst(makesequence(eq_eval,K.t2,t2vi),&ct);
if (is_greater(K.zeronumber,_right(eq_eval,&ct),&ct)) {
res = -1;
return true;
}
else {
if (is_greater(_left(eq_eval,&ct),K.zeronumber,&ct)) {
res = 1;
return true;
}
else {
return false;
}
}
}
bool Polytope::checkEqZero(gen rur, gen par, gen eq) {
if (verbose) {
cout << "checkEqZero" << endl;
cout << "eq=" << eq << endl;
cout << "rur=" << rur << endl;
}
gen te = _subst(makesequence(eq,s__IDNT_e,rur[4]/rur[3]),&ct);
te = _numer(te,&ct);
te = _rem(makesequence(te,rur[2],s__IDNT_e),&ct);
if (verbose) {
cout << "te after subs s: " << te << endl;
}
te = _subst(makesequence(te,K.t1,rur[5]/rur[3]),&ct);
te = _numer(te,&ct);
te = _rem(makesequence(te,rur[2],s__IDNT_e),&ct);
if (verbose) {
cout << "te after subs t1: " << te << endl;
}
te = _subst(makesequence(te,K.t2,rur[6]/rur[3]),&ct);
te = _numer(te,&ct);
te = _rem(makesequence(te,rur[2],s__IDNT_e),&ct);
if (verbose) {
cout << "te after subs t2: " << te << endl;
}
// te = giac::expand(te,&ct);
// te = _numer(te,&ct);
// te = _rem(makesequence(te,rur[2],s__IDNT_e),&ct);
if (operator_equal(te,K.zeronumber,&ct)) {
return true;
}
else {
// need to check if par is a root of te!
// cout << "te=" << te << endl;
// cout << "rur[2]=" << rur[2] << endl;
gen g = _gcd(makesequence(te,rur[2]),&ct);
// [the gcd is useless??]
// cout << "g=" << g << endl;
gen sols = _realroot(makesequence(g,K.prec),&ct);
// gen sols = _realroot(makesequence(te,K.prec),&ct);
// cout << "roots: " << sols << endl;
// int count = 0;
bool fd = false;
int k = 0;
// for (int k=0; k<(*sols._VECTptr).size(); k++) {
while (!fd && k<(*sols._VECTptr).size()) {
gen rt = convert_interval(sols[k][0],K.nd,&ct);
/* gen rt;
if (sols[k][0].type==8) {
rt = convert_interval(sols[k][0],K.nd,&ct);
}
else {
rt = sols[k][0];
}*/
gen Jt = _intersect(makesequence(rt,par),&ct);
/* if (Jt.type==3) {
count++;
}*/
fd = Jt.type==3;
k++;
}
// cout << "result: " << fd << endl;
/* if (count==0) {
return false;
}
else {
if (count==1) {
return true;
}
else {
cout << "Intervals are not isolating, will need to work harder" << endl;
exit(1);
}
}*/
return fd;
}
}
void Polytope::importFaceData() {
string filename = "faceData/faceData_"+K.tag+".chg";
ifstream infile(filename.c_str());
while (infile)
{
int n;
infile >> n;
cout << "[" << n << "]-gon" << endl;
if (infile) {
vector<int> wm;
string line;
getline(infile,line);
istringstream issm(line);
copy(istream_iterator<int>(issm),istream_iterator<int>(),back_inserter(wm));
cout << "Mirror: " << convertword(wm) << endl;
}
for (int k=0; k<n; k++) {
if (infile) {
string s;
infile >> s;
cout << s << endl;
}
}
}
}
void Polytope::exportFaceData() {
ofstream file;
string filename = "faceData/faceData_"+K.tag+".chg";
file.open(filename.c_str());
for (int k=0; k<faces.size(); k++) {
file << faces[k].sides.size() << endl;
file << faces[k].mirror.word << endl;
for (int l=0; l<faces[k].sides.size(); l++) {
file << faces[k].sides[l].word << endl;
}
}
file.close();
cout << "Done exporting face data" << endl;
}
void Polytope::checkLinks() {
for (int k=0; k<vertexPOrbits.size(); k++) {
int kk = vertexPOrbits[k][0];
cout << "Studying link for vertex #" << kk << endl;
WVector V = vertices[kk];
int e0 = 0;
int e1 = 0;
int e2 = 0;
vector<int> incident_edges;
for (int l=0; l<edges.size(); l++) {
if (edges[l].origin==kk || edges[l].end==kk) {
incident_edges.push_back(l);
}
}
e0 = incident_edges.size();
if (verbose) {
cout << "e0=" << e0 << endl;
}
for (int l=0; l<ridges.size(); l++) {
int m = -1;
bool isvert = false;
while (!isvert && m!=ridges[l].verts.size()-1) {
m++;
isvert = ridges[l].verts[m]==kk;
}
if (isvert) {
e1++;
}
}
if (verbose) {
cout << "e1=" << e1 << endl;
}
vector<vector<int> > twofaces_in_link; // Note these could be DIGONS!
// I think this is not a problem, digons do not affect orientation?
for (int u=0; u<vertices[kk].faceindices.size(); u++) {
if (vertices[kk].faceindices[u]!=-1) {
vector<int> twoface, ordered_twoface;
for (int v=0; v<incident_edges.size(); v++) {
vector<int> fi = edges[incident_edges[v]].faceindices;
if (find(fi.begin(),fi.end(),vertices[kk].faceindices[u])!=fi.end()) {
twoface.push_back(incident_edges[v]);
}
}
if (verbose) {
cout << "Unordered 2-face: " << convertword(twoface) << endl;
}
ordered_twoface.push_back(twoface[0]);
twoface.erase(twoface.begin());
bool foundneighb = false;
int st1 = -1;
while (!foundneighb && st1!=twoface.size()-1) {
st1++;
foundneighb = intersect(edges[twoface[0]].faceindices,edges[twoface[st1]].faceindices).size()!=0;
}
if (!foundneighb) {
cerr << "Trouble finding neighbor in 2-face of link" << endl;
exit(1);
}
else {
ordered_twoface.push_back(twoface[st1]);
twoface.erase(twoface.begin()+st1);
while (twoface.size()>0) {
foundneighb = false;
int t = -1;
while (!foundneighb && t!=twoface.size()-1) {
t++;
foundneighb = ( intersect(edges[ordered_twoface[ordered_twoface.size()-1]].faceindices,edges[twoface[t]].faceindices).size()!=0 );
}
if (!foundneighb) {
cerr << "Trouble finding neighbor in 2-face of link" << endl;
exit(1);
}
else {
ordered_twoface.push_back(twoface[t]);
twoface.erase(twoface.begin()+t);
}
}
}
if (ordered_twoface.size()>2) {
twofaces_in_link.push_back(ordered_twoface);
}
else {
cout << "Ignoring digon, irrelevant for orientation check" << endl;
}
if (verbose) {
cout << "Ordered 2-face: " << convertword(ordered_twoface) << endl;
}
}
}
if (verbose) {
cout << "Ordered 2-faces:" << endl;
for (int uu=0; uu<twofaces_in_link.size(); uu++) {
cout << convertword(twofaces_in_link[uu]) << endl;
}
}
// then need to check if we can orient them coherently!
vector<int> list;
for (int uu=0; uu<twofaces_in_link.size(); uu++) {
list.push_back(uu);
}
vector<vector<int> > well_oriented_twofaces;
bool is_orientable = true;
while (is_orientable && list.size()>0) {
if (verbose) {
cout << " trying to find a 2-face that neighbors a well oriented one" << endl;
}
bool isneighbor = false;
int zz=-1;
vector<int> common;
while (!isneighbor && zz!=well_oriented_twofaces.size()-1) {
zz++;
vector<int> common = intersect(twofaces_in_link[0],well_oriented_twofaces[zz]);
isneighbor = common.size()==2;
}
if (!isneighbor) {
list.erase(list.begin());
if (verbose) {
cout << "list=" << list << endl;
}
}
else {
cout << " found a neighbor, will orient it well with that neighbor, then check compatibility" << endl;
bool or1, or2;
int uuu=-1;
bool fdcommon = false;
while (!fdcommon && uuu!=twofaces_in_link[0].size()-1) {
uuu++;
fdcommon = common[0]==twofaces_in_link[0][uuu];
}
if (!fdcommon) {
cerr << "Trouble finding common" << endl;
exit(1);
}
else {
or1 = (common[1]==twofaces_in_link[0][(uuu+1)%twofaces_in_link[0].size()]);
}
int uuuu=-1;
fdcommon = false;
while (!fdcommon && uuuu!=well_oriented_twofaces[zz].size()-1) {
uuuu++;
fdcommon = common[0]==well_oriented_twofaces[zz][uuuu];
}
if (!fdcommon) {
cerr << "Trouble finding common" << endl;
exit(1);
}
else {
or2 = (common[1]==well_oriented_twofaces[zz][(uuuu+1)%well_oriented_twofaces[zz].size()]);
}
if (or1==or2) {
cout << " switch orientation" << endl;
// switch orientation!
twofaces_in_link[0] = flipword(twofaces_in_link[0]);
}
bool is_coherent;
for (int y=0; y<well_oriented_twofaces.size(); y++) {
vector<int> common = intersect(twofaces_in_link[0],well_oriented_twofaces[y]);
if (common.size()==2) {
// locate common in both 2faces?
bool or1, or2;
int uuu=-1;
bool fdcommon = false;
while (!fdcommon && uuu!=twofaces_in_link[0].size()-1) {
uuu++;
fdcommon = common[0]==twofaces_in_link[0][uuu];
}
if (!fdcommon) {
cerr << "Trouble finding common" << endl;
exit(1);
}
else {
or1 = (common[1]==twofaces_in_link[0][(uuu+1)%twofaces_in_link[0].size()]);
}
int uuuu=-1;
fdcommon = false;
while (!fdcommon && uuuu!=well_oriented_twofaces[y].size()-1) {
uuuu++;
fdcommon = common[0]==well_oriented_twofaces[y][uuuu];
}
if (!fdcommon) {
cerr << "Trouble finding common" << endl;
exit(1);
}
else {
or2 = (common[1]==well_oriented_twofaces[y][(uuuu+1)%well_oriented_twofaces[y].size()]);
}
if (or1==or2) {
cerr << "This vertex link is not orientable!!" << endl;
exit(1);
}
}
}
twofaces_in_link.erase(twofaces_in_link.begin());
}
}
if (vertices[kk].faceindices[0]==-1) {
e2 = vertices[kk].faceindices.size()-1;
}
else {
e2 = vertices[kk].faceindices.size();
}
if (verbose) {
cout << "e2=" << e2 << endl;
}
gen ee = (e0-e1+e2);
if (!operator_equal(ee,K.twonumber,&ct)) {
cerr << "Euler characteristic of vertex: " << ee << ", this is not a sphere!" << endl;
exit(1);
}
}
cout << endl;
cout << "Great! Vertex links are spheres!" << endl;
cout << "The boundary of the polytope is a manifold." << endl;
cout << endl;
}
void Polytope::checkSphere() {
vector<vector<int> > graph_edges;
for (int uu=0; uu<edges.size(); uu++) {
vector<int> e;
e.push_back(edges[uu].origin);
e.push_back(edges[uu].end);
graph_edges.push_back(e);
}
sgraph G(graph_edges);
vector<vector<int> > stabgens;
vector<vector<bool> > orientations;
G.fundamental_group(0,stabgens,orientations);
cout << "1-skeleton has " << vertices.size() << " vertices, " << edges.size() << " edges" << endl;
cout << "Found " << G.generators.size() << " gens for pi_1 of 1-skeleton" << endl;
vector<vector<int> > ridgerels;
vector<vector<bool> > ridgeorients;
for (int u=0; u<ridges.size(); u++) {
vector<int> rel;
vector<bool> orient;
int nv = ridges[u].verts.size();
for (int v=0; v<nv; v++) {
int jo = ridges[u].verts[v%nv];
int ko = ridges[u].verts[(v+1)%nv];
bool fd = false;
bool flipped;
int w = -1;
while (!fd && w!=edges.size()-1) {
w++;
fd = (jo==edges[w].origin && ko==edges[w].end);
if (fd) {
flipped = false;
}
else {
fd = (jo==edges[w].end && ko == edges[w].origin);
if (fd) {
flipped = true;
}
}
}
if (fd) {
rel.push_back(w);
orient.push_back(flipped);
}
else {
cerr << "Problem identifying edge in ridge" << endl;
exit(1);
}
}
ridgerels.push_back(rel);
ridgeorients.push_back(orient);
}
G.export_fg_with_relations(0,K.tag,ridgerels,ridgeorients);
cout << " (you should check that that group is trivial by simplifying it with GAP)" << endl;
cout << endl;
}
string Polytope::checkSignature(gen A) {
// this only makes sense provided A is a Hermitian matrix!
gen de = K.det(A);
K.red(de);
de = K.convertToReal(de);
int sgn_de;
if (!K.checkSign(de,sgn_de)) {
cerr << "Trouble checking signature of the Hermitian form" << endl;
exit(1);
}
else {
if (sgn_de<0) {
return "-++";
// this only works for sporadic/triangle group Hermitian forms!
// (because by construction there are some positive vectors, so signature cannot be ---)
}
else {
gen sn = A[0][0]*A[1][1] - A[0][1]*A[1][0];
K.red(sn);
sn = K.convertToReal(sn);
int sgn_sn;
if (!K.checkSign(sn,sgn_sn)) {
cerr << "Trouble checking signature of the Hermitian form (doing Gramm-Schmidt)" << endl;
exit(1);
}
else {
if (sgn_sn>0) {
return "+++";
}
else {
if (sgn_sn<0) {
return "--+";
}
else {
cerr << "Trouble computing signature" << endl;
exit(1);
}
}
}
}
}
}
bool Polytope::checkTraceField(gen &res) {
// so far this only works for Mostow and Sporadic groups!!
gen sigma;
cout << endl;
if (is_symmetric) {
// don't want to take the cube for mostow groups
if (K.tag[0]=='m') {
// cout << "tag=" << K.tag << endl;
// cout << "K.taugen: " << K.taugen << endl;
// cout << "taugen: " << taugen << endl;
sigma = taugen;
}
else {
sigma = normal(taugen,&ct);
// cout << "taugen=" << sigma << endl;
gen s2 = normal(sigma*sigma,&ct);
// cout << "taugen^2=" << s2 << endl;
sigma = normal(s2*sigma,&ct);
// cout << "taugen^3=" << sigma << endl;
}
}
else {
sigma = normal(K.T[0]*K.T[1]*K.T[2],&ct);
}
sigma = eval(sigma,&ct);
cout << "sigma=" << sigma << endl;
cout << " (" << _evalf(sigma,&ct) << ")" << endl;
cout << "Will now compute an upper bound for the degree of adjoint trace field.." << endl;
cout << endl;
cout << "tau^3=" << sigma << endl;
/* cout << "tau^3, eval=" << eval(sigma,&ct) << endl;
cout << "tau^3, simplify eval=" << _simplify(eval(sigma,1,&ct),&ct) << endl;
cout << "evalf(tau^3)=" << _evalf(sigma,&ct) << endl;*/
gen pm = _pmin(eval(sigma,1,&ct),&ct);
// changes nov 22 2019, playing with m3-1%6
//gen pm = _pmin(normal(eval(sigma,1,&ct),&ct),&ct);
// gen pm = _pmin(normal(_eval(sigma,&ct),&ct),&ct);
cout << "pm=" << pm << endl;
gen sigminpol = giac::expand(_poly2symb(makesequence(pm,x__IDNT_e),&ct),&ct);
if (verbose) {
cout << "Minimal polynomial of tau^3: " << sigminpol << endl;
}
int dt3 = _degree(makesequence(sigminpol,x__IDNT_e),&ct).val;
if (dt3==1) {
gen zeta = eval(gen("exp(2*pi*i/"+print_INT_(pval)+")",&ct),1,&ct);
gen zeta_mp = giac::expand(_poly2symb(makesequence(_pmin(zeta,&ct),x__IDNT_e),&ct),&ct);
if (verbose) {
cout << "Minimal polynomial of exp(2*pi*i/p): " << zeta_mp << endl;
}
sigminpol = zeta_mp;
}
else {
if (operator_equal(_coeff(makesequence(sigminpol,x__IDNT_e,dt3),&ct),-K.onenumber,&ct)) {
sigminpol = - sigminpol;
}
// if (verbose) {
cout << "sigminpol " << sigminpol << endl;
// }
gen compol = simplify(eval(gen("x^2+1",&ct),&ct)-sigminpol,&ct);
if (!operator_equal(compol,K.zeronumber,&ct)) {
gen st("k",&ct);
gen ro = rootof(sigminpol,&ct); // this will often not be the same as tau^3
sto(st,ro,&ct);
gen zeta = _simplify(gen("exp(2*pi*i/"+print_INT_(pval)+")",&ct),&ct);
gen zeta_mp = giac::expand(_poly2symb(makesequence(_pmin(zeta,&ct),z__IDNT_e),&ct),&ct);
cout << "Minimal polynomial of exp(2*pi*i/p): " << zeta_mp << endl;
gen fa = _factors(makesequence(zeta_mp,ro),&ct);
for (int l=0; 2*l<(*fa._VECTptr).size(); l++) {
int deg = _degree(makesequence(fa[2*l],z__IDNT_e),&ct).val;
if (deg>1) {
gen te = _simplify(eval(_subst(makesequence(fa[2*l],z__IDNT_e,zeta),&ct),1,&ct),&ct);
if (operator_equal(te,K.zeronumber,&ct)) {
// then split this factor!
if (verbose) {
cout << "Split this factor: " << fa[2*l] << endl;
}
vecteur coe;
for (int uu=deg; uu>=0; uu--) {
gen teuu = _coeff(makesequence(fa[2*l],z__IDNT_e,uu),&ct);
if (verbose) {
cout << "teuu=" << teuu << endl;
}
if (contains(teuu,st)) {
if (verbose) {
cout << "Contains k!" << endl;
}
vecteur coe_u;
int subdeg = _degree(makesequence(teuu,st),&ct).val;
for (int vv=subdeg; vv>=0; vv--) {
gen teuu_vv = _coeff(makesequence(teuu,st,vv),&ct);
coe_u.push_back(teuu_vv);
}
if (verbose) {
cout << "coe_u=" << coe_u << endl;
}
coe.push_back(giac::expand(_poly2symb(makesequence(coe_u,x__IDNT_e),&ct),&ct));
}
else {
if (teuu.type==8) {
if (teuu.is_symb_of_sommet(at_prod)) {
gen yoo = _poly2symb(makesequence(_simplify(teuu[1][1]*teuu[2],&ct),x__IDNT_e),&ct);
coe.push_back(yoo);
}
else {
if (teuu.is_symb_of_sommet(at_rootof)) {
gen yoo = _poly2symb(makesequence(_simplify(teuu[1],&ct),x__IDNT_e),&ct);
coe.push_back(yoo);
}
else {
cout << "teuu=" << teuu << endl;
cout << "Problem reading factors!" << endl;
}
}
}
else {
coe.push_back(teuu);
}
}
}
if (verbose) {
cout << "coe=" << coe << endl;
}
vecteur eqs;
eqs.push_back(sigminpol);
eqs.push_back(giac::expand(_poly2symb(makesequence(coe,a__IDNT_e),&ct),&ct));
if (verbose) {
cout << "eqs: " << eqs << endl;
}
vecteur vars;
vars.push_back(x__IDNT_e);
vars.push_back(a__IDNT_e);
if (verbose) {
cout << "vars: " << vars << endl;
}
gen gb = _gbasis(makesequence(eqs,vars,change_subtype(_RUR_REVLEX,_INT_GROEBNER)),&ct);
if (gb[0]==-4) {
gen varprov = lidnt(gb[2])[0];
sigminpol = _subst(makesequence(gb[2],varprov,x__IDNT_e),&ct);
int ds = _degree(makesequence(sigminpol,x__IDNT_e),&ct).val;
if (operator_equal( _coeff(makesequence(sigminpol,x__IDNT_e,ds),&ct), -K.onenumber, &ct)) {
sigminpol = _simplify(-sigminpol,&ct);
}
}
else {
cerr << "Trouble computing primitive element" << endl;
exit(1);
}
}
}
}
}
else {
cout << "Need alternate method, sto(i) is not allowed" << endl;
gen l = _lcm(makesequence(4*K.onenumber,pval),&ct);
cout << "LCM=" << l << endl;
sigminpol = giac::expand(_poly2symb(makesequence(_cyclotomic(l,&ct),x__IDNT_e),&ct),&ct);
if (verbose) {
cout << "sigminpol: " << sigminpol << endl;
}
}
}
if (verbose) {
cout << "sigminpol=" << sigminpol << endl;
}
int maxdeg = _degree(makesequence(sigminpol,x__IDNT_e),&ct).val;
if (maxdeg%2!=0) {
cerr << "Odd degree for complex field?! This should not happen..." << endl;
exit(1);
}
maxdeg = maxdeg/2;
cout << endl;
cout << "Degree of adjoint trace field is at most " << maxdeg << endl;
cout << "K.minpol: " << K.minpol << endl;
cout << "K.realminpol: " << K.realminpol << endl;
cout << "K.realgen: " << K.realgen << endl;
cout << "K.realgenasrootof: " << K.realgenasrootof << endl;
vecteur li, traces;
vector<vector<int> > wo, woall;
li.push_back(K.Id);
vector<int> wo0;
wo.push_back(wo0);
woall.push_back(wo0);
traces.push_back(K.trace(K.Id)*K.trace(K.Id));
bool done = false;
// this could be improved, we should stop whenever we have found a generator!
while (li.size()<100) {
int n = li.size();
for (int l=0; l<n; l++) {
vector<int> wop1;
wop1.push_back(1);
wop1 = concat(wop1,woall[l]);
woall.push_back(wop1);
gen M = R1*li[l];
K.matred(M);
li.push_back(M);
gen tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wop1);
}
vector<int> wom1;
wom1.push_back(-1);
wom1 = concat(wom1,woall[l]);
woall.push_back(wom1);
M = R1i*li[l];
K.matred(M);
li.push_back(M);
tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wom1);
}
vector<int> wop2;
wop2.push_back(2);
wop2 = concat(wop2,woall[l]);
woall.push_back(wop2);
M = R2*li[l];
K.matred(M);
li.push_back(M);
tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wop2);
}
vector<int> wom2;
wom2.push_back(-2);
wom2 = concat(wom2,woall[l]);
woall.push_back(wom2);
M = R2i*li[l];
K.matred(M);
li.push_back(M);
tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wom2);
}
vector<int> wop3;
wop3.push_back(3);
wop3 = concat(wop3,woall[l]);
woall.push_back(wop3);
M = R3*li[l];
K.matred(M);
li.push_back(M);
tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wop3);
}
vector<int> wom3;
wom3.push_back(-3);
wom3 = concat(wom3,woall[l]);
woall.push_back(wom3);
M = R3i*li[l];
K.matred(M);
li.push_back(M);
tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wom3);
}
vector<int> wop4;
wop4.push_back(4);
wop4 = concat(wop4,woall[l]);
woall.push_back(wop4);
M = J*li[l];
K.matred(M);
li.push_back(M);
tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wop4);
}
vector<int> wom4;
wom4.push_back(-4);
wom4 = concat(wom4,woall[l]);
woall.push_back(wom4);
M = Ji*li[l];
K.matred(M);
li.push_back(M);
tr = K.trace(M);
tr = tr*K.myconj(tr);
K.red(tr);
tr = K.convertToReal(tr);
if (_degree(makesequence(tr,s__IDNT_e),&ct).val>0 && !K.isInList(tr,traces)) {
traces.push_back(tr);
wo.push_back(wom4);
}
}
}
cout << "Values of |tr|^2 found " << endl;
for (int uu=1; uu<wo.size(); uu++) {
cout << convertword(wo[uu]) << ": " << traces[uu] << endl;
}
bool found = false;
vecteur goodtraces;
for (int k=0; k<traces.size(); k++) {
gen yo = _subst(makesequence(traces[k],s__IDNT_e,K.realgenasrootof),&ct);
yo = _simplify(yo,&ct);
if (contains(yo,gen("j",&ct))) {
yo = _subst(makesequence(yo,gen("j",&ct),K.genasrootof),&ct);
}
gen pmt = _pmin(yo,&ct);
int de = _degree(pmt,&ct).val;
if (de>maxdeg) {
cerr << "Found an element with degree higher than upper bound?!" << endl;
exit(1);
}
else {
if (de==maxdeg) {
goodtraces.push_back(traces[k]);
}
}
}
if (maxdeg>1 && goodtraces.size()==0) {
cerr << "I found no trace that generates the adjoint trace field" << endl;
return false;
}
else {
cout << "good traces: " << goodtraces << endl;
cout << "The adjoint trace field is equal to the upper bound, it has degree " << maxdeg << endl;
if (maxdeg==1) {
cout << "It is generated by 1" << endl;
res = K.onenumber;
return true;
}
else {
bool found;
int k=-1;
while (!found && k!=goodtraces.size()-1) {
k++;
found = operator_equal(goodtraces[k],s__IDNT_e,&ct);
}
if (found) {
cout << "It is generated by s" << endl;
res = s__IDNT_e;
}
else {
int dmin = K.dr.val;
for (int uu=0; uu<goodtraces.size(); uu++) {
int de = _degree(makesequence(goodtraces[uu],s__IDNT_e),&ct).val;
if (de<dmin) {
dmin = de;
res = goodtraces[uu];
}
}
cout << "It is generated by " << res << endl;
cout << " (" << K.evali(res) << ")" << endl;
cout << _simplify(_subst(makesequence(res,s__IDNT_e,K.realgenasrootof),&ct),&ct) << endl;
// cout << "It is generated by " << goodtraces[0] << endl;
// cout << _simplify(_subst(makesequence(goodtraces[0],s__IDNT_e,K.realgenasrootof),&ct),&ct) << endl;
}
return true;
}
cout << endl;
}
}
bool Polytope::isArithmeticAlt() {
gen gentf;
if (!checkTraceField(gentf)){
cerr << "I could not compute the adjoint trace field, cannot determine arithmeticity" << endl;
exit(1);
}
cout << "gentf=" << gentf << endl;
vecteur other_roots;
gen fa = _factors(makesequence(_subst(makesequence(K.minpol,x__IDNT_e,a__IDNT_e),&ct),K.genasrootof),&ct);
int nf = (*fa._VECTptr).size()/2;
int k=0;
bool found = false;
while (k<nf && !found) {
gen df = _degree(makesequence(fa[2*k],a__IDNT_e),&ct);
if (df==1) {
gen te = _simplify(-_coeff(makesequence(fa[2*k],a__IDNT_e,0),&ct)/_coeff(makesequence(fa[2*k],a__IDNT_e,1),&ct),&ct);
if (contains(te,gen("j",&ct))) {
int dete = _degree(makesequence(te,j__IDNT_e),&ct).val;
vecteur coe;
for (int uu=dete; uu>=0; uu--){
coe.push_back(_coeff(makesequence(te,j__IDNT_e,uu),&ct));
}
gen yoo = giac::expand(_poly2symb(makesequence(coe,x__IDNT_e),&ct),&ct);
other_roots.push_back(yoo);
}
else {
if (te.is_symb_of_sommet(at_prod)) {
gen yoo = giac::expand(_poly2symb(makesequence(_simplify(te[1][1]*te[2],&ct),x__IDNT_e),&ct),&ct);
other_roots.push_back(yoo);
}
else {
if (te.is_symb_of_sommet(at_rootof)) {
gen yoo = giac::expand(_poly2symb(makesequence(_simplify(te[1],&ct),x__IDNT_e),&ct),&ct);
other_roots.push_back(yoo);
}
else {
cout << "te=" << te << endl;
cout << "Problem reading factors!" << endl;
}
}
}
}
k++;
}
cout << "Done computing Galois conjugates of field generator" << endl;
vecteur x_images;
x_images.push_back(x__IDNT_e);
vecteur gentf_images;
gentf_images.push_back(gentf);
for (int k=0; k<other_roots.size(); k++) {
gen te = _subst(makesequence(gentf,s__IDNT_e,_subst(makesequence(K.realgen,x__IDNT_e,other_roots[k]),&ct)),&ct);
cout << "te before reduction: " << te << endl;
K.red(te);
// cout << "te=" << te << endl;
gen ste = K.convertToReal(te);
// cout << "ste=" << ste << endl;
bool isnew = true;
int l=0;
while (isnew && l<gentf_images.size()) {
isnew = !operator_equal(gentf_images[l],ste,&ct);
l++;
}
if (isnew) {
gentf_images.push_back(ste);
x_images.push_back(other_roots[k]);
}
}
cout << endl;
cout << "Done computing images" << endl;
if (verbose) {
cout << "Images of complex generator: " << x_images << endl;
cout << "Corresponding images of adjoint trace field generator: " << gentf_images << endl;
}
gentf_images.erase(gentf_images.begin());
x_images.erase(x_images.begin());
cout << "Signature of (non trivial) Galois conjugates?" << endl;
bool is_arithmetic = true;
for (int u=0; u<x_images.size(); u++) {
gen Hu = _subst(makesequence(H,x__IDNT_e,x_images[u]),&ct);
K.matred(Hu);
string si = checkSignature(Hu);
cout << si << endl;
if (si=="-++" || si=="--+") {
is_arithmetic=false;
}
}
if (is_arithmetic) {
cout << "Sorry, this group is arithmetic." << endl;
}
else {
cout << "The group is NOT arithmetic!" << endl;
}
isarithmeticitychecked = true;
isarithmetic = is_arithmetic;
return is_arithmetic;
}
bool Polytope::identify_in_field(gen x0, gen pol, gen &res) {
gen den = _denom(x0,&ct);
gen x = normal(x0*den,&ct);
gen mpx = giac::expand(_poly2symb(makesequence(_pmin(eval(x,&ct),&ct),a__IDNT_e),&ct),&ct);
if (verbose) {
cout << "min pol (identify_in_field): " << mpx << endl;
}
if (_degree(makesequence(mpx,a__IDNT_e),&ct).val==1) {
res = x0;
return true;
}
else {
gen gg = rootof(pol,&ct);
gen sta = gen("b",&ct);
sto(gg,sta,&ct);
gen fad = _factors(makesequence(mpx,gg),&ct);
bool found = false;
int k = 0;
int nk = (*fad._VECTptr).size()/2;
while (!found && k<nk) {
if (verbose) {
cout << "factor: " << fad[2*k] << endl;
}
int dfd = _degree(makesequence(fad[2*k],a__IDNT_e),&ct).val;
if (verbose) {
cout << "dfd=" << dfd << endl;
}
if (dfd!=1) {
cerr << "Trouble computing determinant as an element of the trace field" << endl;
// cout << "k=" << k << endl;
return false;
}
gen te = normal(-_subst(makesequence(fad[2*k],a__IDNT_e,K.zeronumber),&ct)/_diff(makesequence(fad[2*k],a__IDNT_e),&ct),&ct);
gen tec = normal(eval(te-x,&ct),&ct);
found = operator_equal(tec,K.zeronumber,&ct);
if (found) {
if (verbose) {
cout << "Found: " << te << endl;
}
// Found as a rootof, need to express it as a polynomial b...
if (contains(te,gen("b",&ct))) {
if (verbose) {
cout << "using b in computation of coeffs (det)" << endl;
}
int dete = _degree(makesequence(te,b__IDNT_e),&ct).val;
vecteur coe;
for (int uu=dete; uu>=0; uu--){
coe.push_back(_coeff(makesequence(te,b__IDNT_e,uu),&ct));
}
res = giac::expand(_poly2symb(makesequence(coe,b__IDNT_e),&ct),&ct)/den;
return true;
}
else {
if (te.is_symb_of_sommet(at_prod)) {
if (verbose) {
cout << "at_prod" << endl;
}
res = giac::expand(_poly2symb(makesequence(_simplify(te[1][1]*te[2],&ct),b__IDNT_e),&ct),&ct)/den;
return true;
}
else {
if (te.is_symb_of_sommet(at_rootof)) {
if (verbose) {
cout << "at_rootof" << endl;
}
res = giac::expand(_poly2symb(makesequence(_simplify(te[1],&ct),b__IDNT_e),&ct),&ct)/den;
return true;
}
else {
cout << "te=" << te << endl;
cout << "Problem reading factors!" << endl;
return false;;
}
}
}
}
k++;
}
if (!found) {
cout << "Trouble identifying in trace field" << endl;
return false;
}
}
}
bool Polytope::isArithmetic() {
gen gentf;
if (!checkTraceField(gentf)){
cerr << "I could not compute the adjoint trace field, cannot determine arithmeticity" << endl;
exit(1);
}
if (verbose) {
cout << "gentf=" << gentf << endl;
cout << " (" << K.evali(gentf) << ")" << endl;
}
gen gentf_asrootof = normal(_subst(makesequence(gentf,s__IDNT_e,K.realgenasrootof),&ct),&ct);
cout << "gentf as rootof: " << gentf_asrootof << endl;
// gen gentf_asrootof = normal(_subst(makesequence(gentf,s__IDNT_e,K.realgenasrootof),&ct),&ct);
// if (verbose) {
// cout << "gentf as rootof=" << gentf_asrootof << endl;
// }
gen p = giac::expand(_poly2symb(makesequence(_pmin(eval(gentf_asrootof,&ct),&ct),a__IDNT_e),&ct),&ct);
// if (verbose) {
cout << "min pol of gentf: " << p << endl;
// }
// gen p_roots = _realroot(makesequence(p,K.nd),&ct);
if (_degree(makesequence(p,a__IDNT_e),&ct).val==1) {
// The group is arithmetic.
// just for sanity check, will determine the signature of the form
cout << "Trace field is Q" << endl;
gen dH = K.det(H); // should be rational, almost nothing to do!
K.red(dH);
gen dHs = H[0][0]*H[1][1]-H[0][1]*H[1][0];
K.red(dHs);
cout << "det=" << dH << endl;
cout << "subdet=" << dHs << endl;
if (is_greater(-K.prec,dH,&ct)) {
cout << "Original signature ++-" << endl;
}
else {
if (is_greater(dH,K.prec,&ct)) {
if (is_greater(-K.prec,dHs,&ct)) {
cout << "Original signature +--" << endl;
cout << " (this should not happen)" << endl;
exit(1);
}
else {
if (is_greater(dHs,K.prec,&ct)) {
cout << "Original signature +++" << endl;
cout << " (this should not happen)" << endl;
exit(1);
}
else {
cerr << "Could not determine signature from intervals" << endl;
exit(1);
}
}
}
}
isarithmeticitychecked = true;
isarithmetic = true;
naindex = 0;
return true;
}
// done with the case where trace field is Q
// only works if p has degree>1
gen gg = rootof(p,&ct);
gen sta = gen("b",&ct);
sto(sta,gg,&ct);
gen gentf_pol;
if (!identify_in_field(gentf_asrootof,p,gentf_pol)) {
cerr << "Trouble identifying generator as poly in rootof" << endl;
exit(1);
}
vecteur other_roots;
gen fa = _factors(makesequence(p,gg),&ct);
int nf = (*fa._VECTptr).size()/2;
for (int k=0; k<nf; k++) {
// cout << "k=" << k << endl;
gen df = _degree(makesequence(fa[2*k],a__IDNT_e),&ct).val;
if (verbose) {
cout << "Factor: " << fa[2*k] << endl;
cout << "df=" << df << endl;
}
if (df==1) {
gen te = normal(-_coeff(makesequence(fa[2*k],a__IDNT_e,0),&ct)/_coeff(makesequence(fa[2*k],a__IDNT_e,1),&ct),&ct);
gen tec = normal(eval(te-gentf_asrootof,&ct),&ct);
gen te_pol;
if (!operator_equal(tec,K.zeronumber,&ct)) {
if (!identify_in_field(te,p,te_pol)) {
cerr << "Trouble identifying generator as poly in rootof" << endl;
exit(1);
}
else {
gen tecc = _simplify(te_pol-b__IDNT_e,&ct);
if (!operator_equal(tecc,K.zeronumber,&ct)) {
other_roots.push_back(te_pol);
}
}
}
}
}
cout << "Done computing " << other_roots.size() << " Galois conjugates of trace field generator" << endl;
cout << "Other roots: " << other_roots << endl;
gen dH = K.det(H);
K.red(dH);
dH = K.convertToReal(dH);
if (verbose) {
cout << "dH=" << dH << endl;
}
gen dH_asrootof = normal(_subst(makesequence(dH,s__IDNT_e,K.realgenasrootof),&ct),&ct);
if (verbose) {
cout << "det(H) as rootof=" << dH_asrootof << endl;
}
gen dHpol;
if (!identify_in_field(dH_asrootof,p,dHpol)) {
cerr << "Trouble identifying determinant" << endl;
exit(1);
}
gen dHs = H[0][0]*H[1][1]-H[0][1]*H[1][0];
K.red(dHs);
dHs = K.convertToReal(dHs);
if (verbose) {
cout << "dHs=" << dHs << endl;
}
gen dHs_asrootof = normal(_subst(makesequence(dHs,s__IDNT_e,K.realgenasrootof),&ct),&ct);
if (verbose) {
cout << "sub det as rootof=" << dHs_asrootof << endl;
}
gen dHspol;
if (!identify_in_field(dHs_asrootof,p,dHspol)) {
cerr << "Trouble identifying sub-determinant" << endl;
exit(1);
}
if (verbose) {
cout << "dHpol=" << dHpol << endl;
cout << "dHspol=" << dHspol << endl;
}
gen det0 = convert_interval(_subst(makesequence(dHpol,b__IDNT_e,gg),&ct),K.nd,&ct);
gen subdet0 = convert_interval(_subst(makesequence(dHspol,b__IDNT_e,gg),&ct),K.nd,&ct);
if (verbose) {
cout << "det(H): " << det0 << endl;
cout << "subdet: " << subdet0 << endl;
}
if (is_greater(-K.prec,det0,&ct)) {
cout << "Original signature ++-" << endl;
}
else {
if (is_greater(det0,K.prec,&ct)) {
if (is_greater(-K.prec,subdet0,&ct)) {
cout << "Original signature +--" << endl;
cout << " (this should not happen)" << endl;
cout << " det(H) num " << K.evali(dH) << endl;
cout << " subdet num " << K.evali(dHs) << endl;
exit(1);
}
else {
if (is_greater(subdet0,K.prec,&ct)) {
cout << "Original signature +++" << endl;
cout << " (this should not happen)" << endl;
cout << " det(H) num " << K.evali(dH) << endl;
cout << " subdet num " << K.evali(dHs) << endl;
exit(1);
}
else {
cerr << "Could not determine signature from intervals" << endl;
exit(1);
}
}
}
}
int NA_index = 0;
for (int j=0; j<other_roots.size(); j++) {
if (verbose) {
cout << "Galois conjugate #" << (j+1) << ":" << endl;
}
gen detj = _subst(makesequence(_subst(makesequence(dHpol,b__IDNT_e,other_roots[j]),&ct),b__IDNT_e,a__IDNT_e),&ct);
gen subdetj = _subst(makesequence(_subst(makesequence(dHspol,b__IDNT_e,other_roots[j]),&ct),b__IDNT_e,a__IDNT_e),&ct);
detj = _simplify(giac::expand(detj,&ct),&ct);
subdetj = _simplify(giac::expand(subdetj,&ct),&ct);
detj = _rem(makesequence(detj,p,a__IDNT_e),&ct);
subdetj = _rem(makesequence(subdetj,p,a__IDNT_e),&ct);
if (verbose) {
cout << "det(H) in a: " << detj << endl;
cout << "subdet in a: " << subdetj << endl;
}
detj = convert_interval(_subst(makesequence(detj,a__IDNT_e,gg),&ct),K.nd,&ct);
subdetj = convert_interval(_subst(makesequence(subdetj,a__IDNT_e,gg),&ct),K.nd,&ct);
if (verbose) {
cout << "det(H): " << detj << endl;
cout << "subdet: " << subdetj << endl;
}
if (is_greater(-K.prec,detj,&ct)) {
cout << " signature ++-" << endl;
NA_index++;
}
else {
if (is_greater(detj,K.prec,&ct)) {
if (is_greater(-K.prec,subdetj,&ct)) {
cout << " signature +--" << endl;
NA_index++;
}
else {
if (is_greater(subdetj,K.prec,&ct)) {
cout << " signature +++" << endl;
}
else {
cerr << "Could not determine signature from intervals" << endl;
exit(1);
}
}
}
}
}
cout << "Non-arithmeticity index: " << NA_index << endl;
if (NA_index==0) {
cout << "Sorry, this group is arithmetic." << endl;
}
else {
cout << "The group is NOT arithmetic, NA index " << NA_index << endl;
}
isarithmeticitychecked = true;
isarithmetic = (NA_index==0);
naindex = NA_index;
return (NA_index==0);
}
gen Polytope::lowerDegree(gen g){
gen res;
gen p = giac::expand(_poly2symb(makesequence(_pmin(g,&ct),z__IDNT_e),&ct),&ct);
gen co = _coeff(makesequence(p,z__IDNT_e),&ct);
gen de =_lcm(_denom(co,&ct),&ct);
p = _simplify(de*p,&ct);
if (_degree(makesequence(p,z__IDNT_e),&ct).val>1) {
gen j = rootof(p,&ct);
gen fa = _factors(makesequence(p,j),&ct);
bool fd = false;
for (int l=0; !fd && 2*l<(*fa._VECTptr).size(); l++) {
int d = _degree(makesequence(fa[2*l],z__IDNT_e),&ct).val;
if (d>1){
return g;
}
if (d==1) {
gen te = normal(-_coeff(makesequence(fa[2*l],z__IDNT_e,0),&ct)/_coeff(makesequence(fa[2*l],z__IDNT_e,1),&ct),&ct);
gen tet = normal(te-g,&ct);
fd = is_zero(tet,&ct);
if (fd) {
return te;
}
}
}
}
else {
return g;
}
return g;
}
bool Polytope::isPPower(gen M) {
bool fd = false;
int k=orderofp-1;
while (!fd && k>=0) {
gen N = M*Ppowers[k];
K.matred(N);
fd = K.isScalar(N);
k--;
}
return fd;
}
int Polytope::testPoint(gen V) {
// returns -1 if point is inside polytope, 0 if it is on boundary, +1 if outside.
// (for now, I will not check the boundary of the ball)
//
int k = 0;
bool foundzero = false;
while (k<faces.size()) {
gen te = Inn(V,faces[k].X0)*Inn(faces[k].X0,V) - Inn(V,faces[k].X1)*Inn(faces[k].X1,V);
K.red(te);
te = K.convertToReal(te);
int sg;
if (!K.checkSign(te,sg)){
cerr << "Trouble checking sign of equation (testing point inside polytope)" << endl;
exit(1);
}
else {
if (sg==0) {
foundzero = true;
}
else {
if (sg>0) {
return 1;
}
}
}
k++;
}
// if we get here, all equations are <=0, we are in polytope!
if (foundzero) {
// one equation is 0, the point may still not be in the boundary?
return 0;
}
else {
return -1;
}
}
bool Polytope::findMirror(gen M, gen &res) {
// cout << "Début findMirror" << endl;
if (verbose) {
cout << "Trying to compute mirror for: " << endl;
cout << "M=" << M << endl;
cout << "K.genasrootof=" << K.genasrootof << endl;
}
gen cpm0 = _charpoly(M,&ct);
vecteur cpm1;
for (int j=0; j<4; j++) {
gen tej = cpm0[j];
K.red(tej);
cpm1.push_back(_subst(makesequence(tej,x__IDNT_e,eval(K.genasrootof,&ct)),&ct));
}
gen var = u__IDNT_e;
// Used to be l__IDNT_e, I changed this to make t3S2 work :S
gen cpm = normal(_poly2symb(makesequence(cpm1,var),&ct),&ct);
/*
// gen Mn = normal(_subst(makesequence(M,x__IDNT_e,K.genasrootof),&ct),&ct);
// cout << "compute det and eval" << endl;
gen pon = _eval(_det(Mn - l__IDNT_e*K.Id,&ct),&ct);
// gen pon = ;
cout << "char pol: " << pon << endl;
cout << _charpoly(Mn,&ct);
*/
if (verbose) {
cout << "cpm=" << cpm << endl;
cout << "K.genasrootof: " << K.genasrootof << endl;
}
gen fan = _factors(makesequence(eval(cpm,&ct),K.genasrootof),&ct);
// gen fan = _factors(makesequence(cpm,l__IDNT_e,K.genasrootof),&ct);
// cout << _factor(makesequence(cpm,l__IDNT_e,K.genasrootof),&ct) << endl;
if (verbose) {
cout << "factors=" << fan << endl;
cout << "fan size: " << (*fan._VECTptr).size() << endl;
}
// for (int jj = 0; 2*jj<6; jj++) {
for (int jj = 0; 2*jj<(*fan._VECTptr).size(); jj++) {
// cout << "if" << endl;
if ( (_degree(makesequence(fan[2*jj],var),&ct).val==1 && (fan[2*jj+1]).val==1) || ( (fan[2*jj+1]).val==3)) {
if (verbose) {
cout << "Studying factor #" << jj << endl;
}
// cout << "huh?" << endl;
gen ev = _eval(normal(-_subst(makesequence(fan[2*jj],var,K.zeronumber),&ct)/_coeff(makesequence(fan[2*jj],var,1),&ct),&ct),&ct);
// changed to make Mostow G(4,0) work, hopefully this doesn't break anything...
if (verbose) {
cout << "ev=" << ev << endl;
}
// cout << "convert interval" << endl;
gen evi = convert_interval(ev,K.nd,&ct);
if (verbose) {
cout << "evi=" << evi << endl;
}
// cout << "pmin" << endl;
gen mpev = giac::expand(_poly2symb(makesequence(_pmin(ev,&ct),z__IDNT_e),&ct),&ct);
if (verbose) {
cout << "min pol of ev: " << mpev << endl;
}
gen evx;
if (! K.findInField(mpev,evi,evx)) {
cerr << "Trouble identifying eigenvalue in field" << endl;
exit(1);
}
if (verbose) {
cout << "eigenvalue in terms of x: " << evx << endl;
}
gen A = _simplify(M - evx*K.Id,&ct);
if (verbose) {
cout << "A before red: " << A << endl;
}
K.matred(A);
if (verbose) {
cout << "A after red: " << A << endl;
}
vector<int> inds;
vector<gen> lir;
for (int kk=0; kk<3; kk++) {
gen v0 = _row(makesequence(A,kk),&ct);
if (!is_zero(v0,&ct)) {
if (inds.size()==0) {
inds.push_back(kk);
lir.push_back(v0);
if (verbose) {
cout << " non-zero row (" << kk << "): " << v0 << endl;
}
}
else {
// if (!is_zero(v0,&ct) && inds.size()==1) {
bool tes = K.areDep(v0,lir[0]);
if (!tes) {
if (verbose){
cout << " indep non-zero row (" << kk << "): " << v0 << endl;
}
inds.push_back(kk);
}
else {
if (verbose){
cout << " following row (" << kk << ") is dependent on first one: " << v0 << endl;
}
}
}
}
}
if (inds.size()<2) {
cerr << "Trouble finding mirror, wrong rank" << endl;
exit(1);
}
gen mirr = _cross( makesequence( _row(makesequence(A,inds[0]),&ct), _row(makesequence(A,inds[1]),&ct)),&ct);
K.vectred(mirr);
res = mirr;
// cout << "mirr=" << mirr << endl;
// cout << "Fin findMirror" << endl;
return true;
}
}
// cout << "Fin findMirror" << endl;
return false;
}
void Polytope::reduce_degree_vect(gen &x0) {
for (int j=0; j<(*x0._VECTptr).size(); j++) {
reduce_degree((*x0._VECTptr)[j]);
}
}
void Polytope::reduce_degree_mat(gen &x0) {
for (int j=0; j<(*x0._VECTptr).size(); j++) {
reduce_degree_vect((*x0._VECTptr)[j]);
}
}
void Polytope::reduce_degree(gen &x0) {
// cout << "reduce_degree" << endl;
// cout << "evalf: " << _evalf(x0,&ct) << endl;
// cout << "convert interval: " << convert_interval(x0,K.nd,&ct) << endl;
// Removed the denom on Dec 1 2019, to fix s4c groups, but this was useful when rational numbers occurred...
gen den = _denom(x0,&ct);
// gen den = K.onenumber;
// cout << "den=" << den << endl;
gen x = normal(x0*den,&ct);
// cout << "x=" << x << endl;
gen mpx = giac::expand(_poly2symb(makesequence(_pmin(eval(x,&ct),&ct),a__IDNT_e),&ct),&ct);
// cout << "min pol: " << mpx << endl;
// cout << "complex roots: " << _complexroot(makesequence(mpx,K.prec),&ct) << endl;
// cout << " (degree " << _degree(makesequence(mpx,a__IDNT_e),&ct).val << ")" << endl;
if (_degree(makesequence(mpx,a__IDNT_e),&ct).val>1) {
//mpx need not be irreducible, not sure if this could ever be a problem...
gen gg = rootof(mpx,&ct);
// cout << "gg=" << gg << endl;
gen fad = _factors(makesequence(mpx,gg),&ct);
// cout << "fad=" << fad << endl;
bool found = false;
int k = 0;
int nk = (*fad._VECTptr).size()/2;
while (!found && k<nk) {
// cout << "factor " << fad[2*k] << endl;
int dfd = _degree(makesequence(fad[2*k],a__IDNT_e),&ct).val;
// cout << "dfd=" << dfd << endl;
if (dfd==1) {
// cout << "using factor " << fad[2*k] << endl;
gen te = normal(-_subst(makesequence(fad[2*k],a__IDNT_e,K.zeronumber),&ct)/_diff(makesequence(fad[2*k],a__IDNT_e),&ct),&ct);
// cout << "te=" << te << endl;
gen tec = normal(te-x,&ct);
// cout << "tec=" << tec << endl;
// cout << "evalf(tec): " << _evalf(tec,&ct) << endl;
// cout << "convert_interval(tec): " << convert_interval(tec,K.nd,&ct) << endl;
found = operator_equal(tec,K.zeronumber,&ct);
if (found) {
x0 = eval(te/den,&ct);
// cout << "done" << endl;
// cout << "evalf: " << _evalf(x0,&ct) << endl;
}
else {
// cout << tec << endl;
// cout << "non-zero (" << _evalf(tec,&ct) << ")" << endl;
cout << "non-zero (" << convert_interval(tec,K.nd,&ct) << ")" << endl;
}
}
k++;
}
if (!found) {
cout << "FAIL" << endl;
}
}
}
void Polytope::normalize_vector(gen &v) {
// will be used with vectors whose entries are complex intervals
bool fd = false;
int j = -1;
while (!fd && j<2) {
j++;
gen ns = re(v[j],&ct)*re(v[j],&ct) + im(v[j],&ct)*im(v[j],&ct);
fd = is_greater(_left(ns,&ct),K.prec,&ct);
}
if (fd) {
v = v/v[j];
}
}
bool Polytope::my_jordan_knowing_linear_order_alt(gen M, int o, vecteur &bas, vecteur &evs) {
bool found = false;
bool problem = false;
int count = 0;
int savend = K.nd;
gen Mi = convert_interval(_subst(makesequence(M,x__IDNT_e,K.xvi),&ct),K.nd,&ct);
gen Hi = convert_interval(_subst(makesequence(H,x__IDNT_e,K.xvi),&ct),K.nd,&ct);
gen u = rootof(_cyclotomic(o,&ct),&ct);
gen uj = K.onenumber;
vector<int> neg_powers;
vector<int> pos_powers;
vecteur bas_neg;
vecteur bas_pos;
for (int j=0; j<o; j++) {
gen uji = convert_interval(uj,K.nd,&ct);
// cout << "uji=" << uji << endl;
gen A = Mi-uji*convert_interval(K.Id,K.nd,&ct);
gen di = A[0][0] * A[1][1] * A[2][2] + A[0][1] * A[1][2] * A[2][0] + A[1][0] * A[2][1] * A[0][2]
- A[2][0] * A[1][1] * A[0][2] - A[1][0] * A[0][1] * A[2][2] - A[2][1] * A[1][2] * A[0][0];
// cout << "di=" << di << endl;
gen dins = re(di,&ct)*re(di,&ct) + im(di,&ct)*im(di,&ct);
// cout << "|di|^2=" << dins << endl;
/* if (is_greater(_left(dins,&ct),K.zeronumber,&ct)) {
cout << "Power " << j << " is definitely not candidate eigenvalue" << endl;
}*/
if (is_greater(K.zeronumber,_left(dins,&ct),&ct)) {
if (verbose) {
cout << "Power " << j << " may well be an eigenvalue" << endl;
}
gen r1 = _row(makesequence(A,0),&ct);
gen r2 = _row(makesequence(A,1),&ct);
gen r3 = _row(makesequence(A,2),&ct);
gen v12 = _cross(makesequence(r1,r2),&ct);
gen v23 = _cross(makesequence(r2,r3),&ct);
gen v31 = _cross(makesequence(r3,r1),&ct);
gen nz12 = convert_interval(K.zeronumber,K.nd,&ct);
for (int l=0; l<3; l++) {
nz12 = nz12 + re(v12[l],&ct)*re(v12[l],&ct) + im(v12[l],&ct)*im(v12[l],&ct);
}
if (verbose) {
cout << "nz12=" << nz12 << endl;
}
if (is_greater(_left(nz12,&ct),K.prec,&ct)) {
// v12 is eigenvector
normalize_vector(v12);
gen v12c = conj(v12,&ct);
gen ns12 = re(v12c*Hi*v12,&ct);
if (verbose) {
cout << "square norm of eigenvector: " << ns12 << endl;
}
if (is_greater(_left(ns12,&ct),K.prec,&ct)) {
pos_powers.push_back(j);
bas_pos.push_back(v12);
}
else {
if (is_greater(-K.prec,_right(ns12,&ct),&ct)) {
neg_powers.push_back(j);
bas_neg.push_back(v12);
}
else {
cout << "Trouble determining sign of eigenvector" << endl;
cout << " (maybe higher precision would help)" << endl;
problem = true;
}
}
}
else {
gen nz23 = convert_interval(K.zeronumber,K.nd,&ct);
for (int l=0; l<3; l++) {
nz23 = nz23 + re(v23[l],&ct)*re(v23[l],&ct) + im(v23[l],&ct)*im(v23[l],&ct);
}
if (verbose) {
cout << "nz23=" << nz23 << endl;
}
if (is_greater(_left(nz23,&ct),K.prec,&ct)) {
// v23 is eigenvector
normalize_vector(v23);
gen v23c = conj(v23,&ct);
gen ns23 = re(v23c*Hi*v23,&ct);
if (verbose) {
cout << "square norm of eigenvector: " << ns23 << endl;
}
if (is_greater(_left(ns23,&ct),K.prec,&ct)) {
pos_powers.push_back(j);
bas_pos.push_back(v23);
}
else {
if (is_greater(-K.prec,_right(ns23,&ct),&ct)) {
neg_powers.push_back(j);
bas_neg.push_back(v23);
}
else {
cout << "Trouble determining sign of eigenvector" << endl;
cout << " (maybe higher precision would help)" << endl;
return false;
}
}
}
else {
gen nz31 = convert_interval(K.zeronumber,K.nd,&ct);
for (int l=0; l<3; l++) {
nz31 = nz31 + re(v31[l],&ct)*re(v31[l],&ct) + im(v31[l],&ct)*im(v31[l],&ct);
}
if (verbose) {
cout << "nz31=" << nz31 << endl;
}
if (is_greater(_left(nz31,&ct),K.prec,&ct)) {
// v31 is eigenvector
normalize_vector(v31);
gen v31c = conj(v31,&ct);
gen ns31 = re(v31c*Hi*v31,&ct);
if (verbose) {
cout << "square norm of eigenvector: " << ns31 << endl;
}
if (is_greater(_left(ns31,&ct),K.prec,&ct)) {
pos_powers.push_back(j);
bas_pos.push_back(v31);
}
else {
if (is_greater(-K.prec,_right(ns31,&ct),&ct)) {
neg_powers.push_back(j);
bas_neg.push_back(v31);
}
else {
cout << "Trouble determining sign of eigenvector" << endl;
cout << " (maybe higher precision would help)" << endl;
return false;
}
}
}
}
}
}
uj = normal(u*uj,&ct);
}
if (verbose) {
cout << "powers for negative vectors: " << neg_powers << endl;
cout << "powers for positive vectors: " << pos_powers << endl;
}
if (pos_powers.size()!=2 || neg_powers.size()!=1) {
cout << "Wrong signature" << endl;
return false;
}
// will return rational numbers encoding roots of unity
evs.push_back(neg_powers[0]*K.onenumber/o);
evs.push_back(pos_powers[0]*K.onenumber/o);
evs.push_back(pos_powers[1]*K.onenumber/o);
// and intervals for corresponding eigenvectors (negative vector first)
bas.push_back(bas_neg[0]);
bas.push_back(bas_pos[0]);
bas.push_back(bas_pos[1]);
int an1, an2;
an1 = (pos_powers[0]-neg_powers[0]);
if (2*an1<-o) {
an1 = an1+o;
}
an2 = (pos_powers[1]-neg_powers[0]);
if (2*an2<-o) {
an2 = an2+o;
}
cout << "Angles: " << an1 << "/" << o << ", " << an2 << "/" << o << endl;
return true;
}
bool Polytope::my_jordan_knowing_linear_order(gen M, int o, vecteur &bas, vecteur &evs) {
// gen Mro = evalWordAsRootOf(w);
gen Mro = normal(eval(_subst(makesequence(M,x__IDNT_e,K.genasrootof),&ct),&ct),&ct);
// gen Mro = eval(_subst(makesequence(M,x__IDNT_e,K.genasrootof),&ct),&ct);
gen cham = _charpoly(M,&ct);
// gen cham = K.det(M-l__IDNT_e*K.Id);
if (verbose) {
cout << "cham=" << cham << endl;
}
gen co0 = cham[3];
// gen co0 = _subst(makesequence(cham,l__IDNT_e,0),&ct);
K.red(co0);
if (verbose) {
cout << "co0 in x: " << co0 << endl;
cout << "will substitute x to K.genasrootof=" << K.genasrootof << endl;
cout << " eval(K.genasrootof)=" << eval(K.genasrootof,&ct) << endl;
}
co0 = normal(_subst(makesequence(co0,x__IDNT_e,eval(K.genasrootof,&ct)),&ct),&ct);
if (verbose) {
cout << "co0=" << co0 << endl;
cout << " (" << _evalf(co0,&ct) << ")" << endl;
}
/* reduce_degree(co0);
if (verbose) {
cout << "co0 after reduce degree=" << co0 << endl;
cout << " (" << _evalf(co0,&ct) << ")" << endl;
}*/
gen co1 = cham[2];
// gen co1 = _coeff(makesequence(cham,l__IDNT_e,1),&ct);
K.red(co1);
if (verbose) {
cout << "co1 in x: " << co1 << endl;
}
co1 = normal(_subst(makesequence(co1,x__IDNT_e,eval(K.genasrootof,&ct)),&ct),&ct);
if (verbose) {
cout << "co1=" << co1 << endl;
cout << " (" << _evalf(co1,&ct) << ")" << endl;
}
/* reduce_degree(co1);
if (verbose) {
cout << "co1 after reduce degree=" << co1 << endl;
cout << " (" << _evalf(co1,&ct) << ")" << endl;
}*/
gen co2 = cham[1];
// gen co2 = _coeff(makesequence(cham,l__IDNT_e,2),&ct);
K.red(co2);
if (verbose) {
cout << "co2 in x: " << co2 << endl;
}
co2 = normal(_subst(makesequence(co2,x__IDNT_e,eval(K.genasrootof,&ct)),&ct),&ct);
if (verbose) {
cout << "co2=" << co2 << endl;
cout << " (" << _evalf(co2,&ct) << ")" << endl;
}
/* reduce_degree(co2);
if (verbose) {
cout << "co2 after reduce degree=" << co2 << endl;
cout << " (" << _evalf(co2,&ct) << ")" << endl;
}*/
gen co0_num = _evalf(co0,&ct);
gen co1_num = _evalf(co1,&ct);
gen co2_num = _evalf(co2,&ct);
if (verbose) {
cout << "co0_num=" << co0_num << endl;
cout << "co1_num=" << co1_num << endl;
cout << "co2_num=" << co2_num << endl;
}
gen rough_eps = 1e-4;
vecteur bas_rough, evs_rough;
gen u = rootof(_cyclotomic(o,&ct),&ct);
if (verbose) {
cout << "o=" << o << endl;
cout << "u=" << u << endl;
}
gen uj = K.onenumber;
int j = 0;
while (j<o && evs_rough.size()<3){
// for (int j=0; j<o; j++) {
// cout << "j=" << j << endl;
// cout << "num val..." << endl;
gen ujn = _evalf(uj,&ct);
// cout << "uj=" << uj << endl;
// cout << "ujn=" << ujn << endl;
// cout << "... done num val" << endl;
gen d1n = ujn+co2_num;
// cout << "d1n=" << d1n << endl;
gen d2n = d1n*ujn+co1_num;
// cout << "d2n=" << d2n << endl;
gen d3n = d2n*ujn+co0_num;
// cout << "d3n=" << d3n << endl;
gen djn = abs(d3n,&ct);
if (verbose) {
cout << "computed num val for dj: " << djn << endl;
}
if (is_greater(rough_eps,djn,&ct)) {
if (verbose) {
cout << "doing exact comps" << endl;
cout << "j=" << j << endl;
cout << "uj=" << uj << endl;
}
gen d1 = normal(eval(uj+co2,&ct),&ct);
/* gen d1red;
if (!reduce_degree(d1,d1red)) {
cout << "Trouble reducing degree" << endl;
}
else {
d1 = d1red;
}*/
// cout << "d1=" << d1 << endl;
// cout << "d1n=" << d1n << endl;
gen d2 = normal(eval(d1*uj+co1,&ct),&ct);
/* gen d2red;
if (!reduce_degree(d2,d2red)) {
cout << "Trouble reducing degree" << endl;
}
else {
d2 = d2red;
}*/
// cout << "d2=" << d2 << endl;
// cout << "d2n=" << d2n << endl;
gen d = normal(eval(d2*uj+co0,&ct),&ct);
// reduce_degree(d);
cout << "d=" << d << endl;
cout << "eval(d)=" << eval(d,&ct) << endl;
cout << "evalf(d)=" << _evalf(d,&ct) << endl;
if (verbose) {
cout << "d contains j?" << contains(d,j__IDNT_e) << endl;
cout << "subst j gar: " <<_subst(makesequence(d,j__IDNT_e,K.genasrootof),&ct) << endl;
cout << "normal subst j gar: " << normal(_subst(makesequence(d,j__IDNT_e,K.genasrootof),&ct),&ct) << endl;
// d = _subst(makesequence(d,j__IDNT_e,K.genasrootof),&ct);
// d = normal(d,&ct);
cout << "d=" << d << endl;
cout << " (" << _evalf(d,&ct) << ")" << endl;
}
// cout << "d3n=" << d3n << endl;
if (operator_equal(d,K.zeronumber,&ct)) {
cout << "j=" << j << ", gives eigenvalue" << endl;
cout << "uj=" << uj << endl;
gen A = recursive_normal(eval(Mro-uj*K.Id,&ct),&ct);
if (verbose) {
cout << "Will now try and reduce degree for matrix before computing kernel" << endl;
}
// reduce_degree_mat(A);
if (verbose) {
cout << "A=" << A << endl;
// cout << "det(A)=" << _det(A,&ct) << endl;
}
/* gen ke;
if (!my_giac_kernel(A,ke)) {
cout << "Trouble computing kernel (with my_giac_kernel)" << endl;
cout << " (maybe the kernel was not 1-dimensional)" << endl;
return false;
}
else {
cout << "Should be close to 0 vector: " << convert_interval(A,K.nd,&ct)*convert_interval(ke,K.nd,&ct) << endl;
}
evs_rough.push_back(uj);
bas_rough.push_back(eval(ke,&ct));*/
gen ke = _ker(A,&ct);
if (verbose) {
cout << "ke=" << ke << endl;
}
int kes = (*ke._VECTptr).size();
if (verbose) {
cout << "kes=" << kes << endl;
}
if (kes==1) {
cout << "Should be close to 0 vector: " << convert_interval(A,K.nd,&ct)*convert_interval(ke[0],K.nd,&ct) << endl;
evs_rough.push_back(uj);
bas_rough.push_back(eval(ke[0],&ct));
// cout << "bas_rough.size(): " << bas_rough.size() << endl;
}
else {
if (kes>1) {
cout << "Matrix has a repeated eigenvalue" << endl;
exit(1);
}
}
}
// else {
// cout << "power " << j << " does not give an eigenvalue" << endl;
// }
}
// else {
// cout << "Did not even try exact computation, this seemed nonzero:" << endl;
// cout << "djn=" << djn << endl;
uj = normal(eval(uj*u,&ct),&ct);
// cout << "uj=" << uj << endl;
j++;
}
if (evs_rough.size()==3) {
if (verbose) {
cout << "Found 3 eigenvectors, will now order them so the first one has negative square-norm.." << endl;
}
vector<int> inds_neg, inds_pos;
for (int j=0; j<3; j++) {
if (verbose) {
cout << "Computing square norm of " << bas_rough[j] << endl;
}
gen cc = normal(eval(conj(bas_rough[j],&ct),&ct),&ct);
if (verbose) {
cout << "cc=" << cc << endl;
}
gen te = normal(eval(cc*H_rootof*bas_rough[j],&ct),&ct);
if (verbose) {
cout << "te=" << te << endl;
}
gen ter0 = convert_interval(te,K.nd,&ct);
if (verbose) {
cout << "ter0=" << ter0 << endl;
}
gen ter = re(ter0,&ct);
if (verbose) {
cout << "ter=" << ter << endl;
}
if (is_greater(_left(ter,&ct),K.zeronumber,&ct)){
if (verbose) {
cout << " (positive)" << endl;
}
inds_pos.push_back(j);
}
else {
if (is_greater(K.zeronumber,_right(ter,&ct),&ct)){
if (verbose) {
cout << " (negative)" << endl;
}
inds_neg.push_back(j);
}
else {
// interval contains 0
cout << "Interval contains 0, should be able to overcome this difficulty" << endl;
cout << " (not implemented yet)" << endl;
return false;
}
}
}
if (inds_pos.size()!=2 || inds_neg.size()!=1){
cout << "Wrong signature" << endl;
return false;
}
else {
if (verbose) {
cout << " ... done reordering" << endl;
}
evs.push_back(evs_rough[inds_neg[0]]);
evs.push_back(evs_rough[inds_pos[0]]);
evs.push_back(evs_rough[inds_pos[1]]);
bas.push_back(bas_rough[inds_neg[0]]);
bas.push_back(bas_rough[inds_pos[0]]);
bas.push_back(bas_rough[inds_pos[1]]);
return true;
}
}
else {
cout << "Trouble diagonalizing matrix" << endl;
return false;
}
}
bool Polytope::my_giac_are_dep(gen v, gen w) {
gen d12 = normal(eval(v[0]*w[1]-v[1]*w[0],&ct),&ct);
if (!operator_equal(d12,K.zeronumber,&ct)) {
return false;
}
else {
gen d23 = normal(eval(v[1]*w[2]-v[2]*w[1],&ct),&ct);
if (!operator_equal(d23,K.zeronumber,&ct)) {
return false;
}
else {
gen d13 = normal(eval(v[0]*w[2]-v[2]*w[0],&ct),&ct);
if (!operator_equal(d13,K.zeronumber,&ct)) {
return false;
}
else {
return true;
}
}
}
}
bool Polytope::my_giac_kernel(gen M, gen &res) {
// method to avoid giac's kernel, only valid when M is a matrix of rootofs, no x allowed!
//
// returns true only if kernel is 1-dimensional
//
// include reducing the degree (this may not be a good idea either...)
vecteur nonzerorows;
/* gen m11 = M[0][0];
gen mred;
if (reduce_degree(m11,mred)) {
m11 = mred;
}
gen m12 = M[0][1];
if (reduce_degree(m12,mred)) {
m12 = mred;
}
gen m13 = M[0][2];
if (reduce_degree(m13,mred)) {
m13 = mred;
}
vecteur row1v;
row1v.push_back(m11);
row1v.push_back(m12);
row1v.push_back(m13);
gen row1 = gen(row1v);*/
gen row1 = _row(makesequence(M,0),&ct);
if (!operator_equal(row1,K.zerovector,&ct)) {
nonzerorows.push_back(row1);
}
/* gen m21 = M[1][0];
if (reduce_degree(m21,mred)) {
m21 = mred;
}
gen m22 = M[1][1];
if (reduce_degree(m22,mred)) {
m22 = mred;
}
gen m23 = M[1][2];
if (reduce_degree(m23,mred)) {
m23 = mred;
}
vecteur row2v;
row2v.push_back(m21);
row2v.push_back(m22);
row2v.push_back(m23);
gen row2 = gen(row2v);*/
gen row2 = _row(makesequence(M,1),&ct);
if (!operator_equal(row2,K.zerovector,&ct)) {
// still want to test if it is independent from first one
if (nonzerorows.size()==0) {
nonzerorows.push_back(row2);
}
else {
if (!my_giac_are_dep(row2,nonzerorows[0])) {
nonzerorows.push_back(row2);
}
}
}
/* gen m31 = M[2][0];
if (reduce_degree(m31,mred)) {
m31 = mred;
}
gen m32 = M[2][1];
if (reduce_degree(m32,mred)) {
m32 = mred;
}
gen m33 = M[2][2];
if (reduce_degree(m33,mred)) {
m33 = mred;
}
vecteur row3v;
row3v.push_back(m31);
row3v.push_back(m32);
row3v.push_back(m33);
gen row3 = gen(row3v);*/
gen row3 = _row(makesequence(M,2),&ct);
if (!operator_equal(row3,K.zerovector,&ct)) {
if (nonzerorows.size()==0) {
nonzerorows.push_back(row3);
}
else {
if (nonzerorows.size()==1) {
if (!my_giac_are_dep(row3,nonzerorows[0])) {
nonzerorows.push_back(row3);
}
}
// otherwise, two independent vectors, can use cross-product
}
}
cout << "nonzerorows.size(): " << nonzerorows.size() << endl;
if (nonzerorows.size()==2) {
gen v = nonzerorows[0];
gen w = nonzerorows[1];
vecteur u;
u.push_back(normal(v[1]*w[2]-v[2]*w[1],&ct));
u.push_back(normal(v[2]*w[0]-v[0]*w[2],&ct));
u.push_back(normal(v[0]*w[1]-v[1]*w[0],&ct));
gen ke0 = gen(u);
cout << "ke0=" << ke0 << endl;
bool fd = false;
int k=-1;
while (!fd && k<2) {
k++;
fd = !operator_equal(ke0[k],K.zeronumber,&ct);
}
if (!fd) {
cout << "Trouble, cross-product should not be zero" << endl;
return false;
}
else {
res = normal(ke0/ke0[k],&ct);
/* cout << "Will now try and reduce degree" << endl;
vecteur alt;
for (int j=0; j<3; j++) {
if (j==k) {
alt.push_back(res[j]);
}
else {
gen te;
if (reduce_degree(res[j],te)) {
alt.push_back(te);
}
else {
alt.push_back(res[j]);
}
}
}
res = gen(alt);
cout << "kernel gen-d by: " << res << endl;*/
return true;
}
}
else {
return false;
}
}
bool Polytope::my_jordan(gen M, vecteur &bas, vecteur &evs) {
cout << "start my_jordan" << endl;
gen poP = K.det(M-l__IDNT_e*K.Id);
// cout << "Characteristic polynomial of poP: " << poP << endl;
// cout << "genasrootof=" << K.genasrootof << endl;
vecteur eqs_pop;
eqs_pop.push_back(K.minpol);
eqs_pop.push_back(poP);
vecteur var_pop;
var_pop.push_back(x__IDNT_e);
var_pop.push_back(l__IDNT_e);
// cout << "eqs_pop=" << eqs_pop << endl;
// cout << "var_pop=" << var_pop << endl;
cout << "calcul rur" << endl;
gen gb = _gbasis(makesequence(eqs_pop,var_pop,change_subtype(_RUR_REVLEX,_INT_GROEBNER)),&ct);
cout << "done with rur" << endl;
if (gb[0]==-4) {
gen varpar = lidnt(gb[2])[0];
gen fa0 = _factors(gb[2],&ct);
cout << "computed factors of parameter polynomial" << endl;
int ng = (*fa0._VECTptr).size()/2;
vecteur pars_restricted;
for (int k=0; k<ng; k++) {
if (_degree(fa0[2*k],&ct)>0) {
// if (verbose) {
cout << "fa0[2*k]=" << fa0[2*k] << endl;
// }
gen te = rootof(fa0[2*k],&ct);
cout << "splitting factor" << endl;
gen fa = _factors(makesequence(fa0[2*k],te),&ct);
cout << "done splitting" << endl;
vecteur pars;
for (int j = 0; 2*j<(*fa._VECTptr).size(); j++) {
gen dj = _degree(fa[2*j],&ct);
// cout << "computing parameter " << j << endl;
if (dj.val==1) {
gen num = eval(_subst(makesequence(fa[2*j],varpar,K.zeronumber),&ct),&ct);
// cout << "num=" << num << endl;
gen den = _diff(fa[2*j],&ct);
// cout << "den=" << den << endl;
gen sol = normal(-num/den,&ct);
// cout << "sol=" << sol << endl;
pars.push_back(sol);
/* gen sol_red;
if (reduce_degree(sol,sol_red)) {
pars.push_back(sol_red);
}
else {
pars.push_back(sol);
}*/
}
// cout << " ... done" << endl;
}
// cout << "Found " << pars.size() << " params" << endl;
for (int j=0; j<pars.size(); j++) {
// cout << "using parameter " << j << endl;
gen num = normal( _subst(makesequence(gb[4],varpar,pars[j]),&ct), &ct);
// cout << "num=" << num << endl;
gen den = normal( _subst(makesequence(gb[3],varpar,pars[j]),&ct), &ct);
// cout << "den=" << den << endl;
te = normal( (num/den) - K.genasrootof, &ct);
// cout << "comparing with genas rootof... what counts is whether this is zero:" << te << endl;
if (operator_equal(te,K.zeronumber,&ct)) {
cout << "pars[" << j << "]=" << pars[j] << endl;
cout << _evalf(pars[j],&ct) << endl;
pars_restricted.push_back(pars[j]);
}
}
}
}
if (pars_restricted.size()==3) {
vecteur evals;
cout << "Computing eigenvalues" << endl;
for (int j=0; j<pars_restricted.size(); j++) {
gen num = normal(_subst(makesequence(gb[5],varpar,pars_restricted[j]),&ct),&ct);
cout << "num=" << num << endl;
gen den = normal(_subst(makesequence(gb[3],varpar,pars_restricted[j]),&ct),&ct);
cout << "den=" << den << endl;
gen evj = normal(num/den,&ct);
reduce_degree(evj);
cout << "e-value " << j << ": " << evj << endl;
evals.push_back( evj );
}
vecteur cols;
for (int j=0; j<evals.size(); j++) {
cout << "Computing kernel for eigenvalue #" << j << endl;
gen A = recursive_normal(eval(_subst(makesequence(M,x__IDNT_e,K.genasrootof),&ct) - evals[j]*K.Id,&ct),&ct);
if (verbose) {
cout << "A:=" << A << endl;
}
gen ke = _ker(A,&ct);
// if (verbose) {
cout << "ke:=" << ke << endl;
// }
if ((*ke._VECTptr).size()!=1) {
cout << "Matrix has a repeated eigenvalue, this is not handled by my_jordan (yet)" << endl;
return false;
}
else {
gen ke2 = ke[0];
if (operator_equal(ke2[0],K.zeronumber,&ct)) {
if (operator_equal(ke2[1],K.zeronumber,&ct)) {
if (operator_equal(ke2[2],K.zeronumber,&ct)) {
cerr << "Trouble, kernel basis vector should not be zero!" << endl;
exit(1);
}
else {
ke2 = normal(ke2/ke2[2],&ct);
}
}
else {
ke2 = normal(ke2/ke2[1],&ct);
}
}
else {
ke2 = normal(ke2/ke2[0],&ct);
}
cout << "ke2=" << ke2 << endl;
cols.push_back(ke2);
}
}
vector<int> inds_neg, inds_pos;
for (int j=0; j<3; j++) {
// if (verbose) {
cout << "Computing square norm of " << cols[j] << endl;
// }
gen cc = normal(conj(cols[j],&ct),&ct);
// if (verbose) {
cout << "cc=" << cc << endl;
// }
gen te = simplify(normal(cc*H_rootof*cols[j],&ct),&ct);
if (verbose) {
cout << "te=" << te << endl;
}
gen ter0 = convert_interval(te,K.nd,&ct);
cout << "ter0=" << ter0 << endl;
gen ter = re(ter0,&ct);
// if (verbose) {
cout << "ter=" << ter << endl;
// }
if (is_greater(_left(ter,&ct),K.zeronumber,&ct)){
// if (verbose) {
cout << " (positive)" << endl;
// }
inds_pos.push_back(j);
}
else {
if (is_greater(K.zeronumber,_right(ter,&ct),&ct)){
// if (verbose) {
cout << " (negative)" << endl;
// }
inds_neg.push_back(j);
}
else {
// interval contains 0
cout << "Interval contains 0, should be able to overcome this difficulty" << endl;
cout << " (not implemented yet)" << endl;
return false;
}
}
}
if (inds_pos.size()!=2 || inds_neg.size()!=1){
cout << "Wrong signature" << endl;
return false;
}
vecteur cols2;
cols2.push_back(cols[inds_neg[0]]);
cols2.push_back(cols[inds_pos[0]]);
cols2.push_back(cols[inds_pos[1]]);
gen keke = gen(cols2);
gen U = K.transpose(keke);
// First column of U is the fixed point in the ball
for (int j=0; j<(*U._VECTptr).size(); j++) {
bas.push_back(U[j]);
}
// bas = U;
vecteur evv;
evv.push_back(evals[inds_neg[0]]);
evv.push_back(evals[inds_pos[0]]);
evv.push_back(evals[inds_pos[1]]);
gen kekeke = gen(evv);
evs = evv;
return true;
}
else {
cout << "Found " << pars_restricted.size() << " e-values" << endl;
cout << "Not obvious how to express eigenvalues as rootof" << endl;
return false;
}
}
else {
cout << "Trouble splitting characteristic polynomial (in my_jordan)" << endl;
return false;
}
}
string Polytope::convert_time(long double x) {
int hours = floor(x/(60*60));
int mins = floor((x-60*60*hours)/60.0);
int secs = floor((x-60*60*hours-60*mins));
string res;
stringstream ss;
if (hours>0) {
ss << hours << "h";
}
if (mins>0) {
ss << mins << "m";
}
ss << secs << "s" << endl;
return ss.str();
}