├── README.md ├── benchmark ├── bench_elimination.m ├── bench_matrixPartitioning.m └── bench_polynomialGenerator.m ├── gbsMacaulay ├── .gitignore ├── calc.bat └── code_template.m2 ├── generator ├── @Zp │ ├── InvZp.m │ ├── Zp.m │ ├── char.m │ ├── diff.m │ ├── display.m │ ├── double.m │ ├── minus.m │ ├── mldivide.m │ ├── mpower.m │ ├── mrdivide.m │ ├── mtimes.m │ └── plus.m ├── CodeTemplates │ ├── CodeGen_Maple_F4.m │ ├── CodeGen_Maple_systematic.m │ ├── CodeGen_Matlab_F4.m │ └── CodeGen_Matlab_systematic.m ├── F4 │ ├── F4_SelFirst.m │ └── F4_SelNormal.m ├── benchmark │ ├── computeSolutionDifference.m │ ├── generateInputData.m │ ├── renderHistogram.m │ ├── validateWithCorrectSolution.m │ └── validateZeroPolynomials.m ├── gbs_Benchmark.m ├── gbs_BuildActionMatrix.m ├── gbs_CheckActionMatrixConditions.m ├── gbs_CreateCode.m ├── gbs_DBGExport.m ├── gbs_ExportMapleCode.m ├── gbs_ExportMatlabCode.m ├── gbs_GeneratePolynomials_F4.m ├── gbs_GeneratePolynomials_systematic.m ├── gbs_GenerateSolver.m ├── gbs_GetVariablesIdx.m ├── gbs_InitConfig.m ├── gbs_MatrixPartitioning.m ├── gbs_ParseAlgebraB.m ├── gbs_ParseEquations.m ├── gbs_PreparePolySystemCoefsMatrix.m ├── gbs_RandomInstance.m ├── gbs_RandomInstanceZp.m ├── gbs_RemoveRedundant.m ├── gbs_RemoveUnnecessary_fixed.m ├── gbs_RemoveUnnecessary_nonfixed.m ├── gbs_ResetFromLog.m ├── gbs_findAlgB_macaulay.m ├── gbs_findAlgB_maple.m ├── helpers │ ├── CreateSubstBlock.m │ ├── EquationModulus.m │ ├── ExtractMonomials.m │ ├── GenerateMonomials.m │ ├── GetDivisors.m │ ├── GetMonomialOrder.m │ ├── GetMonomialsCnt.m │ ├── Monomial_PerformSubst.m │ ├── Monomial_degree.m │ ├── Monomial_grevlexorder.m │ ├── MonomialsDegree.m │ ├── Monomials_order.m │ ├── ReadTemplate.m │ ├── ReorderMonomials.m │ ├── c2s.m │ ├── gbs_Matrix.m │ ├── gbs_Vector.m │ ├── gjzpsp.c │ ├── gjzpsp.mexa64 │ ├── gjzpsp.mexw32 │ ├── gjzpsp.mexw64 │ └── l2s.m └── utils │ └── subfig.m ├── installation.txt ├── license.txt ├── minimalProblems ├── ku9pt.m ├── rolling_shutter_generator_linear_I_planar.m ├── sw5pt.m ├── sw6pt.m └── test.m ├── prerequisites ├── PaToH │ ├── patoh-Linux-i386.tar.gz │ ├── patoh-Linux-x86_64.tar.gz │ └── patoh-matlab.tar.gz └── macaulay2-0.9.2-3.msi ├── setpaths.m └── solvers └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | Automatic generator 2 | ===== 3 | 4 | This software package contains Groebner basis solvers generator as described in paper: 5 | 6 | Kukelova Z., Bujnak M., Pajdla T., Automatic Generator of Minimal Problem Solvers, ECCV 2008, Marseille, France, October 12-18, 2008 7 | -------------------------------------------------------------------------------- /benchmark/bench_elimination.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 2 | % 3 | % Benchmark templates for benchmarking on elimination and multi elimination 4 | % solvers. 5 | 6 | function [ret] = bench_elimination(cfg) 7 | 8 | % generate MATLAB code only 9 | cfg.exportCode = {'matlab'}; 10 | % use systematic generator 11 | cfg.PolynomialsGenerator = 'systematic'; 12 | 13 | % one elimination solver 14 | ret{1}.info = 'One elimination solver.'; 15 | ret{1}.abbrev = 'gjstep_0'; 16 | ret{1}.cfg = cfg; 17 | ret{1}.cfg.PolynomialsGeneratorCfg.GJstep = 0; 18 | 19 | % multi elimination solver - elimination at each total degree enlargement 20 | ret{2}.info = 'Multi elimination solver, elimination at each total degree enlargement.'; 21 | ret{2}.abbrev = 'gjstep_1'; 22 | ret{2}.cfg = cfg; 23 | ret{2}.cfg.PolynomialsGeneratorCfg.GJstep = 1; 24 | 25 | % multi elimination solver - elimination at each second total degree enlargement 26 | ret{3}.info = 'Multi elimination solver, elimination at each second total degree enlargement.'; 27 | ret{3}.abbrev = 'gjstep_2'; 28 | ret{3}.cfg = cfg; 29 | ret{3}.cfg.PolynomialsGeneratorCfg.GJstep = 2; 30 | 31 | end 32 | -------------------------------------------------------------------------------- /benchmark/bench_matrixPartitioning.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 2 | % 3 | % Benchmark templates for benchmarking the matrix partitioning. 4 | 5 | function [ret] = bench_matrixPartitioning(cfg) 6 | 7 | % generate MATLAB code only 8 | cfg.exportCode = {'matlab'}; 9 | % use systematic generator 10 | cfg.PolynomialsGenerator = 'systematic'; 11 | cfg.PolynomialsGeneratorCfg.GJstep = 1; 12 | 13 | % no partitioning 14 | ret{1}.info = 'No matrix partitioning.'; 15 | ret{1}.abbrev = 'none'; 16 | ret{1}.cfg = cfg; 17 | ret{1}.cfg.matrixPartitioning = 'none'; 18 | 19 | % partitioning of the last elimination 20 | ret{2}.info = 'Matrix partitioning of the last elimiantion.'; 21 | ret{2}.abbrev = 'last'; 22 | ret{2}.cfg = cfg; 23 | ret{2}.cfg.matrixPartitioning = 'last'; 24 | 25 | % partitioning of the last elimination 26 | ret{3}.info = 'Matrix partitioning of all elimiantions.'; 27 | ret{3}.abbrev = 'all'; 28 | ret{3}.cfg = cfg; 29 | ret{3}.cfg.matrixPartitioning = 'all'; 30 | 31 | end 32 | -------------------------------------------------------------------------------- /benchmark/bench_polynomialGenerator.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 2 | % 3 | % Benchmark templates for benchmarking methods of generating polynomials. 4 | 5 | function [ret] = bench_polynomialGenerator(cfg) 6 | 7 | % generate MATLAB code only 8 | cfg.exportCode = {'matlab'}; 9 | 10 | % solver using systematic method to add polynomials 11 | ret{1}.info = 'Systematic solver.'; 12 | ret{1}.abbrev = 'systematic'; 13 | ret{1}.cfg = cfg; 14 | ret{1}.cfg.PolynomialsGenerator = 'systematic'; 15 | ret{1}.cfg.PolynomialsGeneratorCfg.GJstep = 0; 16 | 17 | % solver using methods of the F4 Algorithm to add polynomials 18 | ret{2}.info = 'F4 Algorithm solver without matrix partitioning.'; 19 | ret{2}.abbrev = 'F4_none'; 20 | ret{2}.cfg = cfg; 21 | ret{2}.cfg.PolynomialsGenerator = 'F4'; 22 | ret{2}.cfg.PolynomialsGeneratorCfg.Sel = @F4_SelNormal; 23 | 24 | % solver using methods of the F4 Algorithm to add polynomials 25 | ret{3}.info = 'F4 Algorithm solver with matrix partitioning.'; 26 | ret{3}.abbrev = 'F4_last'; 27 | ret{3}.cfg = cfg; 28 | ret{3}.cfg.PolynomialsGenerator = 'F4'; 29 | ret{3}.cfg.PolynomialsGeneratorCfg.Sel = @F4_SelNormal; 30 | ret{3}.cfg.matrixPartitioning = 'last'; 31 | 32 | end 33 | -------------------------------------------------------------------------------- /gbsMacaulay/.gitignore: -------------------------------------------------------------------------------- 1 | code.m2 -------------------------------------------------------------------------------- /gbsMacaulay/calc.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem 4 | rem Macaulay2 wrapper by Martin Bujnak 5 | rem (GBsolver subroutine) 6 | 7 | 8 | c: 9 | cd "!!TODO:c:\Program Files\Macaulay2\bin\" 10 | 11 | rem The slashes in the next line should be / 12 | set M2HOME=!!TODO:c:/Progra~1/Macaulay2/lib/Macaulay2-0.9.2 13 | 14 | rem The slashes in the next line should be \ 15 | set M2WINH=!!TODO:c:\Progra~1\Macaulay2\lib\Macaulay2-0.9.2 16 | 17 | rem to help find cygwin.dll 18 | set PATH=%PATH%;%M2HOME%\..\..\bin 19 | 20 | rem Don't change this line. 21 | "%M2WINH%\libexec\Macaulay2" -tty -ephase=1 "%M2HOME%/m2/setup.m2" -ephase=0 '-e runStartFunctions()' '-silent' '-e load "!!TODO:FULL PATH TO CODE, e.g. C:/../GBpolysolver/gbsMacaulay/code.m2"' 22 | 23 | 24 | -------------------------------------------------------------------------------- /gbsMacaulay/code_template.m2: -------------------------------------------------------------------------------- 1 | -- Macaulay2 code template for gbsolver generator 2 | -- 3 | -- by Martin Bujnak, sep2008 4 | -- 5 | 6 | KK = ZZ/$PRIME$ 7 | 8 | R = KK[x_1..x_$UNKCNT$, MonomialOrder=>GRevLex] 9 | 10 | -- generated part 11 | $EQUATIONS$ 12 | $EQUATIONSVEC$ 13 | -- generated part end 14 | 15 | I1 = ideal(f); 16 | gbTrace = 3; 17 | dm = dim I1; 18 | dg = degree I1; 19 | 20 | -- Do not modify following lines 21 | print "dim:" 22 | print dm; 23 | print "deg:" 24 | print dg; 25 | 26 | A = R/I1; 27 | Ab = basis A; 28 | 29 | print "@@@@@@@@@@@@@@" 30 | print Ab; 31 | print "@@@@@@@@@@@@@@" 32 | 33 | exit 0 34 | -------------------------------------------------------------------------------- /generator/@Zp/InvZp.m: -------------------------------------------------------------------------------- 1 | % Zuzana Kukelova 2007-08-21 2 | % Inverse element to the element from Zp 3 | % Input: x - element from Zp 4 | % p - prime 5 | % 6 | % Output: c = x^(-1) in Zp 7 | 8 | 9 | function c = InvZp(x,p) 10 | 11 | % return x*c - d*p = g 12 | % since p is prime number g=1 => c = x^(-1) 13 | [g,c,d] = gcd(x,-p); 14 | 15 | c = mod(c,p); 16 | -------------------------------------------------------------------------------- /generator/@Zp/Zp.m: -------------------------------------------------------------------------------- 1 | 2 | function p = Zp(a, b) 3 | 4 | if nargin == 0 5 | p.c = []; 6 | p.p = 30097; 7 | p = class(p,'Zp'); 8 | 9 | elseif isa(a,'Zp') 10 | 11 | p = a; 12 | 13 | else 14 | 15 | if nargin == 2 16 | 17 | 18 | if isa(b,'Zp') 19 | prime = b.p; 20 | else 21 | prime = b; 22 | end 23 | else 24 | prime = 30097; 25 | end 26 | 27 | p.c = mod(a, prime); 28 | p.p = prime; 29 | p = class(p,'Zp'); 30 | end 31 | -------------------------------------------------------------------------------- /generator/@Zp/char.m: -------------------------------------------------------------------------------- 1 | 2 | function s = char(p) 3 | 4 | % Zp/CHAR 5 | % CHAR(p) is the string representation of p.c 6 | 7 | s=[int2str(p.c) '(mod ' int2str(p.p) ')']; 8 | end -------------------------------------------------------------------------------- /generator/@Zp/diff.m: -------------------------------------------------------------------------------- 1 | 2 | function q = diff(p) 3 | 4 | % Zp/DIFF DIFF(p) is the derivative 5 | q = p; 6 | q.c = 0; 7 | end -------------------------------------------------------------------------------- /generator/@Zp/display.m: -------------------------------------------------------------------------------- 1 | 2 | function display(p) 3 | % Zp/DISPLAY Command window display of a Zp number 4 | disp(' '); 5 | disp([inputname(1),' = ']); 6 | disp(' '); 7 | disp([' ' int2str(p.c) '(mod ' int2str(p.p) ')']); 8 | disp(' '); -------------------------------------------------------------------------------- /generator/@Zp/double.m: -------------------------------------------------------------------------------- 1 | 2 | function c = double(p) 3 | c = p.c; -------------------------------------------------------------------------------- /generator/@Zp/minus.m: -------------------------------------------------------------------------------- 1 | 2 | function r = minus(p,q) 3 | 4 | % Zp/PLUS Implement (p + q) mod Zp. 5 | 6 | p = Zp(p, q); 7 | q = Zp(q, p); 8 | 9 | r = Zp(0, p); 10 | 11 | r.c = mod((p.c - q.c), p.p); 12 | end 13 | -------------------------------------------------------------------------------- /generator/@Zp/mldivide.m: -------------------------------------------------------------------------------- 1 | 2 | function [c] = mldivide(q,p) 3 | 4 | [c]=mrdivide(q,p); 5 | end 6 | -------------------------------------------------------------------------------- /generator/@Zp/mpower.m: -------------------------------------------------------------------------------- 1 | 2 | function r = mpower(p,q) 3 | 4 | % ZP/MPOWER Implement p ^ q for Zp numbers. 5 | 6 | if q < 0 7 | 8 | [g,c,d] = gcd(p.c, -p.p); 9 | p.c = mod(c, p.p); 10 | q = -q; 11 | end 12 | 13 | r = Zp(1, p.p); 14 | for i=1:q 15 | 16 | r.c = r.c*p.c; 17 | end 18 | r.c = mod(r.c, r.p); 19 | end 20 | -------------------------------------------------------------------------------- /generator/@Zp/mrdivide.m: -------------------------------------------------------------------------------- 1 | function [c] = mrdivide(p,q) 2 | 3 | p = Zp(p, q); 4 | q = Zp(q, p); 5 | 6 | % invert q 7 | [g,c,d] = gcd(q.c,-q.p); 8 | c = mod(c, q.p) ; 9 | 10 | c = Zp(p.c*c, p.p); 11 | 12 | end % mrdivide-method 13 | -------------------------------------------------------------------------------- /generator/@Zp/mtimes.m: -------------------------------------------------------------------------------- 1 | 2 | function r = mtimes(p,q) 3 | 4 | % Zp/PLUS Implement (p + q) mod Zp. 5 | 6 | p = Zp(p, q); 7 | q = Zp(q, p); 8 | 9 | r = Zp(0, p); 10 | 11 | r.c = mod((p.c * q.c), p.p); 12 | end 13 | -------------------------------------------------------------------------------- /generator/@Zp/plus.m: -------------------------------------------------------------------------------- 1 | 2 | function r = plus(p,q) 3 | 4 | % Zp/PLUS Implement (p + q) mod Zp. 5 | 6 | p = Zp(p, q); 7 | q = Zp(q, p); 8 | 9 | r = Zp(0, p); 10 | 11 | r.c = mod((p.c + q.c), p.p); 12 | end 13 | -------------------------------------------------------------------------------- /generator/CodeTemplates/CodeGen_Maple_F4.m: -------------------------------------------------------------------------------- 1 | % Template to generate Maple code of solvers using F4 method of 2 | % generating polynomials. 3 | 4 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 5 | 6 | function [ ] = CodeGen_Maple_F4(trace, lastElim, gjcols, rrefPart, coefscode, fid) 7 | 8 | % elimination part 9 | for i = 1:length(trace) - 1 10 | fprintf(fid, ['> \tF', int2str(i), ' := Matrix(', int2str(size(trace{i}.coefs, 1)), ', ', int2str(size(trace{i}.nonzero, 2)), ', 0):\n']); 11 | for j = 1:size(trace{i}.refs, 1) 12 | 13 | [ofs] = find(trace{i}.coefs(j, trace{i}.nonzero)); 14 | for k = ofs 15 | if trace{i}.refs(j, 1) ~= 0 16 | % copy polynomial from other matrix F 17 | fprintf(fid, ['> \tF', int2str(i), '[', int2str(j), ', ', int2str(k), '] := F', int2str(trace{i}.refs(j, 1)), '[', int2str(trace{i}.refs(j, 2)), ', ', int2str(find(trace{trace{i}.refs(j, 1)}.nonzero == (size(trace{trace{i}.refs(j, 1)}.coefs, 2) - trace{i}.coefs(j, trace{i}.nonzero(k)) + 1), 1, 'first')), ']:\n']); 18 | else 19 | % copy polynomial from input 20 | fprintf(fid, ['> \tF', int2str(i), '[', int2str(j), ', ', int2str(k), '] := c[', int2str(trace{i}.coefs(j, trace{i}.nonzero(k))), ']:\n']); 21 | end 22 | end 23 | end 24 | fprintf(fid, ['> \tF', int2str(i), ' := ReducedRowEchelonForm(F', int2str(i), '):\n']); 25 | fprintf(fid, '> \t\n'); 26 | end 27 | 28 | %last elimination 29 | fprintf(fid, ['> \tM := Matrix(', int2str(size(trace{end}.refs, 1)), ', ', int2str(size(gjcols, 2)), ', 0):\n']); 30 | for i = 1:size(trace{end}.refs, 1) 31 | if trace{end}.refs(i, 1) ~= 0 32 | % copy polynomial from other matrix F 33 | for j = 1:size(gjcols, 2) 34 | if trace{end}.coefs(i, gjcols(j)) ~= 0 35 | fprintf(fid, ['> \tM[', int2str(i), ', ', int2str(j), '] := F', int2str(trace{end}.refs(i, 1)), '[', int2str(trace{end}.refs(i, 2)), ', ', int2str(find(trace{trace{end}.refs(i, 1)}.nonzero == (size(trace{trace{end}.refs(i, 1)}.coefs, 2) - trace{end}.coefs(i, gjcols(j)) + 1), 1, 'first')), ']:\n']); 36 | end 37 | end 38 | else 39 | % copy polynomial from input 40 | for j = 1:size(gjcols, 2) 41 | if trace{end}.coefs(i, gjcols(j)) ~= 0 42 | fprintf(fid, ['> \tM[', int2str(i), ', ', int2str(j), '] := c[', int2str(trace{end}.coefs(i, gjcols(j))), ']:\n']); 43 | end 44 | end 45 | end 46 | end 47 | if lastElim.enable 48 | % last elimination with partitioning 49 | rrefPart(lastElim, 'M', 1); 50 | else 51 | % without partitioning 52 | fprintf(fid, '> \tM := ReducedRowEchelonForm(M);\n'); 53 | end 54 | fprintf(fid, '> \t\n'); 55 | 56 | end 57 | -------------------------------------------------------------------------------- /generator/CodeTemplates/CodeGen_Maple_systematic.m: -------------------------------------------------------------------------------- 1 | % Template to generate Maple code of solvers using systematic method of 2 | % generating polynomials. 3 | 4 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 5 | 6 | function [ ] = CodeGen_Maple_systematic(trace, lastElim, gjcols, rrefPart, coefscode, fid) 7 | 8 | % coefs matrix 9 | trace{end}.Mcoefs = trace{end}.Mcoefs(:, gjcols); 10 | 11 | if length(trace) == 1 12 | matrixName = 'M'; 13 | else 14 | matrixName = 'M1'; 15 | trace{1}.Mcoefs = trace{1}.Mcoefs(:, trace{1}.nonzerocols); 16 | end 17 | 18 | fprintf(fid, ['> \t', matrixName, ' := Matrix(' int2str(size(trace{1}.Mcoefs, 1)) ', ' int2str(size(trace{1}.Mcoefs, 2)) ', 0):\n']); 19 | for i=1:length(coefscode) 20 | 21 | [ofss] = find(trace{1}.Mcoefs == i)'; 22 | for ofs = ofss 23 | fprintf(fid, ['> \t', matrixName, '(' int2str(ofs) ') := c[' int2str(i) ']:\n']); 24 | end 25 | end 26 | fprintf(fid, '> \n'); 27 | 28 | % elimination part 29 | if trace{1}.partitioning.enable || lastElim.enable 30 | %eliminate with partitioning 31 | if length(trace) == 1 32 | %last elimination 33 | rrefPart(lastElim, matrixName, 1); 34 | elseif trace{1}.partitioning.enable 35 | rrefPart(trace{1}.partitioning, matrixName, 0); 36 | else 37 | fprintf(fid, ['> \t', matrixName, ' := ReducedRowEchelonForm(', matrixName, '):\n']); 38 | end 39 | else 40 | fprintf(fid, ['> \t', matrixName, ' := ReducedRowEchelonForm(', matrixName, '):\n']); 41 | end 42 | fprintf(fid, '> \n'); 43 | 44 | for i = 2:length(trace) 45 | if i == length(trace) 46 | matrixName = 'M'; 47 | else 48 | matrixName = ['M', int2str(i)]; 49 | trace{i}.Mcoefs = trace{i}.Mcoefs(:, trace{i}.nonzerocols); 50 | end 51 | %if trace{i - 1}.partitioning.enable 52 | % fprintf(fid, ['> \tMold := M:\n']); 53 | %else 54 | % fprintf(fid, ['> \tMold := Matrix(' int2str(size(trace{1}.Mcoefs, 1)) ', ' int2str(size(trace{1}.Mcoefs, 2)) ', 0):\n']); 55 | % fprintf(fid, ['> \tMold[1..-1, [' l2s(trace{i - 1}.nonzerocols, ', ') ']] := M:\n']); 56 | %end 57 | fprintf(fid, ['> \t', matrixName, ' := Matrix(' int2str(size(trace{i}.Mcoefs, 1)) ', ' int2str(size(trace{i}.Mcoefs, 2)) ', 0):\n']); 58 | if isfield(trace{i}, 'filter') 59 | oldColumns = gjcols - trace{i}.columnfrom + 1; 60 | oldColumns = intersect(oldColumns(oldColumns > 0), trace{i-1}.nonzerocols); 61 | [~, selectCols] = ismember(oldColumns, trace{i-1}.nonzerocols); 62 | [~, newCols] = ismember(oldColumns + trace{i}.size(2) - trace{i-1}.size(2), gjcols); 63 | fprintf(fid, ['> \t', matrixName, '[' int2str(trace{i}.rowfrom) '..' int2str(trace{i}.rowto) ', [', l2s(newCols, ', '), ']] := M', int2str(i-1), '[[' l2s(trace{i}.filter, ', ') '], [' l2s(selectCols, ', ') ']]:\n']); 64 | else 65 | [~, newCols] = ismember(trace{i-1}.nonzerocols + trace{i}.size(2) - trace{i-1}.size(2), trace{i}.nonzerocols); 66 | fprintf(fid, ['> \t', matrixName, '[' int2str(trace{i}.rowfrom) '..' int2str(trace{i}.rowto) ', [', l2s(newCols, ', '), ']] := M', int2str(i-1), '[1..', int2str(trace{i}.rowsold), ', 1..-1]:\n']); 67 | end 68 | 69 | [ofs] = find(trace{i}.Mcoefs); 70 | for j = ofs' 71 | [k, l] = ind2sub(trace{i-1}.size, trace{i}.Mcoefs(j)); 72 | l = find(trace{i-1}.nonzerocols == l, 1, 'first'); 73 | idx = sub2ind(trace{i-1}.size, k, l); 74 | fprintf(fid, ['> \t', matrixName, '(' int2str(j) ') := M', int2str(i-1), '(' int2str(idx) '):\n']); 75 | end 76 | 77 | fprintf(fid, '> \n'); 78 | % elimination part 79 | if trace{i}.partitioning.enable || lastElim.enable 80 | %eliminate with partitioning 81 | if i == length(trace) 82 | %last elimination 83 | rrefPart(lastElim, matrixName, 1); 84 | elseif trace{i}.partitioning.enable 85 | rrefPart(trace{i}.partitioning, matrixName, 0); 86 | else 87 | fprintf(fid, ['\n> \t', matrixName, ' := ReducedRowEchelonForm(', matrixName, '):\n']); 88 | end 89 | else 90 | fprintf(fid, ['\n> \t', matrixName, ' := ReducedRowEchelonForm(', matrixName, '):\n']); 91 | end 92 | fprintf(fid, '> \n'); 93 | end 94 | 95 | end 96 | -------------------------------------------------------------------------------- /generator/CodeTemplates/CodeGen_Matlab_F4.m: -------------------------------------------------------------------------------- 1 | % Template to generate MATLAB code of solvers using F4 method of 2 | % generating polynomials. 3 | 4 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 5 | 6 | function [ ] = CodeGen_Matlab_F4(trace, lastElim, gjcols, rrefPart, coefscode, fid) 7 | 8 | % elimination part 9 | for i = 1:length(trace) - 1 10 | fprintf(fid, ['\tF', int2str(i), ' = zeros(', int2str(size(trace{i}.coefs, 1)), ', ', int2str(size(trace{i}.nonzero, 2)), ');\n']); 11 | for j = 1:size(trace{i}.refs, 1) 12 | 13 | [ofs] = find(trace{i}.coefs(j, trace{i}.nonzero)); 14 | for k = ofs 15 | idx = sub2ind([size(trace{i}.refs, 1), length(trace{i}.nonzero)], j, k); 16 | if trace{i}.refs(j, 1) ~= 0 17 | % copy polynomial from other matrix F 18 | idxFrom = sub2ind([size(trace{trace{i}.refs(j, 1)}.refs, 1), length(trace{trace{i}.refs(j, 1)}.nonzero)], trace{i}.refs(j, 2), find(trace{trace{i}.refs(j, 1)}.nonzero == (size(trace{trace{i}.refs(j, 1)}.coefs, 2) - trace{i}.coefs(j, trace{i}.nonzero(k)) + 1), 1, 'first')); 19 | fprintf(fid, ['\tF', int2str(i), '(', int2str(idx), ') = F', int2str(trace{i}.refs(j, 1)), '(', int2str(idxFrom), ');\n']); 20 | else 21 | % copy polynomial from input 22 | fprintf(fid, ['\tF', int2str(i), '(', int2str(idx), ') = c(', int2str(trace{i}.coefs(j, trace{i}.nonzero(k))), ');\n']); 23 | end 24 | end 25 | end 26 | fprintf(fid, ['\tF', int2str(i), ' = rref(F', int2str(i), ');\n\n']); 27 | end 28 | 29 | %last elimination 30 | fprintf(fid, ['\tM = zeros(', int2str(size(trace{end}.refs, 1)), ', ', int2str(size(gjcols, 2)), ');\n']); 31 | for i = 1:size(trace{end}.refs, 1) 32 | for j = 1:size(gjcols, 2) 33 | if trace{end}.coefs(i, gjcols(j)) ~= 0 34 | idx = sub2ind([size(trace{end}.refs, 1), size(gjcols, 2)], i, j); 35 | if trace{end}.refs(i, 1) ~= 0 36 | % copy polynomial from other matrix F 37 | idxFrom = sub2ind([size(trace{trace{end}.refs(i, 1)}.refs, 1), length(trace{trace{end}.refs(i, 1)}.nonzero)], trace{end}.refs(i, 2), find(trace{trace{end}.refs(i, 1)}.nonzero == (size(trace{trace{end}.refs(i, 1)}.coefs, 2) - trace{end}.coefs(i, gjcols(j)) + 1), 1, 'first')); 38 | fprintf(fid, ['\tM(', int2str(idx), ') = F', int2str(trace{end}.refs(i, 1)), '(', int2str(idxFrom), ');\n']); 39 | else 40 | % copy polynomial from input 41 | fprintf(fid, ['\tM(', int2str(idx), ') = c(', int2str(trace{end}.coefs(i, gjcols(j))), ');\n']); 42 | end 43 | end 44 | end 45 | end 46 | 47 | if lastElim.enable 48 | % last elimination with partitioning 49 | rrefPart(lastElim, 'M', 1); 50 | else 51 | % without partitioning 52 | fprintf(fid, '\tM = rref(M);\n\n'); 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /generator/CodeTemplates/CodeGen_Matlab_systematic.m: -------------------------------------------------------------------------------- 1 | % Template to generate MATLAB code of solvers using systematic method of 2 | % generating polynomials. 3 | 4 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 5 | 6 | function [ ] = CodeGen_Matlab_systematic(trace, lastElim, gjcols, rrefPart, coefscode, fid) 7 | 8 | % coefs matrix 9 | trace{end}.Mcoefs = trace{end}.Mcoefs(:, gjcols); 10 | 11 | if length(trace) == 1 12 | matrixName = 'M'; 13 | else 14 | matrixName = 'M1'; 15 | trace{1}.Mcoefs = trace{1}.Mcoefs(:, trace{1}.nonzerocols); 16 | end 17 | 18 | fprintf(fid, ['\t', matrixName, ' = zeros(' int2str(size(trace{1}.Mcoefs, 1)) ', ' int2str(size(trace{1}.Mcoefs, 2)) ');\n']); 19 | for i=1:length(coefscode) 20 | 21 | [ofs] = find(trace{1}.Mcoefs == i); 22 | 23 | if length(ofs) == 1 24 | 25 | fprintf(fid, ['\t', matrixName, '(' int2str(ofs) ') = c(' int2str(i) ');\n']); 26 | else 27 | fprintf(fid, ['\tci = [']); 28 | fprintf(fid, l2s(ofs, ', ')); 29 | fprintf(fid, '];\n'); 30 | 31 | fprintf(fid, ['\t', matrixName, '(ci) = c(' int2str(i) ');\n\n']); 32 | end 33 | end 34 | fprintf(fid, '\n'); 35 | 36 | % elimination part 37 | if trace{1}.partitioning.enable || lastElim.enable 38 | %eliminate with partitioning 39 | if length(trace) == 1 40 | %last elimination 41 | rrefPart(lastElim, matrixName, 1); 42 | elseif trace{1}.partitioning.enable 43 | rrefPart(trace{1}.partitioning, matrixName, 0); 44 | else 45 | fprintf(fid, ['\t', matrixName, ' = rref(', matrixName, ');\n']); 46 | end 47 | else 48 | fprintf(fid, ['\t', matrixName, ' = rref(', matrixName, ');\n']); 49 | end 50 | fprintf(fid, '\n'); 51 | 52 | for i = 2:length(trace) 53 | if i == length(trace) 54 | matrixName = 'M'; 55 | else 56 | matrixName = ['M', int2str(i)]; 57 | trace{i}.Mcoefs = trace{i}.Mcoefs(:, trace{i}.nonzerocols); 58 | end 59 | fprintf(fid, ['\t', matrixName, ' = zeros(' int2str(size(trace{i}.Mcoefs, 1)) ', ' int2str(size(trace{i}.Mcoefs, 2)) ');\n']); 60 | if isfield(trace{i}, 'filter') 61 | oldColumns = gjcols - trace{i}.columnfrom + 1; 62 | oldColumns = intersect(oldColumns(oldColumns > 0), trace{i-1}.nonzerocols); 63 | [~, selectCols] = ismember(oldColumns, trace{i-1}.nonzerocols); 64 | [~, newCols] = ismember(oldColumns + trace{i}.size(2) - trace{i-1}.size(2), gjcols); 65 | fprintf(fid, ['\t', matrixName, '(' int2str(trace{i}.rowfrom) ':' int2str(trace{i}.rowto) ', [', l2s(newCols, ' '), ']) = M', int2str(i-1), '([' l2s(trace{i}.filter, ' ') '], [', l2s(selectCols, ' '), ']);\n']); 66 | else 67 | [~, newCols] = ismember(trace{i-1}.nonzerocols + trace{i}.size(2) - trace{i-1}.size(2), trace{i}.nonzerocols); 68 | fprintf(fid, ['\t', matrixName, '(' int2str(trace{i}.rowfrom) ':' int2str(trace{i}.rowto) ', [', l2s(newCols, ' '), ']) = M', int2str(i-1), '(1:', int2str(trace{i}.rowsold), ', :);\n']); 69 | end 70 | 71 | [~, ~, vals] = find(trace{i}.Mcoefs); 72 | vals = unique(vals); 73 | for v = vals' 74 | pos = find(trace{i}.Mcoefs == v); 75 | [k, l] = ind2sub(trace{i-1}.size, v); 76 | l = find(trace{i-1}.nonzerocols == l, 1, 'first'); 77 | idx = sub2ind(trace{i-1}.size, k, l); 78 | fprintf(fid, ['\t', matrixName, '([' l2s(pos, ' ') ']) = M', int2str(i-1), '(' int2str(idx) ');\n']); 79 | end 80 | 81 | % elimination part 82 | if trace{i}.partitioning.enable || lastElim.enable 83 | %eliminate with partitioning 84 | if i == length(trace) 85 | %last elimination 86 | rrefPart(lastElim, matrixName, 1); 87 | elseif trace{i}.partitioning.enable 88 | rrefPart(trace{i}.partitioning, matrixName, 0); 89 | else 90 | fprintf(fid, ['\t', matrixName, ' = rref(', matrixName, ');\n']); 91 | end 92 | else 93 | fprintf(fid, ['\t', matrixName, ' = rref(', matrixName, ');\n']); 94 | end 95 | fprintf(fid, '\n'); 96 | end 97 | 98 | end 99 | 100 | -------------------------------------------------------------------------------- /generator/F4/F4_SelFirst.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 2 | % 3 | % Selection strategy for F4 Algorithm. Selects the first pair from the set. 4 | % 5 | % POld - set of all pairs 6 | % PSel - set of selected pairs 7 | % PNew - set of remaining pairs 8 | 9 | 10 | function [PSel, PNew] = F4_SelFirst(POld) 11 | 12 | PSel = POld(1:1,1); 13 | PNew = POld(2:end,1); 14 | 15 | end 16 | 17 | -------------------------------------------------------------------------------- /generator/F4/F4_SelNormal.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 2 | % 3 | % Selection strategy for F4 Algorithm. Selects all pairs with a minimal 4 | % total degree. Known as the normal strategy for F4. 5 | % 6 | % POld - set of all pairs 7 | % PSel - set of selected pairs 8 | % PNew - set of remaining pairs 9 | 10 | 11 | function [PSel, PNew] = F4_SelNormal(POld) 12 | 13 | % find minimal total degree 14 | minDeg = sum(POld{1}.lcm); 15 | select = []; 16 | for i = 1:length(POld) 17 | if sum(POld{i}.lcm) < minDeg 18 | minDeg = sum(POld{i}.lcm); 19 | select = [i]; 20 | elseif sum(POld{i}.lcm) == minDeg 21 | select = [select, i]; 22 | end 23 | end 24 | 25 | % select those pairs 26 | PSel = POld(select, 1); 27 | PNew = POld(setdiff(1:length(POld), select), 1); 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /generator/benchmark/computeSolutionDifference.m: -------------------------------------------------------------------------------- 1 | % Prokop Silhavy, silhapro@fel.cvut.cz, August 2015 2 | % 3 | % Utility for validation for benchmark. 4 | % This function computes sinus of solutions computed by automatic generator 5 | % and correct solutions defined by user. 6 | % 7 | % correctSolution - solutions defined by user 8 | % solution - computed solutions by solver 9 | function [err] = computeSolutionDifference( correctSolution, solution ) 10 | 11 | err = NaN(1,size(solution,2)); 12 | 13 | bestIndex = 0; 14 | actError = 0; 15 | d = 0; 16 | 17 | for i = 1:size(solution,2) 18 | for j = 1:size(correctSolution,2) 19 | %actError = sum(abs(solution(:,i) - correctSolution(:,j)))/length(solution(:,i)); 20 | d = dot(solution(:,i), correctSolution(:,j))/(sqrt(sum(solution(:,i).^2))*sqrt(sum(correctSolution(:,j).^2))) 21 | if abs(d)>1 22 | d = 1*sign(d); 23 | end 24 | actError = sin(acos(d)); 25 | if isnan(err(i)) || actError < err(i) 26 | err(i) = actError; 27 | end 28 | end 29 | end 30 | end 31 | 32 | -------------------------------------------------------------------------------- /generator/benchmark/generateInputData.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 2 | % 3 | % Function generates inputData to be used by benchmark. Data are generated 4 | % by Normal distribution with mean 0 and standard deviation 1. 5 | % 6 | % known - list of knowns 7 | % kngroups - groups of knowns 8 | % maxInputs - number of generated inputs 9 | 10 | function [inputData] = generateInputData(~, known, ~, kngroups, maxInputs) 11 | 12 | % initialize variables 13 | inputData = cell(maxInputs, 1); 14 | 15 | % sort knowns into kngroups 16 | if isempty(kngroups) 17 | numKnowns = ones(length(known), 1); 18 | else 19 | numKnowns = zeros(0, 1); 20 | for i = 1:length(known) 21 | if size(numKnowns, 1) < kngroups(i) 22 | numKnowns(kngroups(i), 1) = 1; 23 | else 24 | numKnowns(kngroups(i)) = numKnowns(kngroups(i)) + 1; 25 | end 26 | end 27 | end 28 | 29 | % get dimensions 30 | rows = length(numKnowns); 31 | cols = max(numKnowns); 32 | 33 | % generate sets of input data 34 | for i = 1:maxInputs 35 | 36 | % for each known generate random number 37 | inputData{i, 1} = random('Normal', 0, 1, rows, cols); 38 | 39 | end 40 | 41 | end -------------------------------------------------------------------------------- /generator/benchmark/renderHistogram.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 2 | % 3 | % Default function for rendering errors for benchmarking. 4 | % 5 | % results - results of benchmark 6 | % benchmark - settings of benchmark 7 | % numFigures - total count of figures to be displayed on the screen 8 | % i - index of current subfigure 9 | % fitHistogram - boolean if graph should be plot or histogram 10 | 11 | function [] = renderHistogram(results, benchmark, numFigures, i, fitHistogram) 12 | 13 | % reshape into vector and get rid of NaNs 14 | vector = reshape(results.err, [], 1); 15 | vector = abs(vector(isnan(vector) == 0)); 16 | 17 | % logarithm 18 | vector = log10(vector); 19 | 20 | % get rid of -Inf 21 | ix = vector ~= -Inf; 22 | vector = vector(ix); 23 | 24 | % prepare data for histogram 25 | range = (min(vector):(max(vector)-min(vector))/100:max(vector))'; 26 | count = histc(vector, range); 27 | 28 | % divide screen into adequate number of subfigures 29 | if numFigures <= 4 30 | rows = 2; 31 | cols = 2; 32 | elseif numFigures <= 6 33 | rows = 2; 34 | cols = 3; 35 | else 36 | rows = 3; 37 | cols = 4; 38 | end 39 | 40 | % plot histogram 41 | subfig(rows, cols, i); 42 | if fitHistogram 43 | f = fit(range, count, 'smoothingspline'); 44 | plot(f, '-b'); 45 | else 46 | histogram(vector,100); 47 | end 48 | 49 | legend('off'); 50 | axis([min(range) max(range) min(count) max(count)]); 51 | title(['Histogram of error. (', benchmark.info, ')']); 52 | ylabel('Frequency'); 53 | xlabel(sprintf('Log10 of |error| for |error| > 0, %.2e of error = 0', nnz(~ix)/length(ix))); 54 | drawnow; 55 | 56 | end -------------------------------------------------------------------------------- /generator/benchmark/validateWithCorrectSolution.m: -------------------------------------------------------------------------------- 1 | % Prokop Silhavy, silhapro@fel.cvut.cz, August 2015 2 | % 3 | % Validation function used by benchmark utility. 4 | % This function compares solutions computed by automatic generator with 5 | % correct solutions defined by user. 6 | % 7 | % correctOutput - solutions defined bz user 8 | % solution - computed solutions by solver 9 | 10 | function [err] = validateWithCorrectSolution(~, correctOutput, solution, ~, ~, ~) 11 | 12 | err = NaN(size(solution, 1), 0); 13 | 14 | reverseStr = ''; 15 | 16 | solutionErr = []; 17 | for i = 1:length(solution) 18 | 19 | solutionErr = computeSolutionDifference(correctOutput{i}, solution{i}); 20 | 21 | % enlarge matrix if needed 22 | if length(solutionErr) > size(err, 2) 23 | oldErr = err; 24 | err = NaN(size(solution, 1), length(solutionErr)); 25 | err(:, 1:size(oldErr, 2)) = oldErr; 26 | end 27 | 28 | err(i,1:length(solutionErr)) = solutionErr; 29 | 30 | msg = sprintf(' %2.0f %%%% done', i/size(solution, 1)*100); 31 | fprintf([reverseStr, msg]); 32 | reverseStr = repmat(sprintf('\b'), 1, length(msg) - 1); 33 | end 34 | 35 | fprintf(reverseStr); 36 | 37 | end -------------------------------------------------------------------------------- /generator/benchmark/validateZeroPolynomials.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 2 | % 3 | % Validation function used by benchmark utility. 4 | % This function substitutes computed solution into polynomials generated 5 | % by solver. This should be zero value, but because of bad stability we 6 | % get non zero value. 7 | % 8 | % inputData - a set of instanced known parameters 9 | % solution - computed solutions by solver 10 | % eq - input equations 11 | % unknown - list of unknowns 12 | % known - list of knowns 13 | 14 | function [err] = validateZeroPolynomials(inputData, ~, solution, eq, unknown, known) 15 | 16 | err = ones(size(solution, 1), 0)*NaN; 17 | 18 | % make symbolic variables of known and unknown 19 | for i = 1:length(unknown) 20 | eval(['syms ', unknown{i}]); 21 | end 22 | for i = 1:length(known) 23 | eval(['syms ', known{i}]); 24 | end 25 | 26 | % prepare all syms into one vector 27 | symbolic = [known, unknown]; 28 | 29 | reverseStr = ''; 30 | % for each inputData 31 | for i = 1:size(inputData, 1) 32 | 33 | % prepare vector of knowns 34 | substitute = cell(size(symbolic)); 35 | substitute(1, 1:length(known)) = num2cell(reshape(inputData{i}', 1, length(known))); 36 | 37 | % for each solution 38 | for j = 1:size(solution{i}, 2); 39 | 40 | % prepare vector of unknowns 41 | substitute(1, length(known)+1:end) = num2cell(solution{i}(:, j)'); 42 | 43 | 44 | % enlarge matrix if needed 45 | if j > size(err, 2) 46 | oldErr = err; 47 | err = ones(size(solution, 1), j)*NaN; 48 | err(:, 1:size(oldErr, 2)) = oldErr; 49 | end 50 | 51 | err(i, j) = sum(double(subs(eq, symbolic, substitute))); 52 | 53 | end 54 | 55 | msg = sprintf(' %2.0f %%%% done', i/size(inputData, 1)*100); 56 | fprintf([reverseStr, msg]); 57 | reverseStr = repmat(sprintf('\b'), 1, length(msg) - 1); 58 | end 59 | fprintf(reverseStr); 60 | 61 | end -------------------------------------------------------------------------------- /generator/gbs_Benchmark.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 2 | % 3 | % problemName - name of the minimalProblem; function specifies the problem 4 | % must have the same name 5 | % benchmark - function, which defines benchmark procedures 6 | % inputData - set of data on which we will test the solvers 7 | % correctOutput - correct solutions of the problem for the inputData. It is 8 | % used to compare the correctness of the generated solvers. 9 | % validationFunction - function called to evaluate the results 10 | % renderFunction - function to render results 11 | 12 | function [results, inputData] = gbs_Benchmark(problemName, benchmarkFunction, inputData, correctOutput, validationFunction, renderFunction) 13 | 14 | % get minimal problem definition 15 | problem = str2func(problemName); 16 | [eq, known, unknown, kngroups, cfg, algB] = problem(); 17 | 18 | % parse input parameters 19 | if nargin < 3 20 | % if no inputData, we have to generate random inputs 21 | inputData = generateInputData(eq, known, unknown, kngroups, cfg.benchmark.maxInputs); 22 | end 23 | if nargin < 4 24 | % default zero of polynomials 25 | validationFunction = @validateZeroPolynomials; 26 | correctOutput = []; 27 | end 28 | if nargin < 6 29 | % default histogram 30 | renderFunction = @renderHistogram; 31 | end 32 | 33 | % enable benchmark mode 34 | cfg.benchmark.enable = 1; 35 | 36 | % get benchmark definitions 37 | benchmarkConfig = benchmarkFunction(cfg); 38 | 39 | % do benchmarks 40 | fprintf('\nBENCHMARK STARTED\n'); 41 | results = cell(length(benchmarkConfig), 1); 42 | for i = 1:length(benchmarkConfig) 43 | benchmark = benchmarkConfig{i}; 44 | 45 | % print info 46 | fprintf('\n################################################################\n'); 47 | fprintf(['\n', benchmark.info, '\n\n\n']); 48 | 49 | % create code 50 | gbs_CreateCode([problemName, '_', benchmark.abbrev], eq, known, unknown, kngroups, benchmark.cfg, algB); 51 | 52 | % update MATLAB cache to recognize new generated functions 53 | rehash; 54 | 55 | solver = str2func(['solver_', problemName, '_' ,benchmark.abbrev]); 56 | 57 | fprintf('\nSolver generated.\n'); 58 | fprintf('Benchmarking solver.\n'); 59 | 60 | % call solver for all inputData and save results 61 | results{i}.solution = cell(size(inputData, 1), 1); 62 | results{i}.benchData = cell(size(inputData, 1), 1); 63 | results{i}.time = zeros(size(inputData, 1), 1); 64 | reverseStr = ''; 65 | for j = 1:min(size(inputData, 1), cfg.benchmark.maxInputs) 66 | try 67 | [results{i}.solution{j}, results{i}.time(j)] = solver(inputData{j}); 68 | msg = sprintf(' %2.0f %%%% done', j/min(size(inputData, 1), cfg.benchmark.maxInputs)*100); 69 | fprintf([reverseStr, msg]); 70 | reverseStr = repmat(sprintf('\b'), 1, length(msg) - 1); 71 | catch 72 | fprintf(reverseStr); 73 | reverseStr = ''; 74 | fprintf(' solver executed on data %d failed!\n', j); 75 | results{i}.solution{j} = zeros(length(unknown), 0); 76 | results{i}.time(j) = NaN; 77 | end 78 | end 79 | fprintf(reverseStr); 80 | 81 | fprintf('Evaluating results.\n'); 82 | % get errors of solutions 83 | results{i}.err = validationFunction(inputData, correctOutput, results{i}.solution, eq, unknown, known); 84 | 85 | % render results 86 | renderFunction(results{i}, benchmark, length(benchmarkConfig), i, false); 87 | 88 | end 89 | 90 | end -------------------------------------------------------------------------------- /generator/gbs_BuildActionMatrix.m: -------------------------------------------------------------------------------- 1 | % Build action natrix for variable "actMvar" given coefficient matrix M 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, mar2008 4 | % last edit by Pavel Trutman, February 2015 5 | 6 | 7 | function [amrows, amcols, gjcols, aidx, PartitioningWorkflow] = gbs_BuildActionMatrix(cfg, M, algB, amLT, amLTall, algBidx, actMvar) 8 | 9 | % extract action matrix for variable "actMvar" 10 | 11 | cols = size(M, 2); 12 | algBcnt = size(algBidx, 2); 13 | 14 | amrows = zeros(algBcnt, 1); 15 | 16 | % GJ 17 | nonzero = find(sum(M) ~= 0); 18 | Kk = M(:, nonzero); 19 | B = gjzpsp(Kk, cfg.prime); 20 | A = zeros(size(M)); 21 | A(:, nonzero) = B; 22 | 23 | % 24 | % detect leading '1' 25 | [val, idx] = min(abs(B' - 1)); 26 | idx = idx(find(val == 0)); 27 | 28 | % add algB columns 29 | 30 | % columns that are really required in GJ 31 | gjcols = union(nonzero(idx), (cols+1)-algBidx); 32 | 33 | % create monomials lookup table 34 | aidx = (-1)*ones(1,cols); 35 | aidx(gjcols) = 1:size(gjcols, 2); 36 | 37 | fprintf('Extracting the action matrix for variable ''%s'' (used coef. matrix size %dx%d) \n', char(actMvar), size(Kk, 1), length(gjcols)); 38 | 39 | amcols = aidx((cols+1)-algBidx); 40 | 41 | if strcmp(cfg.matrixPartitioning, 'all') || strcmp(cfg.matrixPartitioning, 'last') 42 | %use matrix partitioning 43 | [B, PartitioningWorkflow] = gbs_MatrixPartitioning(M(:, gjcols), amcols, false, cfg.prime); 44 | A = zeros(size(M)); 45 | A(:, gjcols) = B; 46 | else 47 | PartitioningWorkflow.enable = 0; 48 | end 49 | 50 | for i=1:algBcnt 51 | 52 | pos = find(algBidx == amLTall(i)); 53 | if isempty(pos) 54 | 55 | % take remainder 56 | [r_one]=find(A(:,cols-amLTall(i)+1) == 1); 57 | amrows(i) = r_one; 58 | 59 | else 60 | % in the B 61 | amrows(i) = -pos; 62 | end 63 | end 64 | 65 | end -------------------------------------------------------------------------------- /generator/gbs_CheckActionMatrixConditions.m: -------------------------------------------------------------------------------- 1 | % Check if in given matrix are all required polynomials to build an action 2 | % matrix 3 | % by Martin Bujnak, mar2008 4 | % last edit by Pavel Trutman, May 2015 5 | 6 | function [res, ordersReq] = gbs_CheckActionMatrixConditions(M, amStats, isElim, prime) 7 | 8 | if ~isElim 9 | 10 | nonzero = find(sum(M) ~= 0); 11 | Kk = M(:, nonzero); 12 | 13 | B = gjzpsp(Kk, prime); 14 | 15 | M = zeros(size(M, 1), size(M, 2)); 16 | M(:, nonzero) = B; 17 | end 18 | 19 | cols = size(M, 2); 20 | 21 | % check conditions for all action matrices 22 | for i=1:length(amStats) 23 | 24 | % test required leading terms 25 | if max(amStats{i}.amLT) > cols 26 | continue; 27 | end 28 | [r_ones, ~]=find(M(:, cols-amStats{i}.amLT+1) == 1); 29 | if size(r_ones,1) < amStats{i}.amLTcnt 30 | continue; 31 | end 32 | rowssum = find(sum(M(r_ones, amStats{i}.zero_el),2) == 1); 33 | if size(rowssum, 1) < amStats{i}.amLTcnt 34 | continue; 35 | end 36 | 37 | % all tests passed OK 38 | res = i; 39 | if nargout > 1 40 | ordersReq = []; 41 | end 42 | return; 43 | end 44 | 45 | % count which leading monials are not generated yet 46 | if nargout > 1 47 | 48 | % pick leading monomials 49 | leadingMons = []; 50 | for i = 1:size(M, 1) 51 | index = find(M(i, :), 1, 'first'); 52 | leadingMons = [leadingMons, size(M, 2) - index + 1]; 53 | end 54 | 55 | % pick variable with minimal required not present leading monomials 56 | ordersReq = setdiff(amStats{1}.amLT, leadingMons); 57 | for i = 2:length(amStats) 58 | req = setdiff(amStats{i}.amLT, leadingMons); 59 | if length(req) < length(ordersReq) 60 | ordersReq = req; 61 | end 62 | end 63 | end 64 | 65 | res = 0; 66 | end -------------------------------------------------------------------------------- /generator/gbs_CreateCode.m: -------------------------------------------------------------------------------- 1 | % This code uses Grobner basis methods to generate a code solving system of 2 | % given polynomial equations. 3 | % 4 | % Please refer to the following paper, when using this code : 5 | % 6 | % "Kukelova Z., Bujnak M., Pajdla T., Automatic Generator of Minimal 7 | % Problem Solvers, ECCV 2008, Marseille, France, October 12-18, 2008" 8 | % 9 | % 10 | % by Martin Bujnak, mar2008 11 | % last edit by Pavel Trutman, February 2015 12 | 13 | function [res, export] = gbs_CreateCode(codename, eq, known, unknown, kngroups, cfg, algB) 14 | 15 | export = []; 16 | 17 | if nargin < 5 18 | 19 | kngroups = []; 20 | end 21 | 22 | if nargin < 6 23 | 24 | cfg = gbs_InitConfig(); 25 | end 26 | 27 | if nargin < 7 28 | 29 | algB = []; 30 | end 31 | 32 | % parse & detect & add required polynomials 33 | [M, trace, coefscode, amVar, amLT, amLTall, algBidx, algB] = gbs_PreparePolySystemCoefsMatrix(cfg, eq, known, unknown, algB); 34 | 35 | if ~isempty(M) 36 | 37 | % prepare code lookups 38 | [amrows, amcols, gjcols, aidx, PaToHWorkflow] = gbs_BuildActionMatrix(cfg, M, algB, amLT, amLTall, algBidx, amVar); 39 | 40 | % save calculated data 41 | export.M = M; 42 | export.trace = trace; 43 | export.coefscode = coefscode; 44 | export.known = known; 45 | export.unknown = unknown; 46 | export.algB = algB; 47 | export.actMvar = amVar; 48 | export.amrows = amrows; 49 | export.amcols = amcols; 50 | export.gjcols = gjcols; 51 | export.aidx = aidx; 52 | 53 | if cfg.bGeneratorSolverResult 54 | save(['solvers\' codename '_expparams'], 'export'); 55 | end 56 | 57 | for tmp = cfg.exportCode 58 | 59 | % cut suffix 60 | parls = strfind(tmp{1}, '('); 61 | if isempty(parls) 62 | suffix = []; 63 | else 64 | suffix = tmp{1}(parls(end)+1:end-1); 65 | tmp{1} = tmp{1}(1:parls(end)-1); 66 | end 67 | 68 | if strcmpi(tmp{1}, 'matlab') 69 | 70 | fprintf('--- generating MATLAB solver ---\n'); 71 | gbs_ExportMatlabCode(['./solvers/solver_' codename suffix], M, trace, coefscode, known, kngroups, unknown, algB, amVar, amrows, amcols, gjcols, aidx, PaToHWorkflow, cfg); 72 | 73 | elseif strcmpi(tmp{1}, 'maple') 74 | fprintf('--- generating Maple solver ---\n'); 75 | if isempty(suffix) 76 | suffix = '.txt'; 77 | end 78 | 79 | gbs_ExportMapleCode(['./solvers/solver_' codename suffix], M, trace, coefscode, known, kngroups, unknown, algB, amVar, amrows, amcols, gjcols, aidx, PaToHWorkflow, cfg); 80 | else 81 | try 82 | fprintf('--- generating c solver using '' %s '' template---\n', tmp{1}); 83 | if isempty(suffix) 84 | suffix = 'mex.c'; 85 | end 86 | % warning: this function is not implemented in this package 87 | gbs_ExportCCode(['solvers\solver_' codename suffix], tmp{1}, M, trace, coefscode, known, kngroups, unknown, algB, amVar, amrows, amcols, gjcols, aidx, PaToHWorkflow, cfg); 88 | catch 89 | fprintf('... error exporting using ''%s'' template---\n', tmp{1}); 90 | end 91 | end 92 | end 93 | end 94 | 95 | res = 0; 96 | end -------------------------------------------------------------------------------- /generator/gbs_DBGExport.m: -------------------------------------------------------------------------------- 1 | % debug export (equations, variables, instance, polynomials,...) 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, oct2008 4 | 5 | function [] = gbs_DBGExport(known, unknown, eq, symcoefs, allmons, Minit, Mmons) 6 | 7 | % export code 8 | fid = fopen('coefs.txt', 'w'); 9 | 10 | fprintf(fid, '%% Generated using GBSolver generator Copyright Martin Bujnak,\n'); 11 | fprintf(fid, '%% Zuzana Kukelova, Tomas Pajdla CTU Prague 2008.\n%% \n'); 12 | fprintf(fid, '%% Please refer to the following paper, when using this code :\n'); 13 | fprintf(fid, '%% Kukelova Z., Bujnak M., Pajdla T., Automatic Generator of Minimal Problem Solvers,\n'); 14 | fprintf(fid, '%% ECCV 2008, Marseille, France, October 12-18, 2008\n'); 15 | fprintf(fid, '%%\n'); 16 | 17 | fprintf(fid, '%% unknowns\n\t%s', c2s(unknown, ' ')); 18 | 19 | fprintf(fid, '\n\n'); 20 | 21 | fprintf(fid, '%% known\n\t%s', c2s(known, ' ')); 22 | 23 | fprintf(fid, '\n\n'); 24 | % export equations in raw form 25 | fprintf(fid, '%% raw equations \n'); 26 | for i=1:length(eq) 27 | fprintf(fid, '\teq(%d) = %s;\n', i, char(eq(i))); 28 | end 29 | fprintf(fid, '\n\n'); 30 | 31 | % export coefs vars 32 | fprintf(fid, '%% coeficients \n'); 33 | 34 | for i=1:length(symcoefs) 35 | fprintf(fid, '\tc(%d) = %s;\n', i, char(symcoefs(i))); 36 | end 37 | fprintf(fid, '\n\n'); 38 | 39 | % export monimials vector 40 | fprintf(fid, '%% monomials [%d] \n ', length(allmons)); 41 | fprintf(fid, '\tmons=[...\n'); 42 | for mons = allmons 43 | fprintf(fid, '%s ', char(mons)); 44 | end 45 | fprintf(fid, '];\n'); 46 | 47 | fprintf(fid, '\n\n'); 48 | 49 | % export coefs matrix 50 | fprintf(fid, '%% coefficients matrix \n'); 51 | fprintf(fid, '\tM=[...\n'); 52 | for i=1:size(Minit,1) 53 | fprintf(fid, '\t\t'); 54 | for j=1:size(Minit,2) 55 | fprintf(fid, '%d ', Minit(i,j)); 56 | end 57 | fprintf(fid, '...\n'); 58 | end 59 | fprintf(fid, '\t\t];\n'); 60 | 61 | 62 | % export used monimials vector 63 | fprintf(fid, '%% used monomials [%d] \n ', length(monomials)); 64 | fprintf(fid, '\tmons=[...\n'); 65 | for mons = monomials 66 | fprintf(fid, '%s ', char(mons)); 67 | end 68 | fprintf(fid, '1];\n'); 69 | 70 | fprintf(fid, '\n\n'); 71 | 72 | % export coefs matrix 73 | fprintf(fid, '%% used coefficients matrix \n'); 74 | fprintf(fid, '\tM=[...\n'); 75 | for i=1:size(Mmons,1) 76 | fprintf(fid, '\t\t'); 77 | for j=1:size(Mmons,2) 78 | fprintf(fid, '%d ', Mmons(i,j)); 79 | end 80 | fprintf(fid, '...\n'); 81 | end 82 | fprintf(fid, '\t\t];\n'); 83 | 84 | fclose(fid); 85 | end -------------------------------------------------------------------------------- /generator/gbs_ExportMapleCode.m: -------------------------------------------------------------------------------- 1 | % Generate Matlab Code for given action matrix and coefficient matrices 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, sep2008 4 | % last edit by Pavel Trutman, May 2015 5 | 6 | 7 | function [res] = gbs_ExportMapleCode(filename, M, trace, coefscode, known, knowngroups, unknown, algB, actMvar, amrows, amcols, gjcols, aidx, lastElim, cfg) 8 | 9 | [p, probname, e] = fileparts(filename); 10 | if isempty(e) 11 | filename = [filename '.txt']; 12 | end; 13 | 14 | if (~isdir(p)) 15 | mkdir(p); 16 | end 17 | 18 | if isempty(knowngroups) 19 | knowngroups = 1:length(known); 20 | end 21 | 22 | % generate coefs calculation code 23 | knvars=[]; 24 | knvarnames=[]; 25 | knvarcnt=[]; 26 | for i=1:length(known) 27 | 28 | if length(knvars) >= knowngroups(i) 29 | knvars{knowngroups(i)} = [knvars{knowngroups(i)} sym(known{i})]; 30 | knvarcnt(knowngroups(i)) = knvarcnt(knowngroups(i)) + 1; 31 | else 32 | knvars{knowngroups(i)} = sym(known{i}); 33 | knvarcnt(knowngroups(i)) = 1; 34 | end 35 | 36 | if length(knvarnames) < knowngroups(i) || isempty(knvarnames(knowngroups(i))) 37 | name=known(i); 38 | knvarnames{knowngroups(i)} = name{1}; 39 | end 40 | end 41 | 42 | fid = fopen(filename, 'w'); 43 | 44 | fprintf(fid, '# Generated using GBSolver generator Copyright Martin Bujnak,\n'); 45 | fprintf(fid, '# Zuzana Kukelova, Tomas Pajdla CTU Prague 2008.\n# \n'); 46 | fprintf(fid, '# Please refer to the following paper, when using this code :\n'); 47 | fprintf(fid, '# Kukelova Z., Bujnak M., Pajdla T., Automatic Generator of Minimal Problem Solvers,\n'); 48 | fprintf(fid, '# ECCV 2008, Marseille, France, October 12-18, 2008\n# \n'); 49 | 50 | fprintf(fid, '> restart:\n'); 51 | fprintf(fid, '> with(LinearAlgebra):\n'); 52 | fprintf(fid, '> interface(rtablesize = 210):\n'); 53 | fprintf(fid, '> Digits:=100:\n\n'); 54 | 55 | fprintf(fid, '# #\n'); 56 | fprintf(fid, '# #\n'); 57 | fprintf(fid, '# # Solver \n'); 58 | fprintf(fid, '# #\n'); 59 | fprintf(fid, '> \n'); 60 | fprintf(fid, ['> ' probname ':=proc(' c2s(knvarnames, ', ') ')' '\n> \n']); 61 | 62 | % local variables 63 | fprintf(fid, ['> \tlocal c, M, Mold, amcols, A, D1, V1, i, ' c2s((unknown), ', ') ' , mat1, mat2']); 64 | if strcmp(cfg.PolynomialsGenerator, 'F4') 65 | for i = 1:length(trace) - 1; 66 | fprintf(fid, [', F', int2str(i)]); 67 | end 68 | end 69 | fprintf(fid, ';\n> \n'); 70 | 71 | % coeffs 72 | fprintf(fid, '> \t# precalculate polynomial equations coefficients\n'); 73 | for i=1:length(coefscode) 74 | 75 | % rename coefficients according to "knowngroups" 76 | coefcode = char(coefscode(i)); 77 | 78 | for j=1:length(knvars) 79 | if length(knvars{j}) > 1 80 | for k=1:length(knvars{j}) 81 | coefcode = regexprep([coefcode, ' '], [char(knvars{j}(k)), '([^0-9\(])'], [knvarnames{j} '(' int2str(k) ')$1']); 82 | end 83 | end 84 | end 85 | 86 | % replace (,) with [,] 87 | coefcode = strrep(coefcode, '(', '['); 88 | coefcode = strrep(coefcode, ')', ']'); 89 | 90 | fprintf(fid, ['> \tc[' int2str(i) '] := ' regexprep(coefcode, '\s*$', '') ':\n']); 91 | end 92 | fprintf(fid, '> \n'); 93 | 94 | 95 | % Generate code using different methods 96 | CodeGenerator = str2func(['CodeGen_Maple_', cfg.PolynomialsGenerator]); 97 | CodeGenerator(trace, lastElim, gjcols, @rrefPart, coefscode, fid); 98 | 99 | 100 | % action matrix 101 | fprintf(fid, ['> \tA := Matrix(' int2str(length(amrows)) ', ' int2str(length(amrows)) ', 0):\n']); 102 | fprintf(fid, ['> \tamcols := [' l2s(amcols, ', ') ']:\n']); 103 | 104 | tgcols = ['1..' int2str(length(amrows))]; 105 | 106 | for i=1:length(amrows) 107 | 108 | if amrows(i) < 0 109 | fprintf(fid, ['> \tA[' int2str(i) ', ' int2str(-amrows(i)) '] := 1:\n']); 110 | else 111 | fprintf(fid, ['> \tA[' int2str(i) ', ' tgcols '] := -M[' int2str(amrows(i)) ', amcols]:\n']); 112 | end 113 | end 114 | fprintf(fid, '> \n'); 115 | 116 | % solution extraction 117 | 118 | fprintf(fid, '> \t(D1, V1) := Eigenvectors(evalf(A)):\n'); 119 | fprintf(fid, '>\n'); 120 | 121 | [oneidx, unksidx] = gbs_GetVariablesIdx(algB, unknown); 122 | varsinvec = find(unksidx > 0); 123 | 124 | ucnt = length(unknown); 125 | for i=1:ucnt 126 | 127 | fprintf(fid, ['> \t' unknown{ucnt - i + 1} ' := Vector(' int2str(length(amrows)) ', 0): \n']); 128 | end 129 | 130 | if (sum(unksidx == 0)) > 0 131 | 132 | idx = find(unksidx == 0); 133 | if (length(idx) > 1) 134 | 135 | fprintf(fid, '\t\tWARNING: cannot extract all unknowns at once. A back-substitution required (not implemented/automatized)\n'); 136 | end 137 | end 138 | 139 | fprintf(fid, ['> \tfor i from 1 to ' int2str(length(amrows)) ' do \n']); 140 | 141 | ucnt = length(unknown); 142 | for i=1:ucnt 143 | 144 | if unksidx(i) == 0 145 | fprintf(fid, ['> \t\t' unknown{i} '[i] := evalf(D1[ i, i]) \n']); 146 | else 147 | fprintf(fid, ['> \t\t' unknown{i} '[i] := evalf(V1[' int2str(unksidx(i)) ', i]) / evalf(V1[' int2str(oneidx) ', i]): \n']); 148 | end 149 | end 150 | 151 | fprintf(fid, '> \tend do; \n'); 152 | 153 | % outputs 154 | fprintf(fid, '> \n'); 155 | fprintf(fid, ['> \t(' c2s((unknown), ', ') ');\n']); 156 | fprintf(fid, '> \n'); 157 | fprintf(fid, '> end proc:\n'); 158 | 159 | fclose(fid); 160 | 161 | 162 | function [] = rrefPart(workflow, matrixName, last) 163 | %matrix elimination with partitioning 164 | fprintf(fid, '> \n> \t# GJ elimination with partitioning\n'); 165 | 166 | %first part of matrix 167 | mat1Cols = [workflow.noAmCols(:, [workflow.ACols1; workflow.BCols]) workflow.amCols]; 168 | fprintf(fid, ['> \tmat1 := ', matrixName, '[[', l2s(workflow.PRows1, ', '), '], [', l2s(mat1Cols, ', '), ']]:\n']); 169 | fprintf(fid, ['> \tmat1[1..-1, [', l2s(workflow.mat1NonzeroCols, ', '), ']] := ReducedRowEchelonForm(mat1[1..-1, [', l2s(workflow.mat1NonzeroCols, ', '), ']]):\n']); 170 | 171 | %second part of matrix 172 | mat2Cols = [workflow.noAmCols(:, [workflow.ACols2; workflow.BCols]) workflow.amCols]; 173 | fprintf(fid, ['> \tmat2 := ', matrixName, '[[', l2s(workflow.PRows2, ', '), '], [', l2s(mat2Cols, ', '), ']]:\n']); 174 | fprintf(fid, ['> \tmat2[1..-1, [', l2s(workflow.mat2NonzeroCols, ', '), ']] := ReducedRowEchelonForm(mat2[1..-1, [', l2s(workflow.mat2NonzeroCols, ', '), ']]):\n> \n']); 175 | 176 | %assemble both parts together 177 | fprintf(fid, ['> \t', matrixName, ' := Matrix(', l2s(size(workflow.res), ', '), ', 0):\n']); 178 | if size(workflow.mat1TopRows, 2) ~= 0 179 | resMat1TopRows = workflow.resMat1TopRows; 180 | if ~last 181 | resMat1TopRows = workflow.permutationRows(resMat1TopRows); 182 | end 183 | fprintf(fid, ['> \t', matrixName, '[[', l2s(resMat1TopRows, ', '), '], [', l2s(mat1Cols, ', '), ']] := mat1[[', l2s(workflow.mat1TopRows, ', '), '], 1..-1]:\n']); 184 | end 185 | if size(workflow.mat2TopRows, 2) ~= 0 186 | resMat2TopRows = workflow.resMat2TopRows; 187 | if ~last 188 | resMat2TopRows = workflow.permutationRows(resMat2TopRows); 189 | end 190 | fprintf(fid, ['> \t', matrixName, '[[', l2s(resMat2TopRows, ', '), '], [', l2s(mat2Cols, ', '), ']] := mat2[[', l2s(workflow.mat2TopRows, ', '), '], 1..-1]:\n']); 191 | end 192 | if size(workflow.mat1BottRows, 2) ~= 0 193 | resMat1BottRows = workflow.resMat1BottRows; 194 | if ~last 195 | resMat1BottRows = workflow.permutationRows(resMat1BottRows); 196 | end 197 | fprintf(fid, ['> \t', matrixName, '[[', l2s(resMat1BottRows, ', '), '], [', l2s(mat1Cols, ', '), ']] := mat1[[', l2s(workflow.mat1BottRows, ' '), '], 1..-1]:\n']); 198 | end 199 | if size(workflow.mat2BottRows, 2) ~= 0 200 | resMat2BottRows = workflow.resMat2BottRows; 201 | if ~last 202 | resMat2BottRows = workflow.permutationRows(resMat2BottRows); 203 | end 204 | fprintf(fid, ['> \t', matrixName, '[[', l2s(resMat2BottRows, ', '), '], [', l2s(mat2Cols, ', '), ']] := mat2[[', l2s(workflow.mat2BottRows, ' '), '], 1..-1]:\n']); 205 | end 206 | 207 | %eliminate bottom rows of the matrix 208 | if size(workflow.bottomRows, 2) ~= 0 209 | bottomRows = workflow.bottomRows; 210 | if ~last 211 | bottomRows = workflow.permutationRows(bottomRows); 212 | end 213 | fprintf(fid, ['> \t', matrixName, '[[', l2s(bottomRows, ', '), '], [', l2s(workflow.resBottNonzeroCols, ', '), ']] := ReducedRowEchelonForm(', matrixName, '[[', l2s(bottomRows, ', '), '], [', l2s(workflow.resBottNonzeroCols, ', '), ']]):\n']); 214 | end 215 | 216 | fprintf(fid, '> \n'); 217 | 218 | if last 219 | %eliminate amrows 220 | elimRows = amrows(amrows > 0); 221 | elimRows = setdiff(elimRows, workflow.bottomRows); 222 | for col = workflow.noAmCols(workflow.BCols)' 223 | [pivotRow, ~] = find(workflow.res(workflow.bottomRows, col) == 1); 224 | if size(pivotRow, 1) ~= 0 225 | pivotRow = workflow.bottomRows(pivotRow); 226 | for row = elimRows' 227 | if row > 0 228 | if workflow.res(row, col) ~= 0 229 | fprintf(fid, ['> \t', matrixName, '[', int2str(row), ', 1..-1] := ', matrixName, '[', int2str(row), ', 1..-1] - ', matrixName, '[', int2str(row), ', ', int2str(col), ']*', matrixName, '[', int2str(pivotRow), ', 1..-1]:\n']); 230 | end 231 | end 232 | end 233 | end 234 | end 235 | fprintf(fid, '> \n'); 236 | else 237 | %eliminate all 238 | if isfield(workflow, 'elim') 239 | for elim = workflow.elim 240 | elim = elim{1}; 241 | if strcmp(elim.type, 'divide') 242 | fprintf(fid, ['> \t', matrixName, '[', int2str(elim.row), ', 1..-1] := ', matrixName, '[', int2str(elim.row), ', 1..-1]/', matrixName, '[', int2str(elim.row), ', ', int2str(elim.col), ']:\n']); 243 | elseif strcmp(elim.type, 'switch') 244 | fprintf(fid, ['> \t', matrixName, '[[', l2s(elim.rows, ', '), '], 1..-1] := ', matrixName, '[[', l2s(elim.rows(end:-1:1), ', '), '], 1..-1]:\n']); 245 | elseif strcmp(elim.type, 'eliminate') 246 | fprintf(fid, ['> \t', matrixName, '[', int2str(elim.row), ', 1..-1] := ', matrixName, '[', int2str(elim.row), ', 1..-1] - ', matrixName, '[', int2str(elim.row), ', ', int2str(elim.col), ']*', matrixName, '[', int2str(elim.pivotRow), ', 1..-1]:\n']); 247 | end 248 | end 249 | end 250 | end 251 | end 252 | 253 | end 254 | -------------------------------------------------------------------------------- /generator/gbs_ExportMatlabCode.m: -------------------------------------------------------------------------------- 1 | % Generate Matlab Code for given action matrix and coefficient matrices 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, mar2008 4 | % last edit by Pavel Trutman, May 2015 5 | 6 | 7 | function [res] = gbs_ExportMatlabCode(filename, M, trace, coefscode, known, knowngroups, unknown, algB, actMvar, amrows, amcols, gjcols, aidx, lastElim, cfg) 8 | 9 | [p, probname, e] = fileparts(filename); 10 | if isempty(e) 11 | filename = [filename '.m']; 12 | end; 13 | 14 | if (~isdir(p)) 15 | mkdir(p); 16 | end 17 | 18 | if isempty(knowngroups) 19 | knowngroups = 1:length(known); 20 | end 21 | 22 | % generate coefs calculation code 23 | knvars=[]; 24 | knvarnames=[]; 25 | knvarcnt=[]; 26 | for i=1:length(known) 27 | 28 | if length(knvars) >= knowngroups(i) 29 | knvars{knowngroups(i)} = [knvars{knowngroups(i)} sym(known{i})]; 30 | knvarcnt(knowngroups(i)) = knvarcnt(knowngroups(i)) + 1; 31 | else 32 | knvars{knowngroups(i)} = sym(known{i}); 33 | knvarcnt(knowngroups(i)) = 1; 34 | end 35 | 36 | if length(knvarnames) < knowngroups(i) || isempty(knvarnames(knowngroups(i))) 37 | 38 | name=known(i); 39 | knvarnames{knowngroups(i)} = name{1}; 40 | end 41 | end 42 | 43 | fid = fopen(filename, 'w'); 44 | 45 | fprintf(fid, '%% Generated using GBSolver generator Copyright Martin Bujnak,\n'); 46 | fprintf(fid, '%% Zuzana Kukelova, Tomas Pajdla CTU Prague 2008.\n%% \n'); 47 | fprintf(fid, '%% Please refer to the following paper, when using this code :\n'); 48 | fprintf(fid, '%% Kukelova Z., Bujnak M., Pajdla T., Automatic Generator of Minimal Problem Solvers,\n'); 49 | fprintf(fid, '%% ECCV 2008, Marseille, France, October 12-18, 2008\n'); 50 | fprintf(fid, '\n'); 51 | if cfg.benchmark.enable 52 | fprintf(fid, ['function [unknowns, time] = ' probname '(args)\n\n']); 53 | else 54 | fprintf(fid, ['function [' c2s((unknown), ', ') '] = ' probname '(' c2s(knvarnames, ', ') ')\n\n']); 55 | end 56 | 57 | if cfg.benchmark.enable 58 | fprintf(fid, '\t%% This is a benchmark solver!\n\n'); 59 | for i = 1:length(knvarnames) 60 | fprintf(fid, ['\t', c2s(knvarnames(i)), ' = args(', int2str(i), ', :);\n']); 61 | end 62 | fprintf(fid, '\n'); 63 | fprintf(fid, '\ttic;\n'); 64 | fprintf(fid, '\n'); 65 | end 66 | 67 | % coeffs 68 | fprintf(fid, '\t%% precalculate polynomial equations coefficients\n'); 69 | for i=1:length(coefscode) 70 | 71 | % rename coefficients according to "knowngroups" 72 | coefcode = char(coefscode(i)); 73 | 74 | for j=1:length(knvars) 75 | if length(knvars{j}) > 1 76 | for k=1:length(knvars{j}) 77 | coefcode = regexprep([coefcode, ' '], [char(knvars{j}(k)), '([^0-9\(])'], [knvarnames{j} '(' int2str(k) ')$1']); 78 | end 79 | end 80 | end 81 | 82 | fprintf(fid, ['\tc(' int2str(i) ') = ' regexprep(coefcode, '\s*$', '') ';\n']); 83 | end 84 | fprintf(fid, '\n'); 85 | 86 | 87 | % Generate code using different methods 88 | CodeGenerator = str2func(['CodeGen_Matlab_', cfg.PolynomialsGenerator]); 89 | CodeGenerator(trace, lastElim, gjcols, @rrefPart, coefscode, fid); 90 | 91 | 92 | % action matrix 93 | fprintf(fid, ['\tA = zeros(' int2str(length(amrows)) ');\n']); 94 | fprintf(fid, ['\tamcols = [' l2s(amcols, ' ') '];\n']); 95 | for i=1:length(amrows) 96 | 97 | if amrows(i) < 0 98 | fprintf(fid, ['\tA(' int2str(i) ', ' int2str(-amrows(i)) ') = 1;\n']); 99 | else 100 | fprintf(fid, ['\tA(' int2str(i) ', :) = -M(' int2str(amrows(i)) ', amcols);\n']); 101 | end 102 | end 103 | fprintf(fid, '\n'); 104 | 105 | % solution extraction 106 | 107 | fprintf(fid, '\t[V D] = eig(A);\n'); 108 | 109 | [oneidx, unksidx] = gbs_GetVariablesIdx(algB, unknown); 110 | varsinvec = find(unksidx > 0); 111 | 112 | fprintf(fid, ['\tsol = V([' l2s(unksidx(varsinvec), ', ') '],:)./(ones(' int2str(length(varsinvec)) ', ' int2str(oneidx) ')*V(' int2str(oneidx) ',:));\n']); 113 | fprintf(fid, '\n'); 114 | 115 | fprintf(fid, '\tif (find(isnan(sol(:))) > 0)\n\t\t\n'); 116 | 117 | % division by zero filter 118 | ucnt = length(unknown); 119 | for i=1:ucnt 120 | 121 | fprintf(fid, ['\t\t' unknown{i} ' = zeros(1, 0);\n']); 122 | end 123 | 124 | fprintf(fid, '\telse\n\t\t\n'); 125 | 126 | % extract variables 127 | if (sum(unksidx == 0)) > 0 128 | 129 | idx = find(unksidx == 0); 130 | if (length(idx) > 1) 131 | 132 | fprintf(fid, '\t\tWARNING: cannot extract all unknowns at once. A back-substitution required (not implemented/automatized)\n'); 133 | end 134 | 135 | fprintf(fid, ['\t\tev = diag(D);\n']); 136 | fprintf(fid, ['\t\tI = find(not(imag( sol(1,:) )) & not(imag( ev )));\n']); 137 | else 138 | fprintf(fid, ['\t\tI = find(not(imag( sol(1,:) )));\n']); 139 | end 140 | 141 | ui = 1; 142 | for i=1:ucnt 143 | 144 | if unksidx(i) == 0 145 | 146 | % action variable ? 147 | if strcmp(actMvar, unknown{i}) 148 | 149 | fprintf(fid, ['\t\t' unknown{i} ' = ev(I);\n']); 150 | else 151 | 152 | fprintf(fid, '\t\tWARNING: one or more unknowns could not be extracted.\n'); 153 | end 154 | 155 | else 156 | fprintf(fid, ['\t\t' unknown{i} ' = sol(' int2str(ui) ',I);\n']); 157 | ui = ui+1; 158 | end 159 | end 160 | 161 | fprintf(fid, '\tend\n'); 162 | 163 | if cfg.benchmark.enable 164 | fprintf(fid, '\n'); 165 | fprintf(fid, '\ttime = toc;\n'); 166 | fprintf(fid, '\n'); 167 | fprintf(fid, '\t%%save benchmark data\n'); 168 | for i = 1:length(unknown) 169 | fprintf(fid, ['\tunknowns(', int2str(i), ', :) = ', c2s(unknown(i)), ';\n']); 170 | end 171 | fprintf(fid, '\n'); 172 | end 173 | 174 | fprintf(fid, 'end\n'); 175 | 176 | fclose(fid); 177 | 178 | 179 | function [] = rrefPart(workflow, matrixName, last) 180 | %matrix elimination with partitioning 181 | fprintf(fid, '\n\t%%GJ elimination with partitioning\n'); 182 | 183 | %first part of matrix 184 | mat1Cols = [workflow.noAmCols(:, [workflow.ACols1; workflow.BCols]) workflow.amCols]; 185 | %fprintf(fid, ['\tmat1 = ', matrixName, '([', l2s(workflow.PRows1, ' '), '], [', l2s(mat1Cols, ' '), ']);\n']); 186 | %fprintf(fid, ['\tmat1(:, [', l2s(workflow.mat1NonzeroCols, ' '), ']) = rref(mat1(:, [', l2s(workflow.mat1NonzeroCols, ' '), ']));\n']); 187 | fprintf(fid, ['\tmat1 = zeros([', l2s([length(workflow.PRows1) length(mat1Cols)], ' '), ']);\n']); 188 | fprintf(fid, ['\tmat1(:, [', l2s(workflow.mat1NonzeroCols, ' '), ']) = rref(', matrixName, '([', l2s(workflow.PRows1, ' '), '], [', l2s(mat1Cols(workflow.mat1NonzeroCols), ' '), ']));\n']); 189 | 190 | %second part of matrix 191 | mat2Cols = [workflow.noAmCols(:, [workflow.ACols2; workflow.BCols]) workflow.amCols]; 192 | %fprintf(fid, ['\tmat2 = ', matrixName, '([', l2s(workflow.PRows2, ' '), '], [', l2s(mat2Cols, ' '), ']);\n']); 193 | %fprintf(fid, ['\tmat2(:, [', l2s(workflow.mat2NonzeroCols, ' '), ']) = rref(mat2(:, [', l2s(workflow.mat2NonzeroCols, ' '), ']));\n\n']); 194 | fprintf(fid, ['\tmat2 = zeros([', l2s([length(workflow.PRows2) length(mat2Cols)], ' '), ']);\n']); 195 | fprintf(fid, ['\tmat2(:, [', l2s(workflow.mat2NonzeroCols, ' '), ']) = rref(', matrixName, '([', l2s(workflow.PRows2, ' '), '], [', l2s(mat2Cols(workflow.mat2NonzeroCols), ' '), ']));\n']); 196 | 197 | %assemble both parts together 198 | fprintf(fid, ['\t', matrixName, ' = zeros([', l2s(size(workflow.res), ' '), ']);\n']); 199 | if size(workflow.mat1TopRows, 2) + size(workflow.mat1BottRows, 2) ~= 0 200 | resMat1TopRows = workflow.resMat1TopRows; 201 | resMat1BottRows = workflow.resMat1BottRows; 202 | if ~last 203 | resMat1TopRows = workflow.permutationRows(resMat1TopRows)'; 204 | resMat1BottRows = workflow.permutationRows(resMat1BottRows)'; 205 | end 206 | fprintf(fid, ['\t', matrixName, '([', l2s([resMat1TopRows resMat1BottRows], ' '), '], [', l2s(mat1Cols, ' '), ']) = mat1([', l2s([workflow.mat1TopRows workflow.mat1BottRows], ' '), '], :);\n']); 207 | end 208 | if size(workflow.mat2TopRows, 2) + size(workflow.mat2BottRows, 2) ~= 0 209 | resMat2TopRows = workflow.resMat2TopRows; 210 | resMat2BottRows = workflow.resMat2BottRows; 211 | if ~last 212 | resMat2TopRows = workflow.permutationRows(resMat2TopRows)'; 213 | resMat2BottRows = workflow.permutationRows(resMat2BottRows)'; 214 | end 215 | fprintf(fid, ['\t', matrixName, '([', l2s([resMat2TopRows resMat2BottRows], ' '), '], [', l2s(mat2Cols, ' '), ']) = mat2([', l2s([workflow.mat2TopRows workflow.mat2BottRows], ' '), '], :);\n']); 216 | end 217 | %if size(workflow.mat1BottRows, 2) ~= 0 218 | % resMat1BottRows = workflow.resMat1BottRows; 219 | % if ~last 220 | % resMat1BottRows = workflow.permutationRows(resMat1BottRows); 221 | % end 222 | % fprintf(fid, ['\t', matrixName, '([', l2s(resMat1BottRows, ' '), '], [', l2s(mat1Cols, ' '), ']) = mat1([', l2s(workflow.mat1BottRows, ' '), '], :);\n']); 223 | %end 224 | %if size(workflow.mat2BottRows, 2) ~= 0 225 | % resMat2BottRows = workflow.resMat2BottRows; 226 | % if ~last 227 | % resMat2BottRows = workflow.permutationRows(resMat2BottRows); 228 | % end 229 | % fprintf(fid, ['\t', matrixName, '([', l2s(resMat2BottRows, ' '), '], [', l2s(mat2Cols, ' '), ']) = mat2([', l2s(workflow.mat2BottRows, ' '), '], :);\n']); 230 | %end 231 | 232 | %eliminate bottom rows of the matrix 233 | if size(workflow.bottomRows, 2) ~= 0 234 | bottomRows = workflow.bottomRows; 235 | if ~last 236 | bottomRows = workflow.permutationRows(bottomRows); 237 | end 238 | fprintf(fid, ['\t', matrixName, '([', l2s(bottomRows, ' '), '], [', l2s(workflow.resBottNonzeroCols, ' '), ']) = rref(', matrixName, '([', l2s(bottomRows, ' '), '], [', l2s(workflow.resBottNonzeroCols, ' '), ']));\n']); 239 | end 240 | 241 | fprintf(fid, '\n'); 242 | 243 | if last 244 | %eliminate amrows 245 | elimRows = amrows(amrows > 0); 246 | elimRows = setdiff(elimRows, workflow.bottomRows); 247 | for col = workflow.noAmCols(workflow.BCols)' 248 | [pivotRow, ~] = find(workflow.res(workflow.bottomRows, col) == 1); 249 | if size(pivotRow, 1) ~= 0 250 | pivotRow = workflow.bottomRows(pivotRow); 251 | for row = elimRows' 252 | if row > 0 253 | if workflow.res(row, col) ~= 0 254 | fprintf(fid, ['\t', matrixName, '(', int2str(row), ', :) = ', matrixName, '(', int2str(row), ', :) - ', matrixName, '(', int2str(row), ', ', int2str(col), ')*', matrixName, '(', int2str(pivotRow), ', :);\n']); 255 | end 256 | end 257 | end 258 | end 259 | end 260 | fprintf(fid, '\n'); 261 | else 262 | %eliminate all 263 | if isfield(workflow, 'elim') 264 | for elim = workflow.elim 265 | elim = elim{1}; 266 | if strcmp(elim.type, 'divide') 267 | fprintf(fid, ['\t', matrixName, '(', int2str(elim.row), ', :) = ', matrixName, '(', int2str(elim.row), ', :)/', matrixName, '(', int2str(elim.row), ', ', int2str(elim.col), ');\n']); 268 | elseif strcmp(elim.type, 'switch') 269 | fprintf(fid, ['\t', matrixName, '([', l2s(elim.rows, ' '), '], :) = ', matrixName, '([', l2s(elim.rows(end:-1:1), ' '), '], :);\n']); 270 | elseif strcmp(elim.type, 'eliminate') 271 | fprintf(fid, ['\t', matrixName, '(', int2str(elim.row), ', :) = ', matrixName, '(', int2str(elim.row), ', :) - ', matrixName, '(', int2str(elim.row), ', ', int2str(elim.col), ')*', matrixName, '(', int2str(elim.pivotRow), ', :);\n']); 272 | end 273 | end 274 | end 275 | end 276 | end 277 | 278 | end 279 | -------------------------------------------------------------------------------- /generator/gbs_GeneratePolynomials_F4.m: -------------------------------------------------------------------------------- 1 | % Generate all polynomials required to build an action matrix. Polynomials 2 | % are generated with using some strategies from F4 algorithm. 3 | 4 | % last edit by Pavel Trutman, April 2015 5 | 6 | function [foundVar, G, trace] = gbs_GeneratePolynomials_F4(p, eq, unknown, maxdeg, alldegs, allmonsdeg, allmons, amStats, cfg, algorithmCfg) 7 | 8 | global prime; 9 | global maxorder; 10 | global allDegs; 11 | global maxDeg; 12 | global unknowns; 13 | global allMons; 14 | global ordering; 15 | global GRefs; 16 | global input; 17 | 18 | prime = cfg.prime; 19 | Sel = algorithmCfg.Sel; 20 | maxorder = length(allmons); 21 | allDegs = alldegs; 22 | maxDeg = maxdeg; 23 | unknowns = unknown; 24 | allMons = allmons; 25 | ordering = cfg.ordering; 26 | input = p; 27 | 28 | d = 0; 29 | G = zeros(0, maxorder); 30 | P = cell(0, 1); 31 | GRefs = zeros(0, 2); 32 | GCoefs = zeros(0, maxorder); 33 | 34 | % make pairs 35 | for i = 1:length(p) 36 | f = zeros(1, maxorder); 37 | for j = 1:p{i}.monscnt 38 | order = GetMonomialOrder(p{i}.deg(j, :), unknowns); 39 | f(1, maxorder - order + 1) = p{i}.coefs(j); 40 | end 41 | [G, P, GRefs, GCoefs] = Update(G, P, f, GRefs, GCoefs, 0, i); 42 | end 43 | 44 | % itarate over pairs 45 | while length(P) ~= 0 46 | d = d + 1; 47 | F{d} = zeros(0, 0); 48 | Ft{d} = zeros(0, 0); 49 | 50 | % select pairs 51 | [PSel{d}, P] = Sel(P); 52 | 53 | % put left a right sides of pairs together 54 | L{d} = cell(0, 1); 55 | last = 0; 56 | for i = 1:length(PSel{d}) 57 | 58 | left = true; 59 | right = true; 60 | % check duplicity of pairs 61 | for j = 1:length(L{d}) 62 | if(left && size(L{d}{j}.polynomial, 2) == size(PSel{d}{i}.left.polynomial, 2) && sum(L{d}{j}.monomial ~= PSel{d}{i}.left.monomial) == 0 && sum(L{d}{j}.polynomial ~= PSel{d}{i}.left.polynomial) == 0) 63 | left = false; 64 | end 65 | if(right && size(L{d}{j}.polynomial, 2) == size(PSel{d}{i}.right.polynomial, 2) && sum(L{d}{j}.monomial ~= PSel{d}{i}.right.monomial) == 0 && sum(L{d}{j}.polynomial ~= PSel{d}{i}.right.polynomial) == 0) 66 | right = false; 67 | end 68 | if(~left && ~right) 69 | break; 70 | end 71 | end 72 | 73 | if left 74 | last = last + 1; 75 | L{d}{last} = PSel{d}{i}.left; 76 | end 77 | if right 78 | last = last + 1; 79 | L{d}{last} = PSel{d}{i}.right; 80 | end 81 | end 82 | 83 | % reducto 84 | [FtplusNew, FNew, FtNew, FRefs, traceRefs, traceCoefs] = Reduction(L{d}, G, F, Ft); 85 | 86 | if size(FtplusNew, 1) ~= 0 87 | 88 | Ftplus{d} = FtplusNew; 89 | F{d} = FNew; 90 | Ft{d} = FtNew; 91 | 92 | trace{d}.refs = traceRefs; 93 | trace{d}.coefs = traceCoefs; 94 | trace{d}.nonzero = sort(find(sum(FNew) ~= 0), 'ascend'); 95 | 96 | % insert new pairs 97 | for i = 1:size(Ftplus{d}, 1) 98 | [G, P, GRefs, GCoefs] = Update(G, P, Ftplus{d}(i, :), GRefs, GCoefs, d, FRefs(i, 1)); 99 | end 100 | 101 | % recompute amStats 102 | for a = 1:length(amStats) 103 | amStats{a}.zero_el = setdiff(1:size(G, 2), (size(G, 2) + 1) - amStats{a}.algBidx); 104 | end 105 | 106 | % check conditions for the action matrix 107 | foundVar = gbs_CheckActionMatrixConditions(G, amStats, false, prime); 108 | 109 | if foundVar 110 | break; 111 | end 112 | 113 | else 114 | %nothing added into G, therefore last elimination can be removed 115 | fprintf(' Nothing is added into G, removing last elimination from the template\n'); 116 | d = d - 1; 117 | end 118 | 119 | end 120 | 121 | if foundVar == 0 122 | % add required polynomials to be able to build the action matrix 123 | [foundVar, ordersReq] = gbs_CheckActionMatrixConditions(G, amStats, false, prime); 124 | 125 | if (max(ordersReq) > maxorder) || (size(G, 2) < maxorder) 126 | % enlarge the matrix 127 | while max(ordersReq) > maxorder 128 | maxDeg = maxDeg + 1; 129 | [mons, degs] = GenerateMonomials(maxDeg, unknowns, ordering); 130 | allDegs = [degs; allDegs]; 131 | allMons = [mons, allMons]; 132 | maxorder = size(allMons, 2); 133 | end 134 | 135 | G = [zeros(size(G, 1), maxorder - size(G, 2)) G]; 136 | GCoefs = [zeros(size(GCoefs, 1), maxorder - size(GCoefs, 2)) GCoefs]; 137 | 138 | % recompute amStats 139 | for a = 1:length(amStats) 140 | amStats{a}.zero_el = setdiff(1:size(G, 2), (size(G, 2) + 1) - amStats{a}.algBidx); 141 | end 142 | 143 | end 144 | 145 | % get head monomials and monomials of all polynomials from G 146 | headMonsGDegs = zeros(size(G, 1), size(allDegs, 2)); 147 | monomials = []; 148 | for i = 1:size(G, 1) 149 | index = find(G(i, :)); 150 | headMonsGDegs(i, :) = allDegs(end - size(G, 2) + index(1), :); 151 | monomials = [monomials, size(G, 2) - index + 1]; 152 | end 153 | 154 | done = unique(monomials); 155 | 156 | % add required polynomials 157 | GAdd = zeros(length(ordersReq), maxorder); 158 | GCoefsAdd = zeros(length(ordersReq), maxorder); 159 | GRefsAdd = zeros(length(ordersReq), 2); 160 | ordersReq = sort(ordersReq, 'descend'); 161 | i = 1; 162 | while isempty(ordersReq) == 0 163 | order = ordersReq(1); 164 | done = [done, order]; 165 | ordersReq = setdiff(ordersReq, order); 166 | reqDeg = allDegs(end - order + 1, :); 167 | for j = 1:size(headMonsGDegs, 1) 168 | if sum((reqDeg - headMonsGDegs(j, :)) < 0) == 0 169 | [monomial, polynomial, matrixId, polRow] = Simplify(reqDeg - headMonsGDegs(j, :), G(j, :), F, Ft, GRefs(j, 1), GRefs(j, 2)); 170 | [f, coefs] = Multiply(monomial, polynomial, [matrixId, polRow]); 171 | GAdd(i, :) = f; 172 | GCoefsAdd(i, :) = coefs; 173 | GRefsAdd(i, :) = [matrixId, polRow]; 174 | index = find(GAdd(i, :)); 175 | mons = size(GAdd, 2) - index + 1; 176 | ordersReq = unique([ordersReq; setdiff(mons, done)]); 177 | i = i + 1; 178 | break; 179 | end 180 | end 181 | 182 | end 183 | 184 | G = [GAdd; G]; 185 | GCoefs = [GCoefsAdd; GCoefs]; 186 | GRefs = [GRefsAdd; GRefs]; 187 | 188 | % check conditions for the action matrix 189 | foundVar = gbs_CheckActionMatrixConditions(G, amStats, false, prime); 190 | 191 | end 192 | 193 | nonzero = find(sum(G) ~= 0); 194 | fprintf('Groebner basis of size %dx%d generated\n', size(G, 1), length(nonzero)); 195 | 196 | % remove redundant polynomials 197 | filter = gbs_RemoveRedundant(G, prime); 198 | G = G(filter, :); 199 | GCoefs = GCoefs(filter, :); 200 | GRefs = GRefs(filter, :); 201 | 202 | % remove not necesary polynomials 203 | RemoveUnnecessary = str2func(['gbs_RemoveUnnecessary_', cfg.RemoveUnnecessary]); 204 | [filter, foundVar] = RemoveUnnecessary(G, amStats, foundVar, prime); 205 | %filter = gbs_RemoveUnnecessary(G, amStats, foundVar, prime); 206 | G = G(filter, :); 207 | GCoefs = GCoefs(filter, :); 208 | GRefs = GRefs(filter, :); 209 | 210 | trace{d + 1}.refs = GRefs; 211 | trace{d + 1}.coefs = GCoefs; 212 | 213 | end 214 | 215 | 216 | 217 | % Update (Buchberger) 218 | 219 | function [GNew, BNew, GNewRefs, GNewCoefs] = Update(GOld, BOld, h, GOldRefs, GOldCoefs, hMatrixId, hPolRow) 220 | 221 | global maxorder; 222 | global allDegs; 223 | global input; 224 | 225 | % get HM of h 226 | hOrder = size(h, 2) - find(h, 1, 'first') + 1; 227 | hDeg = allDegs(end - hOrder + 1, :); 228 | 229 | if size(GOld, 2) < maxorder 230 | GOld = [zeros(size(GOld, 1), maxorder - size(GOld, 2)), GOld]; 231 | GOldCoefs = [zeros(size(GOldCoefs, 1), maxorder - size(GOldCoefs, 2)), GOldCoefs]; 232 | end 233 | 234 | D = zeros(0, maxorder); 235 | C = GOld; 236 | DRefs = zeros(0, 2); 237 | CRefs = GOldRefs; 238 | 239 | % go throught C 240 | for i = 1:size(C, 1) 241 | % get HM of g 242 | gOrder = size(C, 2) - find(C(i, :), 1, 'first') + 1; 243 | gDeg = allDegs(end - gOrder + 1, :); 244 | 245 | % are HM(h) and HM(C(i)) disjoint? 246 | if sum(min([hDeg; gDeg], [], 1)) == 0 247 | % are disjoint 248 | D = [D; C(i, :)]; 249 | DRefs = [DRefs; CRefs(i, :)]; 250 | else 251 | lcmHG = max([hDeg; gDeg], [], 1); 252 | condition1 = true; 253 | for j = i + 1:size(C, 1) 254 | %get HM of g2 255 | g2Order = size(C, 2) - find(C(j, :), 1, 'first') + 1; 256 | g2Deg = allDegs(end - g2Order + 1, :); 257 | lcmHG2 = max([hDeg; g2Deg], [], 1); 258 | % check first condition of divisibility 259 | if sum(lcmHG2 <= lcmHG) == size(lcmHG, 2) 260 | condition1 = false; 261 | break; 262 | end 263 | end 264 | 265 | if condition1 266 | condition2 = true; 267 | for j = 1:size(D, 1) 268 | g2Order = size(D, 2) - find(D(j, :), 1, 'first') + 1; 269 | g2Deg = allDegs(end - g2Order + 1, :); 270 | lcmHG2 = max([hDeg; g2Deg], [], 1); 271 | % check second condition of divisibility 272 | if sum(lcmHG2 <= lcmHG) == size(lcmHG, 2) 273 | condition2 = false; 274 | break; 275 | end 276 | end 277 | 278 | if condition2 279 | % all conditions satisfied 280 | D = [D; C(i, :)]; 281 | DRefs = [DRefs; CRefs(i, :)]; 282 | end 283 | end 284 | 285 | end 286 | end 287 | 288 | E = cell(0, 1); 289 | last = 0; 290 | % go throught D 291 | for i = 1:size(D, 1) 292 | % get HM of g 293 | gOrder = size(D, 2) - find(D(i, :), 1, 'first') + 1; 294 | gDeg = allDegs(end - gOrder + 1, :); 295 | if sum(min([hDeg; gDeg], [], 1)) ~= 0 296 | % are not disjoint 297 | lcmHG = max([hDeg; gDeg], [], 1); 298 | % create pair 299 | last = last + 1; 300 | E{last, 1}.left.polynomial = h; 301 | E{last, 1}.left.monomial = lcmHG - hDeg; 302 | E{last, 1}.left.matrixId = hMatrixId; 303 | E{last, 1}.left.polRow = hPolRow; 304 | E{last, 1}.right.polynomial = D(i, :); 305 | E{last, 1}.right.monomial = lcmHG - gDeg; 306 | E{last, 1}.right.matrixId = DRefs(i, 1); 307 | E{last, 1}.right.polRow = DRefs(i, 2); 308 | E{last, 1}.lcm = lcmHG; 309 | end 310 | end 311 | 312 | BNew = cell(0, 1); 313 | last = 0; 314 | % go thorought BOld 315 | for i = 1:length(BOld) 316 | % get HM of g1 and g2 317 | g1Order = size(BOld{i}.left.polynomial, 2) - find(BOld{i}.left.polynomial, 1, 'first') + 1; 318 | g1Deg = allDegs(end - g1Order + 1, :); 319 | g2Order = size(BOld{i}.right.polynomial, 2) - find(BOld{i}.right.polynomial, 1, 'first') + 1; 320 | g2Deg = allDegs(end - g2Order + 1, :); 321 | 322 | if (sum(hDeg < BOld{i}.lcm) < size(hDeg, 2)) || (sum(max([hDeg; g1Deg], [], 1) ~= BOld{i}.lcm) == 0) || (sum(max([hDeg; g2Deg], [], 1) ~= BOld{i}.lcm) == 0) 323 | % add pair 324 | last = last + 1; 325 | BNew{last, 1} = BOld{i}; 326 | end 327 | end 328 | 329 | % add E into BNew 330 | BNew = vertcat(BNew, E); 331 | 332 | GNew = zeros(0, maxorder); 333 | GNewRefs = zeros(0, 2); 334 | GNewCoefs = zeros(0, maxorder); 335 | last = 0; 336 | % go thorought GOld 337 | for i = 1:size(GOld, 1) 338 | % get HM of g 339 | gOrder = size(GOld, 2) - find(GOld(i, :), 1, 'first') + 1; 340 | gDeg = allDegs(end - gOrder + 1, :); 341 | 342 | if sum(hDeg <= gDeg) < size(hDeg, 2) 343 | last = last + 1; 344 | GNew(last, :) = GOld(i, :); 345 | GNewRefs(last, :) = GOldRefs(i, :); 346 | GNewCoefs(last, :) = GOldCoefs(i, :); 347 | end 348 | end 349 | 350 | % add h into GNew 351 | GNew(end + 1, :) = h; 352 | GNewRefs(end + 1, :) = [hMatrixId, hPolRow]; 353 | 354 | last = size(GNewCoefs, 1) + 1; 355 | orders = size(h, 2) - find(h) + 1; 356 | for order = orders 357 | deg = allDegs(maxorder - order + 1, :); 358 | if hMatrixId ~= 0 359 | % input polynomial from some matrix F 360 | GNewCoefs(last, maxorder - order + 1) = order; 361 | else 362 | % input polynomial from the input set 363 | GNewCoefs(last, maxorder - order + 1) = input{hPolRow}.coefsIDX(find(ismember(input{hPolRow}.deg, deg, 'rows'), 1, 'first')); 364 | end 365 | end 366 | 367 | end 368 | 369 | 370 | 371 | % Reduction (F4) 372 | 373 | function [Ftplus, F, Ft, FtRefs, traceRefs, traceCoefs] = Reduction(L, G, FAll, FtAll) 374 | 375 | global prime; 376 | global maxorder; 377 | 378 | [F, traceRefs, traceCoefs] = SymbolicPreprocessing(L, G, FAll, FtAll); 379 | nonzero = find(sum(F) ~= 0); 380 | fprintf(' Matrix of size %dx%d obtained\n', size(F, 1), length(nonzero)); 381 | 382 | % remove redundant polynomials 383 | filter = gbs_RemoveRedundant(F, prime); 384 | F = F(filter, :); 385 | traceRefs = traceRefs(filter, :); 386 | traceCoefs = traceCoefs(filter, :); 387 | 388 | nonzero = find(sum(F) ~= 0); 389 | Kk = F(:, nonzero); 390 | fprintf(' Reducing matrix %dx%d\n', size(Kk, 1), size(Kk, 2)); 391 | B = gjzpsp(Kk, prime); 392 | Ft = zeros(size(F, 1), size(F, 2)); 393 | Ft(:, nonzero) = B; 394 | 395 | % pick head monomials 396 | HM = zeros(0, 1); 397 | for i = 1:size(F, 1) 398 | index = find(F(i, :), 1, 'first'); 399 | if ~isempty(index) 400 | HM = [HM; index]; 401 | end 402 | end 403 | 404 | % pick rows with new head monomials 405 | last = 0; 406 | Ftplus = zeros(0, maxorder); 407 | FtRefs = zeros(0, 1); 408 | for i = 1:size(F, 1) 409 | index =find(Ft(i, :), 1, 'first'); 410 | if ~isempty(index) 411 | if sum(HM == index) == 0 412 | last = last + 1; 413 | Ftplus(last, :) = Ft(i, :); 414 | FtRefs(last, 1) = i; 415 | end 416 | end 417 | end 418 | 419 | end 420 | 421 | 422 | 423 | % Symbolic Preprocessing (F4) 424 | 425 | function [F, traceRefs, traceCoefs] = SymbolicPreprocessing(L, G, FAll, FtAll) 426 | 427 | global maxorder; 428 | global allDegs; 429 | global GRefs; 430 | 431 | % multiply polynomials from pairs and parse used monomials 432 | monomials = zeros(0, 1); 433 | headMonomials = zeros(0, 1); 434 | F = zeros(length(L), maxorder); 435 | traceRefs = zeros(length(L), 2); 436 | traceCoefs = zeros(length(L), maxorder); 437 | for i = 1:length(L) 438 | [monomial, polynomial, matrixId, polRow] = Simplify(L{i}.monomial, L{i}.polynomial, FAll, FtAll, L{i}.matrixId, L{i}.polRow); 439 | [f, coefs] = Multiply(monomial, polynomial, [matrixId, polRow]); 440 | if size(f, 2) > size(F, 2) 441 | F = [zeros(size(F, 1), size(f, 2) - size(F, 2)), F]; 442 | traceCoefs = [zeros(size(traceCoefs, 1), size(coefs, 2) - size(traceCoefs, 2)), traceCoefs]; 443 | end 444 | F(i, :) = f; 445 | traceRefs(i, :) = [matrixId, polRow]; 446 | traceCoefs(i, :) = coefs; 447 | indices = find(F(i, :)); 448 | headMonomials = unique([headMonomials; size(F, 2) - indices(1) + 1]); 449 | monomials = unique([monomials; size(F, 2) - indices(2:end)' + 1]); 450 | end 451 | 452 | % get head monomials of all polynomials from G 453 | headMonsGDegs = zeros(size(G, 1), size(allDegs, 2)); 454 | for i = 1:size(G, 1) 455 | index = find(G(i, :), 1, 'first'); 456 | headMonsGDegs(i, :) = allDegs(end - size(G, 2) + index, :); 457 | end 458 | 459 | done = headMonomials; 460 | remaining = setdiff(monomials, headMonomials); 461 | 462 | % go throught all monomials 463 | while isempty(remaining) == 0 464 | m = remaining(end); 465 | remaining = setdiff(remaining, m); 466 | done = [done; m]; 467 | 468 | for i = 1:size(headMonsGDegs, 1) 469 | if sum((allDegs(end - m + 1, :) - headMonsGDegs(i, :)) < 0) == 0 470 | [monomial, polynomial, matrixId, polRow] = Simplify(allDegs(end - m + 1, :) - headMonsGDegs(i, :), G(i, :), FAll, FtAll, GRefs(i, 1), GRefs(i, 2)); 471 | [f, coefs] = Multiply(monomial, polynomial, [matrixId, polRow]); 472 | F = [F; f]; 473 | traceRefs = [traceRefs; matrixId, polRow]; 474 | traceCoefs = [traceCoefs; coefs]; 475 | indices = find(F(end, :)); 476 | mons = size(F, 2) - indices' + 1; 477 | remaining = unique([remaining; setdiff(mons, done)]); 478 | break; 479 | end 480 | end 481 | 482 | end 483 | 484 | end 485 | 486 | 487 | 488 | % Simplify (F4) 489 | 490 | function [monomial, polynomial, matrixIdNew, polRowNew] = Simplify(m, f, FAll, FtAll, matrixId, polRow) 491 | 492 | % get divisors of m 493 | u = GetDivisors(m); 494 | u = setdiff(u, zeros(size(m)), 'rows'); 495 | 496 | [~, IX] = sort(sum(u, 2), 'ascend'); 497 | u = u(IX, :); 498 | 499 | % go trought all divisors of m 500 | for i = 1:size(u, 1) 501 | uf = Multiply(u(i, :), f); 502 | 503 | % go thorught FAll 504 | for j = 1:length(FAll) - 1 505 | %if exists u*f in FAll{j} 506 | if sum(sum(([zeros(size(FAll{j}, 1), size(uf, 2)-size(FAll{j}, 2)) FAll{j}] - ones(size(FAll{j}, 1), 1)*uf) ~= 0, 2) == 0) 507 | HMuf = size(uf, 2) - find(uf, 1, 'first') + 1; 508 | 509 | % find HM of FtAll{j} such equals to HM(u*f) 510 | for k = 1:size(FtAll{j}, 1) 511 | if (size(FtAll{j}, 2) - find(FtAll{j}(k, :), 1, 'first') + 1) == HMuf 512 | 513 | if sum(u(i, :) ~= m) ~= 0 514 | [monomial, polynomial, matrixIdNew, polRowNew] = Simplify(m - u(i, :), FtAll{j}(k, :), FAll, FtAll, j, k); 515 | return; 516 | else 517 | monomial = zeros(size(m)); 518 | polynomial = FtAll{j}(k, :); 519 | matrixIdNew = j; 520 | polRowNew = k; 521 | return; 522 | end 523 | 524 | end 525 | end 526 | end 527 | end 528 | end 529 | 530 | matrixIdNew = matrixId; 531 | polRowNew = polRow; 532 | monomial = m; 533 | polynomial = f; 534 | 535 | end 536 | 537 | 538 | 539 | % Multiply 540 | % Multiplies monomial m and polynomial f 541 | 542 | function [polynomial, coefs] = Multiply(m, f, source) 543 | 544 | global maxorder; 545 | global maxDeg; 546 | global unknowns; 547 | global allDegs; 548 | global allMons; 549 | global ordering; 550 | global input; 551 | 552 | if nargin < 3 553 | source = [-1 -1]; 554 | end 555 | 556 | polynomial = zeros(1, maxorder); 557 | coefs = zeros(1, maxorder); 558 | % multiply each monomial of f 559 | orders = size(f, 2) - find(f) + 1; 560 | for order = orders 561 | deg = allDegs(maxorder - order + 1, :); 562 | newOrder = GetMonomialOrder(deg + m, unknowns); 563 | 564 | if newOrder > maxorder 565 | % enlarge matrix dimensions 566 | while newOrder > maxorder 567 | maxDeg = maxDeg + 1; 568 | [mons, degs] = GenerateMonomials(maxDeg, unknowns, ordering); 569 | allDegs = [degs; allDegs]; 570 | allMons = [mons, allMons]; 571 | maxorder = size(allMons, 2); 572 | end 573 | polynomial = [zeros(1, maxorder - size(polynomial, 2)), polynomial]; 574 | coefs = [zeros(1, maxorder - size(coefs, 2)), coefs]; 575 | end 576 | 577 | % numbers 578 | polynomial(1, maxorder - newOrder + 1) = f(1, size(f, 2) - order + 1); 579 | 580 | % coefs 581 | if source(1, 1) ~= 0 582 | % from other matrix F 583 | coefs(1, maxorder - newOrder + 1) = order; 584 | else 585 | % from input polynomial 586 | coefs(1, maxorder - newOrder + 1) = input{source(1, 2)}.coefsIDX(find(ismember(input{source(1, 2)}.deg, deg, 'rows'), 1, 'first')); 587 | end 588 | end 589 | 590 | end 591 | -------------------------------------------------------------------------------- /generator/gbs_GeneratePolynomials_systematic.m: -------------------------------------------------------------------------------- 1 | % Generate all polynomials required to build an action matrix. Polynomials 2 | % are generated without any strategy. 3 | % by Martin Bujnak, mar2008 4 | % last edit by Pavel Trutman, May 2015 5 | 6 | function [foundVar, M, trace] = gbs_GeneratePolynomials_systematic(p, eq, unknown, maxdeg, alldegs, allmonsdeg, allmons, amStats, cfg, algorithmCfg) 7 | 8 | prime = cfg.prime; 9 | GJstep = algorithmCfg.GJstep; 10 | ordering = cfg.ordering; 11 | 12 | % count rows 13 | rowsalloc = 0; 14 | for i = 1:length(eq); 15 | for j = p{i}.maxdeg+1:maxdeg-1 16 | rowsalloc = rowsalloc + nchoosek(j - p{i}.maxdeg + length(unknown) - 1, length(unknown) - 1); 17 | end 18 | end 19 | rowsalloc = rowsalloc + length(eq); 20 | 21 | % initial size 22 | cols = size(allmonsdeg, 2); 23 | M = zeros(rowsalloc, cols); 24 | Mcoefs = zeros(rowsalloc, cols); 25 | 26 | fprintf(' Initializing matrix size %dx%d\n', rowsalloc, cols); 27 | 28 | % insert polynomials into matrices 29 | equations = rowsalloc - length(p) + 1:rowsalloc; 30 | row = 1; 31 | for i = 1:length(p) 32 | for deg = 1:maxdeg - p{i}.maxdeg - 1 33 | [mons, degs] = GenerateMonomials(deg, unknown, ordering); 34 | for j = 1:length(mons) 35 | for k = 1:p{i}.monscnt 36 | monnew = alldegs(length(allmonsdeg) - GetMonomialOrder(char(p{i}.mons(k)), unknown) + 1, :) + degs(j, :); 37 | order = GetMonomialOrder(monnew, unknown); 38 | M(row, cols - (order - 1)) = p{i}.coefs(k); 39 | Mcoefs(row, cols - (order - 1)) = p{i}.coefsIDX(k); 40 | end 41 | row = row + 1; 42 | end 43 | end 44 | end 45 | for i = 1:length(p) 46 | for k = 1:p{i}.monscnt 47 | monnew = alldegs(length(allmonsdeg) - GetMonomialOrder(char(p{i}.mons(k)), unknown) + 1, :); 48 | order = GetMonomialOrder(monnew, unknown); 49 | M(row, cols - (order - 1)) = p{i}.coefs(k); 50 | Mcoefs(row, cols - (order - 1)) = p{i}.coefsIDX(k); 51 | end 52 | row = row + 1; 53 | end 54 | 55 | iteration = 1; 56 | trace{iteration}.Mcoefs = Mcoefs; 57 | 58 | nonzero = find(sum(M) ~= 0); 59 | Kk = M(:, nonzero); 60 | B = gjzpsp(Kk, prime); 61 | MGJ = zeros(size(M, 1), size(M, 2)); 62 | MGJ(:, nonzero) = B; 63 | var = gbs_CheckActionMatrixConditions(MGJ, amStats, true, prime); 64 | 65 | todeg = maxdeg; 66 | if GJstep == 0 67 | nextElim = -1; 68 | else 69 | nextElim = 1; 70 | end 71 | 72 | first = true; 73 | equationsAddedOld = 0; 74 | 75 | % generate polynomials 76 | while var == 0 77 | if first 78 | MoldCoefs = Mcoefs; 79 | Mold = M; 80 | first = false; 81 | else 82 | MoldCoefs = zeros(size(Mold, 1), size(Mold, 2)); 83 | Mold = MGJ; 84 | end 85 | 86 | todegOld = todeg; 87 | 88 | while nextElim <= GJstep 89 | alldegsold = alldegs; 90 | allmonsdegold = allmonsdeg; 91 | 92 | %count new rows 93 | rows = 0; 94 | degsold = zeros(1, size(Mold, 1)); 95 | rowsold = find(sum(Mold, 2) ~= 0, 1, 'last'); 96 | for i = equations 97 | [~, id] = find(Mold(i, :), 1, 'first'); 98 | degsold(i) = allmonsdegold(id); 99 | if degsold(i) < todeg 100 | rows = rows + nchoosek(todeg - degsold(i) + length(unknown) - 1, length(unknown) - 1); 101 | end 102 | end 103 | rows = rows + rowsold; 104 | 105 | % reallocate cols 106 | if todeg > maxdeg 107 | maxdeg = todeg; 108 | [mons, degs] = GenerateMonomials(todeg, unknown, ordering); 109 | allmons = [mons allmons]; 110 | alldegs = [degs; alldegs]; 111 | allmonsdeg = [todeg*ones(1, length(mons)) allmonsdeg]; 112 | cols = size(allmonsdeg, 2); 113 | for a=1:length(amStats) 114 | amStats{a}.zero_el = setdiff(1:cols, (cols+1)-amStats{a}.algBidx); 115 | end 116 | fprintf(' Coefficient matrix reallocation, adding %d (%d degree) monomials\n', length(mons), todeg); 117 | end 118 | fprintf(' %d equations added\n', rows - rowsold); 119 | 120 | % prepare new matrices 121 | M = zeros(rows, cols); 122 | Mcoefs = zeros(rows, cols); 123 | M(rows - rowsold + 1:rows, cols - length(allmonsdegold) + 1:cols) = Mold(1:rowsold, :); 124 | Mcoefs(rows - rowsold + 1:rows, cols - length(allmonsdegold) + 1:cols) = MoldCoefs(1:rowsold, :); 125 | 126 | % generate new polynomials 127 | row = 1; 128 | for i = equations; 129 | if degsold(i) < todeg 130 | [mons, degs] = GenerateMonomials(todeg - degsold(i), unknown, ordering); 131 | idx = find(Mold(i, :)); 132 | for j = 1:length(mons) 133 | for k = 1:length(idx) 134 | monnew = alldegsold(idx(k), :) + degs(j, :); 135 | order = GetMonomialOrder(monnew, unknown); 136 | M(row, cols - (order - 1)) = Mold(i, idx(k)); 137 | if (nextElim == 1) && (iteration ~= 1) 138 | Mcoefs(row, cols - (order - 1)) = size(Mold, 1)*(idx(k) - 1) + i; 139 | else 140 | Mcoefs(row, cols - (order - 1)) = MoldCoefs(i, idx(k)); 141 | end 142 | end 143 | row = row + 1; 144 | end 145 | end 146 | end 147 | 148 | nonzero = find(sum(M) ~= 0); 149 | Kk = M(:, nonzero); 150 | B = gjzpsp(Kk, prime); 151 | MGJ = zeros(size(M, 1), size(M, 2)); 152 | MGJ(:, nonzero) = B; 153 | var = gbs_CheckActionMatrixConditions(MGJ, amStats, true, prime); 154 | 155 | if nextElim == 1 156 | trace{iteration}.rowsold = rowsold; 157 | end 158 | 159 | todeg = todeg + 1; 160 | 161 | if var ~= 0 162 | break; 163 | end; 164 | 165 | if nextElim ~= -1 166 | nextElim = nextElim + 1; 167 | end 168 | 169 | Mold = M; 170 | MoldCoefs = Mcoefs; 171 | equations = equations + row - 1; 172 | end 173 | 174 | 175 | % remove not necesary polynomials 176 | filter = gbs_RemoveRedundant(M, prime); 177 | 178 | M = M(filter, :); 179 | Mcoefs = Mcoefs(filter, :); 180 | nonzero = find(sum(M) ~= 0); 181 | Kk = M(:, nonzero); 182 | B = gjzpsp(Kk, prime); 183 | MGJ = zeros(size(M, 1), size(M, 2)); 184 | MGJ(:, nonzero) = B; 185 | 186 | fprintf(' GJ elimination performed on matrix with size %dx%d\n', size(M, 1), length(nonzero)); 187 | 188 | equationsAdded = size(find(sum(MGJ, 2) ~= 0), 1); 189 | if equationsAddedOld >= equationsAdded 190 | %revert back to previous iteration and leave todeg increased 191 | iteration = iteration - 1; 192 | Mcoefs = trace{iteration}.Mcoefs; 193 | MGJ = trace{iteration}.MGJ; 194 | discard = 1; 195 | else 196 | %try to add new equations up to total degree todeg 197 | todeg = todegOld; 198 | discard = 0; 199 | end 200 | equationsAddedOld = equationsAdded; 201 | 202 | equations = find(sum(MGJ, 2) ~= 0)'; 203 | 204 | %matrix partitioning for elimination 205 | if strcmp(cfg.matrixPartitioning, 'all') 206 | [~, partitioning] = gbs_MatrixPartitioning(M(:, nonzero), [], true, cfg.prime); 207 | partitioning.enable = 1; 208 | else 209 | partitioning.enable = 0; 210 | end 211 | 212 | % save trace 213 | if (discard == 0) || (var ~= 0) 214 | trace{iteration}.Mcoefs = Mcoefs; 215 | trace{iteration}.MGJ = MGJ; 216 | trace{iteration}.nonzerocols = nonzero; 217 | trace{iteration}.partitioning = partitioning; 218 | trace{iteration}.size = size(Mcoefs); 219 | if iteration > 1 220 | trace{iteration}.rowfrom = size(Mcoefs, 1) - trace{iteration}.rowsold + 1; 221 | trace{iteration}.rowto = size(Mcoefs, 1); 222 | trace{iteration}.columnfrom = size(Mcoefs, 2) - size(trace{iteration - 1}.Mcoefs, 2) + 1; 223 | trace{iteration}.columnto = size(Mcoefs, 2); 224 | end 225 | end 226 | 227 | iteration = iteration + 1; 228 | if GJstep ~= 0 229 | nextElim = 1; 230 | end 231 | 232 | end 233 | 234 | foundVar = var; 235 | 236 | % remove not necesary polynomials 237 | RemoveUnnecessary = str2func(['gbs_RemoveUnnecessary_', cfg.RemoveUnnecessary]); 238 | [filter, foundVar] = RemoveUnnecessary(M, amStats, foundVar, prime); 239 | 240 | if iteration ~= 1 241 | iteration = iteration - 1; 242 | end 243 | 244 | M = M(filter, :); 245 | trace{iteration}.Mcoefs = trace{iteration}.Mcoefs(filter, :); 246 | if foundVar ~= 0 247 | trace{iteration}.nonzerocols = union(find(sum(M) ~= 0), size(M, 2) - amStats{foundVar}.algBidx + 1); 248 | else 249 | trace{iteration}.nonzerocols = find(sum(M) ~= 0); 250 | end 251 | if iteration == 1 252 | %matrix partitioning for elimination 253 | if strcmp(cfg.matrixPartitioning, 'all') 254 | [~, partitioning] = gbs_MatrixPartitioning(M(:, nonzero), [], true, cfg.prime); 255 | partitioning.enable = 1; 256 | else 257 | partitioning.enable = 0; 258 | end 259 | trace{iteration}.partitioning = partitioning; 260 | else 261 | trace{iteration}.filter = filter(filter >= trace{iteration}.rowfrom) - trace{iteration}.rowfrom + 1; 262 | trace{iteration}.rowfrom = size(filter(filter < trace{iteration}.rowfrom), 2) + 1; 263 | trace{iteration}.rowto = size(filter, 2); 264 | trace{iteration}.size = size(trace{iteration}.Mcoefs); 265 | end 266 | 267 | end 268 | -------------------------------------------------------------------------------- /generator/gbs_GenerateSolver.m: -------------------------------------------------------------------------------- 1 | % This function generate solver for the given problem specified as 2 | % function. Minimal problems are typicaly defined in folder 3 | % 'minimalProblems'. 4 | % 5 | % Minimal problem is every function of the form 6 | % '[eq, known, unknown, kngroups, cfg, algB] = nameOfMinimalProblem()'. 7 | % 8 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, March 2015 9 | % 10 | % problemName - name of the minimalProblem; function specifies the problem 11 | % must have the same name 12 | 13 | function [res, export] = gbs_GenerateSolver(problemName) 14 | 15 | % get minimal problem definition 16 | problem = str2func(problemName); 17 | [eq, known, unknown, kngroups, cfg, algB] = problem(); 18 | 19 | %create code 20 | [res, export] = gbs_CreateCode(problemName, eq, known, unknown, kngroups, cfg, algB); 21 | 22 | end -------------------------------------------------------------------------------- /generator/gbs_GetVariablesIdx.m: -------------------------------------------------------------------------------- 1 | % get pointers of unknown variables in algB array 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, dec2008 4 | 5 | function [one unksidx] = gbs_GetVariablesIdx(algB, unkn) 6 | 7 | ucnt = size(unkn, 2); 8 | 9 | one = findmon(algB, '1'); 10 | 11 | unksidx = zeros(1, ucnt); 12 | for i=1:ucnt 13 | unksidx(i) = findmon(algB, unkn{i}); 14 | end 15 | end 16 | 17 | function [idx] = findmon(algB, ch) 18 | 19 | res = strcmp(ch, algB); 20 | idx = find(res == 1); 21 | if (isempty(idx)) 22 | idx = 0; 23 | end 24 | end -------------------------------------------------------------------------------- /generator/gbs_InitConfig.m: -------------------------------------------------------------------------------- 1 | % Config file. 2 | % (GBsolver subroutine) 3 | % 4 | % by Martin Bujnak, mar 2008 5 | % last edit by Pavel Trutman, March 2015 6 | 7 | function [cfg] = gbs_InitConfig() 8 | 9 | cfg.ordering = 3; %grevlex - Do not modify! 10 | 11 | % prime field generator 12 | cfg.prime = 30097; 13 | 14 | % list of equations which should be used in Groebner basis solver (cfg.GBSolver). 15 | % e.g. set cfg.GBrestrictEq = 1:4; to use equations 1 to 4 only. 16 | cfg.GBrestrictEq = []; 17 | 18 | % groebner basis solver 19 | % any function of the form 20 | % "[algB res] = GBSolver(cfg, eq, known, unknown);" 21 | 22 | % Macaulay2 gb solver 23 | cfg.GBSolver = @gbs_findAlgB_macaulay; 24 | 25 | % Maple gb solver 26 | %cfg.GBSolver = @gbs_findAlgB_maple; 27 | 28 | % instance generators 29 | % any function of the form 30 | % "function [eqi] = gbs_RandomInstance(cfg, eq, known, unknown)" 31 | % 32 | % define your own function if you want to study a special scene configurations 33 | % like planar scenes etc. 34 | 35 | % random instance within Zp field 36 | cfg.InstanceGenerator = @gbs_RandomInstanceZp; 37 | cfg.ZpGeneratorMaxNumber = 999; 38 | 39 | % random instance (coeffs may be bigger than cfg.prime) 40 | % cfg.InstanceGenerator = @gbs_RandomInstance; 41 | % cfg.ZpGeneratorMaxNumber = 55; 42 | 43 | % polynomial removing step 44 | %cfg.bdoReduce = true; 45 | %cfg.bIncremental = false; 46 | 47 | 48 | % generator of polynomials 49 | % generate polynomials to selected degree 50 | cfg.PolynomialsGenerator = 'systematic'; 51 | % config of this algorithm: 52 | % the total degree of the polynomials, we are generating polynomials up to, is inceased by GJstep after each GJ elimination 53 | % 0 means perform only one GJ elimination at the end 54 | cfg.PolynomialsGeneratorCfg.GJstep = 1; 55 | 56 | % use strategies from F4 algorithm 57 | %cfg.PolynomialsGenerator = 'F4'; 58 | % config of this algorithm: 59 | % define selection strategy of the F4 algorithm 60 | %cfg.PolynomialsGeneratorCfg.Sel = @F4_SelNormal; 61 | 62 | % removing unnecessary polynomials 63 | % remove polynomials without fixed solution 64 | cfg.RemoveUnnecessary = 'nonfixed'; 65 | 66 | % remove polynomials without fixed solution 67 | %cfg.RemoveUnnecessary = 'fixed'; 68 | 69 | % use matrix partitioning (by PaToH) 70 | % how to set up this external library see the 'installation.txt', this library is not available for Windows 71 | % possible values 72 | % 'none' - no matrix partitioning is used 73 | % 'last' - only the last elimination is done by using partitioning 74 | % 'all' - for all eliminations is used partitioning 75 | cfg.matrixPartitioning = 'none'; 76 | 77 | % crash recovery from a log file. 78 | % copy&paste matlab console output to a log file and run solver again 79 | % while setting cfg.crashlog = 'consoleout.log'. Copy just solver output. 80 | cfg.crashlog = []; 81 | 82 | % export coefficients * monomials vectors (debug) 83 | cfg.exportEqs = false; 84 | cfg.bGeneratorSolverResult = false; 85 | 86 | % code to export 87 | cfg.exportCode = {'matlab' 'maple'}; 88 | 89 | % set benchmark mode 90 | cfg.benchmark.enable = 0; 91 | 92 | % settings for benchmark 93 | % maximal count of tried inputs from inputData, same amount is generated by function generateInputData 94 | cfg.benchmark.maxInputs = 1000; 95 | 96 | end -------------------------------------------------------------------------------- /generator/gbs_MatrixPartitioning.m: -------------------------------------------------------------------------------- 1 | % GJ elimination with PaToH partitioning 2 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, February 2015 3 | 4 | function [res, workflow] = gbs_MatrixPartitioning(matrix, amCols, eliminateCompletly, prime) 5 | 6 | %separete algB collumns 7 | amCols = sort(amCols); 8 | noAmCols = setdiff(1:size(matrix, 2), amCols); 9 | algBcnt = size(amCols, 2); 10 | redMatrix = matrix(:, noAmCols); 11 | 12 | %use PaToH to patition the matrix 13 | if eliminateCompletly 14 | [P, PRows, PCols] = PaToHMatrixPart(redMatrix, 2, 'RWU'); 15 | else 16 | [P, PRows, PCols] = PaToHMatrixPart(redMatrix, 2, 'RWS'); 17 | end 18 | 19 | %extract rows and cols for each part 20 | [PRows1, ~] = find(PRows == 1); 21 | [PRows2, ~] = find(PRows == 2); 22 | [PCols1, ~] = find(PCols == 1); 23 | [PCols2, ~] = find(PCols == 2); 24 | 25 | tmp = P; 26 | tmp(PRows1, PCols1) = zeros(size(PRows1, 1), size(PCols1, 1)); 27 | tmp(PRows2, PCols2) = zeros(size(PRows2, 1), size(PCols2, 1)); 28 | [~, cols] = find(tmp); 29 | BCols = unique(cols); 30 | 31 | ACols1 = setdiff(PCols1, BCols); 32 | ACols2 = setdiff(PCols2, BCols); 33 | 34 | %elimination of the first matrix 35 | mat1 = [redMatrix(PRows1, [ACols1; BCols]), matrix(PRows1, amCols)]; 36 | mat1NonzeroCols = find(sum(mat1, 1) ~= 0); 37 | mat1(:, mat1NonzeroCols) = gjzpsp(mat1(:, mat1NonzeroCols), prime); 38 | if size(ACols1, 1) ~= 0 39 | [lastRow1, ~] = find(sum(mat1(:, 1:size(ACols1, 1)), 2), 1, 'last'); 40 | if size(lastRow1, 1) == 0 41 | lastRow1 = 0; 42 | end 43 | else 44 | lastRow1 = 0; 45 | end 46 | 47 | %elimination of the second matrix 48 | mat2 = [redMatrix(PRows2, [ACols2; BCols]), matrix(PRows2, amCols)]; 49 | mat2NonzeroCols = find(sum(mat2, 1) ~= 0); 50 | mat2(:, mat2NonzeroCols) = gjzpsp(mat2(:, mat2NonzeroCols), prime); 51 | if size(ACols2, 1) ~= 0 52 | [lastRow2, ~] = find(sum(mat2(:, 1:size(ACols2, 1)), 2), 1, 'last'); 53 | if size(lastRow2, 1) == 0 54 | lastRow2 = 0; 55 | end 56 | else 57 | lastRow2 = 0; 58 | end 59 | 60 | %assemble the top of the final matrix 61 | tmp = zeros(lastRow1 + lastRow2, size(matrix, 2) - algBcnt); 62 | tmp(1:lastRow1, [ACols1; BCols]) = mat1(1:lastRow1, 1:end-algBcnt); 63 | tmp(lastRow1+1:lastRow1 + lastRow2, [ACols2; BCols]) = mat2(1:lastRow2, 1:end-algBcnt); 64 | 65 | topRows = 1:size(tmp, 1); 66 | bottomRows = size(tmp, 1)+1:size(matrix, 1); 67 | 68 | res = zeros(size(matrix)); 69 | res(topRows, noAmCols) = tmp; 70 | res(topRows, amCols) = [mat1(1:lastRow1, end - algBcnt + 1:end); mat2(1:lastRow2, end - algBcnt + 1:end)]; 71 | 72 | %assemble the bottom of the final matrix 73 | tmp = zeros(size(bottomRows, 2), size(matrix, 2) - algBcnt); 74 | tmp(1:size(mat1, 1) - lastRow1, [ACols1; BCols]) = mat1(lastRow1 + 1:end, 1:end-algBcnt); 75 | tmp(size(mat1, 1) - lastRow1 + 1:end, [ACols2; BCols]) = mat2(lastRow2 + 1:end, 1:end-algBcnt); 76 | res(bottomRows, noAmCols) = tmp; 77 | res(bottomRows, amCols) = [mat1(lastRow1 + 1:end, end - algBcnt + 1:end); mat2(lastRow2 + 1:end, end - algBcnt + 1:end)]; 78 | 79 | %again eliminate the bottom part 80 | nonzero = find(sum(res(bottomRows, :), 1) ~= 0); 81 | res(bottomRows, nonzero) = gjzpsp(res(bottomRows, nonzero), prime); 82 | 83 | if eliminateCompletly 84 | %reorder rows to get identity matrix 85 | [rows, cols] = find(res == 1); 86 | [resPivotRows, indexCol, ~] = unique(rows, 'sorted'); 87 | resPivotCols = cols(indexCol); 88 | [~, resPermutationRows] = sort(resPivotCols); 89 | resPermutationRows = resPivotRows(resPermutationRows); 90 | [~, resPermutationRows] = sort(resPermutationRows); 91 | res(resPermutationRows, :) = res; 92 | 93 | %eliminate rest 94 | elimCols = BCols; 95 | i = 1; 96 | while size(elimCols, 1) ~= 0 97 | col = elimCols(1); 98 | elimCols = setdiff(elimCols, col); 99 | if sum(res(:, col)) ~= 0 100 | 101 | %find pivotRow 102 | if col ~= 1 103 | pivotRow = find(sum(res(:, 1:col-1), 2), 1, 'last') + 1; 104 | if size(pivotRow, 2) == 0 105 | pivotRow = 1; 106 | end 107 | else 108 | pivotRow = 1; 109 | end 110 | 111 | if pivotRow > size(res, 1) 112 | break; 113 | end 114 | 115 | 116 | if res(pivotRow, col) == 0 117 | %switch rows if zero in pivotRow 118 | if sum(res(pivotRow:end, col)) ~= 0 119 | switchRow = find(res(pivotRow:end, col), 1, 'first') + pivotRow - 1; 120 | tmpRow = res(pivotRow, :); 121 | res(pivotRow, :) = res(switchRow, :); 122 | res(switchRow, :) = tmpRow; 123 | workflow.elim{i}.type = 'switch'; 124 | workflow.elim{i}.rows = [pivotRow, switchRow]; 125 | i = i + 1; 126 | 127 | addElimCols = find(res(switchRow, :)); 128 | elimCols = unique([elimCols; addElimCols(addElimCols > col)'], 'sorted'); 129 | else 130 | %continue with next col if zeros below pivotRow 131 | continue; 132 | end 133 | 134 | end 135 | 136 | addElimCols = find(res(pivotRow, :)); 137 | elimCols = unique([elimCols; addElimCols(addElimCols > col)'], 'sorted'); 138 | 139 | if res(pivotRow, col) ~= 1 140 | %divide to get one 141 | [~, c] = gcd(res(pivotRow, col), -prime); 142 | res(pivotRow, :) = mod(c*res(pivotRow, :), prime); 143 | workflow.elim{i}.type = 'divide'; 144 | workflow.elim{i}.row = pivotRow; 145 | workflow.elim{i}.col = col; 146 | i = i + 1; 147 | end 148 | 149 | %eliminate the column 150 | for row = setdiff(1:size(res, 1), pivotRow) 151 | if res(row, col) ~= 0 152 | res(row, :) = mod(res(row, :) - res(row, col)*res(pivotRow, :), prime); 153 | workflow.elim{i}.type = 'eliminate'; 154 | workflow.elim{i}.row = row; 155 | workflow.elim{i}.col = col; 156 | workflow.elim{i}.pivotRow = pivotRow; 157 | i = i + 1; 158 | end 159 | end 160 | end 161 | if pivotRow == size(res, 1) 162 | %break if bottom reached 163 | break; 164 | end 165 | end 166 | 167 | workflow.permutationRows = resPermutationRows; 168 | 169 | end 170 | 171 | %save workflow 172 | workflow.enable = 1; 173 | workflow.res = res; 174 | workflow.amCols = amCols; 175 | workflow.noAmCols = noAmCols; 176 | workflow.PRows1 = PRows1; 177 | workflow.PRows2 = PRows2; 178 | workflow.ACols1 = ACols1; 179 | workflow.ACols2 = ACols2; 180 | workflow.BCols = BCols; 181 | workflow.mat1TopRows = 1:lastRow1; 182 | workflow.mat2TopRows = 1:lastRow2; 183 | workflow.mat1BottRows = lastRow1 + 1:size(mat1, 1); 184 | workflow.mat2BottRows = lastRow2 + 1:size(mat2, 1); 185 | workflow.resMat1TopRows = 1:lastRow1; 186 | workflow.resMat2TopRows = (1:lastRow2) + lastRow1; 187 | lastRow = lastRow1 + lastRow2; 188 | if size(workflow.mat1BottRows, 2) == 0 189 | workflow.resMat1BottRows = 1:0; 190 | else 191 | workflow.resMat1BottRows = workflow.mat1BottRows - workflow.mat1BottRows(1) + lastRow + 1; 192 | lastRow = lastRow + size(workflow.resMat1BottRows, 2); 193 | end 194 | if size(workflow.mat2BottRows, 2) == 0 195 | workflow.resMat2BottRows = 1:0; 196 | else 197 | workflow.resMat2BottRows = workflow.mat2BottRows - workflow.mat2BottRows(1) + lastRow + 1; 198 | end 199 | workflow.topRows = topRows; 200 | workflow.bottomRows = bottomRows; 201 | workflow.resBottNonzeroCols = nonzero; 202 | workflow.mat1NonzeroCols = mat1NonzeroCols; 203 | workflow.mat2NonzeroCols = mat2NonzeroCols; 204 | 205 | end -------------------------------------------------------------------------------- /generator/gbs_ParseAlgebraB.m: -------------------------------------------------------------------------------- 1 | % Parse and prepare algebra B basis 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, mar2008 4 | 5 | 6 | function [amLT, amLTcnt, amLTall, algB, algBidx, algBcnt] = gbs_ParseAlgebraB(algB, actMvar, unknown) 7 | 8 | algBcnt = size(algB, 2); 9 | algBidx = zeros(1, algBcnt); 10 | tmpLt = zeros(1, algBcnt); 11 | mvar = sym(actMvar); 12 | for i=1:algBcnt 13 | 14 | algBidx(i) = GetMonomialOrder(algB{i}, unknown); 15 | 16 | ai = sym(algB{i}) * mvar; 17 | tmpLt(i) = GetMonomialOrder(char(ai), unknown); 18 | end 19 | 20 | % sort (grevlex) 21 | [algBidx, p] = sort(algBidx); 22 | tmpLt = tmpLt(p); 23 | algB = algB(p); 24 | 25 | amLT = setdiff(tmpLt, algBidx); 26 | amLTcnt = size(amLT, 2); 27 | amLTall = tmpLt; 28 | end -------------------------------------------------------------------------------- /generator/gbs_ParseEquations.m: -------------------------------------------------------------------------------- 1 | % Parse input equations 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, mar2008 4 | % last edit by Pavel Trutman, oct 2014 5 | 6 | 7 | function [monomials, p, p_currdeg, symcoefs, maxdeg] = gbs_ParseEquations(cfg, eq, known, unknown) 8 | 9 | if ~isfield(cfg, 'eqinstance') 10 | 11 | eqs = cfg.InstanceGenerator(cfg, eq, known, unknown); 12 | else 13 | eqs = cfg.eqinstance; 14 | end 15 | 16 | prime = cfg.prime; 17 | 18 | monomials=[]; 19 | eqcnt = length(eq); 20 | usedcoefidx = 1; 21 | clear symcoefs; 22 | clear p; 23 | p = cell([1 eqcnt]); 24 | for i=1:eqcnt 25 | 26 | eq(i) = expand(eq(i)); 27 | 28 | if eq(i) == 0 29 | 30 | warning('empty/zero equation (%d), remove it and run solver again', i); 31 | end 32 | 33 | p{i}.eq = eq(i); 34 | 35 | % extract monomials & coefficents 36 | [coefs, monoms] = coeffs(eq(i), unknown); 37 | [coefs_rc, monoms] = coeffs(eqs(i), unknown); 38 | [monoms, sortArray] = sort(monoms, 'descend'); 39 | p{i}.coefs = coefs(sortArray); 40 | p{i}.coefs_rc = coefs_rc(sortArray); 41 | p{i}.mons = arrayfun(@(x) char(x), monoms, 'UniformOutput', 0); 42 | p{i}.deg = MonomialsDegree(p{i}.mons, unknown); 43 | p{i}.maxdeg = max( sum(p{i}.deg, 2) ); 44 | 45 | p_currdeg(i) = p{i}.maxdeg; 46 | p{i}.monsidx = 0; 47 | p{i}.monscnt = length(p{i}.mons); 48 | monomials = union(monomials, p{i}.mons); 49 | 50 | % convert (fractions) coeffs to Zp 51 | zpcoefs = []; 52 | coefidx = []; 53 | for j=1:length(p{i}.coefs) 54 | 55 | cmpl = p{i}.coefs_rc(j); 56 | [a]=sscanf(char(cmpl),'%d/%d'); 57 | if length(a) > 1 58 | zpcoefs(j) = double(Zp(a(1), prime) / Zp(a(2), prime)); 59 | else 60 | zpcoefs(j) = double(Zp(a(1), prime)); 61 | end 62 | 63 | symcoefs(usedcoefidx) = p{i}.coefs(j); 64 | coefidx(j) = usedcoefidx; 65 | usedcoefidx = usedcoefidx+1; 66 | end 67 | 68 | p{i}.coefs = zpcoefs; 69 | p{i}.coefsIDX = coefidx; 70 | 71 | end 72 | maxdeg = max(p_currdeg); 73 | p_currdeg = p_currdeg - min(p_currdeg); 74 | end 75 | -------------------------------------------------------------------------------- /generator/gbs_PreparePolySystemCoefsMatrix.m: -------------------------------------------------------------------------------- 1 | % Generate all polynomials required to build an action matrix for 2 | % variable "actMvar" (detect actMvar if variable was not specified) 3 | % (GBsolver subroutine) 4 | % by Martin Bujnak, mar2008 5 | % last edit by Pavel Trutman, March 2015 6 | 7 | 8 | function [M, trace, symcoefs, amVar, amLT, amLTall, algBidx, algB] = gbs_PreparePolySystemCoefsMatrix(cfg, eq, known, unknown, algB, amVar) 9 | 10 | ordering = cfg.ordering; 11 | 12 | % create random instance 13 | if ~isfield(cfg, 'eqinstance') 14 | 15 | cfg.eqinstance = cfg.InstanceGenerator(cfg, eq, known, unknown); 16 | end 17 | 18 | if nargin < 5 || isempty(algB) 19 | 20 | % find quotion ring basis ( monomial basis of quotient ring C[x1,...xn]/I ) 21 | [algB] = cfg.GBSolver(cfg, eq, known, unknown); 22 | 23 | if isempty(algB) 24 | 25 | M=[]; 26 | trace=[]; 27 | symcoefs=[]; 28 | amVar=[]; 29 | amLT=[]; 30 | amLTall=[]; 31 | algBidx=[]; 32 | return; 33 | end 34 | end 35 | 36 | % prepare algebra B and find which monomials we need to build the 37 | % action matrix 38 | fprintf('analyzing quotient ring basis\n'); 39 | 40 | if nargin < 9 41 | 42 | amVars = unknown; 43 | else 44 | amVars = amVar; 45 | end 46 | 47 | amStats = {}; 48 | for i=1:length(amVars) 49 | 50 | actMvar = amVars{i}; 51 | 52 | [amLT, amLTcnt, amLTall, algB, algBidx] = gbs_ParseAlgebraB(algB, actMvar, unknown); 53 | 54 | amStats{i}.actMvar = actMvar; 55 | amStats{i}.amLT = amLT; 56 | amStats{i}.amLTcnt = amLTcnt; 57 | amStats{i}.amLTall = amLTall; 58 | amStats{i}.algB = algB; 59 | amStats{i}.algBidx = algBidx; 60 | end 61 | 62 | % 63 | % extract equations into coeffients + monomial form 64 | fprintf('extracting coefficient & monomials\n'); 65 | [monomials, p, ~, symcoefs, maxdeg] = gbs_ParseEquations(cfg, eq, known, unknown); 66 | 67 | 68 | % 69 | % just statistics (can be removed from this code) 70 | [monomials] = ReorderMonomials(monomials, unknown, ordering); 71 | 72 | fprintf('...used %d monomials : \n ', length(monomials)); 73 | for mons = monomials 74 | fprintf('%s ', char(mons)); 75 | end 76 | fprintf('\n'); 77 | 78 | fprintf('...max. poly. degree %d\n', maxdeg); 79 | 80 | 81 | if ~isempty(cfg.crashlog) 82 | 83 | fprintf('...crash log file detected - recovering from previous state using: %s\n', cfg.crashlog); 84 | [~, ~, max_deg] = gbs_ResetFromLog(cfg.crashlog); 85 | 86 | maxdeg = max_deg; 87 | fprintf('...need to generate polynomials to degree %d\n', maxdeg); 88 | end 89 | 90 | 91 | 92 | % 93 | % generate monomials up-to maxdeg (matrix cols) 94 | allmons = {'1'}; 95 | alldegs = zeros(1, length(unknown)); 96 | allmonsdeg = 0; 97 | for i=1:maxdeg 98 | [mons, degs] = GenerateMonomials(i, unknown, ordering); 99 | allmons = [mons allmons]; 100 | alldegs = [degs; alldegs]; 101 | allmonsdeg = [i*ones(1, length(mons)) allmonsdeg]; 102 | end 103 | 104 | % create action var. masks 105 | cols = size(allmonsdeg, 2); 106 | for a=1:length(amStats) 107 | amStats{a}.zero_el = setdiff(1:cols, (cols+1)-amStats{a}.algBidx); 108 | end 109 | 110 | if cfg.exportEqs 111 | 112 | fprintf('...exporting parsed equations'); 113 | 114 | % debug - create coefficient matrix with all initial polynomials 115 | cols = size(allmonsdeg, 2); 116 | Minit = zeros(length(eq), cols); 117 | for i=1:length(eq) 118 | for j=1:p{i}.monscnt 119 | pmon2 = p{i}.deg(j,:); 120 | order = GetMonomialOrder(pmon2, unknown); 121 | Minit(i, cols-(order-1)) = p{i}.coefsIDX(j); 122 | end 123 | end 124 | 125 | nonzero = find(sum(Minit) ~= 0); 126 | Mmons = Minit(:, nonzero); 127 | 128 | gbs_DBGExport(known, unknown, eq, symcoefs, allmons, Minit, Mmons); 129 | end 130 | 131 | fprintf('Adding polynomials\n'); 132 | 133 | PolynomialsGenerator = str2func(['gbs_GeneratePolynomials_', cfg.PolynomialsGenerator]); 134 | [foundVar, M, trace] = PolynomialsGenerator(p, eq, unknown, maxdeg, alldegs, allmonsdeg, allmons, amStats, cfg, cfg.PolynomialsGeneratorCfg); 135 | 136 | if ~foundVar 137 | 138 | M = []; 139 | trace = []; 140 | 141 | amVar = []; 142 | amLT = []; 143 | amLTall = []; 144 | algBidx = []; 145 | 146 | else 147 | 148 | amVar = amStats{foundVar}.actMvar; 149 | amLT = amStats{foundVar}.amLT; 150 | amLTall = amStats{foundVar}.amLTall; 151 | algBidx = amStats{foundVar}.algBidx; 152 | end 153 | end 154 | -------------------------------------------------------------------------------- /generator/gbs_RandomInstance.m: -------------------------------------------------------------------------------- 1 | % create random instance of the equation in Zp 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, mar2008 4 | 5 | function [eqi] = gbs_RandomInstance(cfg, eq, known, unknown) 6 | 7 | vars = [unknown known]; 8 | for mon = vars 9 | eval(['syms ' char(mon) ';']); 10 | end 11 | 12 | for mon = known 13 | eval([char(mon) '=' num2str(floor(rand()*cfg.ZpGeneratorMaxNumber)) ';']); 14 | end 15 | 16 | fprintf('Creating random instance for %d equations\n', length(eq)); 17 | 18 | for i=1:length(eq) 19 | eqi(i) = eval(eq(i)); 20 | end 21 | end -------------------------------------------------------------------------------- /generator/gbs_RandomInstanceZp.m: -------------------------------------------------------------------------------- 1 | % create random instance of the equation in Zp 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, mar2008 4 | % last edit by Pavel Trutman, oct 2014 5 | 6 | function [eqi] = gbs_RandomInstanceZp(cfg, eq, known, unknown) 7 | 8 | vars = [unknown known]; 9 | for mon = vars 10 | eval(['syms ' char(mon) ';']); 11 | end 12 | 13 | for mon = known 14 | eval([char(mon) '=' num2str(floor(rand()*cfg.ZpGeneratorMaxNumber)) ';']); 15 | end 16 | 17 | fprintf('Creating random instance in Z_%d for %d equations\n', cfg.prime, length(eq)); 18 | 19 | reverseStr = ''; 20 | for i=1:length(eq) 21 | 22 | st = char(expand(eq(i))); 23 | 24 | % split to + and - and evaluate separately 25 | ep = strfind(st, '-'); 26 | em = strfind(st, '+'); 27 | els = [ep em length(st)+1]; 28 | els = sort(els); 29 | 30 | p1 = 0; 31 | prev = 1; 32 | for j=1:size(els, 2) 33 | 34 | if prev < (els(j)-1) 35 | if st(prev) == '+' 36 | prev = prev+1; 37 | end 38 | ee = eval( st( prev:(els(j)-1)) ); 39 | p1 = EquationModulus(p1 + ee, unknown, cfg.prime); 40 | end 41 | 42 | prev = els(j); 43 | 44 | % print status 45 | msg = sprintf(' instancing %d equation of %d (%2.0f %%%%)', i, length(eq), j/ size(els, 2)*100); 46 | fprintf([reverseStr msg]); 47 | reverseStr = repmat(sprintf('\b'), 1, length(msg) - 1); 48 | 49 | end 50 | 51 | eqi(i) = p1; 52 | %eqi2(i) = eval(eq(i)); 53 | end 54 | fprintf(reverseStr); 55 | end -------------------------------------------------------------------------------- /generator/gbs_RemoveRedundant.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 2 | % 3 | % Remove polynomials that are redundant in the matrix. 4 | % 5 | % M - a matrix from which we are removing polynomials 6 | % prime - we are computing modulo this prime 7 | % filter - a list of rows that have to remain in the matrix M 8 | 9 | 10 | function [filter] = gbs_RemoveRedundant(M, prime) 11 | 12 | nonzero = find(sum(M) ~= 0); 13 | Kk = M(:, nonzero); 14 | B = gjzpsp(Kk, prime); 15 | 16 | toRemove = size(find(sum(B, 2) == 0), 1); 17 | filter = 1:size(M, 1); 18 | 19 | reverseStr = ''; 20 | if toRemove > 0 21 | fprintf(' removing %d equations', toRemove); 22 | usedRows = size(find(sum(B, 2) ~= 0), 1); 23 | removed = 0; 24 | step = max([floor(toRemove/4) 1]); 25 | up = 1; 26 | while up <= size(M, 1) 27 | down = up + step - 1; 28 | if down > size(M, 1) 29 | down = size(M, 1); 30 | step = down - up + 1; 31 | end 32 | filterOld = filter; 33 | filter = setdiff(filter, up:down); 34 | 35 | Kk = M(filter, nonzero); 36 | B = gjzpsp(Kk, prime); 37 | 38 | if size(find(sum(B, 2) ~= 0), 1) < usedRows 39 | if step == 1 40 | up = up + 1; 41 | else 42 | step = max([floor(step/4) 1]); 43 | end 44 | filter = filterOld; 45 | else 46 | removed = removed + step; 47 | 48 | if removed == toRemove 49 | fprintf(reverseStr); 50 | fprintf(' - all removed'); 51 | break; 52 | end 53 | up = down + 1; 54 | step = min([2*step toRemove-removed]); 55 | end 56 | 57 | % print progress 58 | msg = sprintf(' (%2.0f %%%% removed, remaining %d equations to check)', floor(removed/toRemove*100), size(M, 1) - up); 59 | fprintf([reverseStr msg]); 60 | reverseStr = repmat(sprintf('\b'), 1, length(msg) - 1); 61 | 62 | end 63 | fprintf('\n'); 64 | 65 | end 66 | 67 | end 68 | 69 | -------------------------------------------------------------------------------- /generator/gbs_RemoveUnnecessary_fixed.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 2 | % 3 | % Remove polynomials that are not necessary for building of the action 4 | % matrix with fixed solution for one variable. 5 | % 6 | % M - a matrix from which we are removing polynomials 7 | % amStats - inforamtion about what is required for buiding of the action 8 | % matrix 9 | % foundVar - variable with respect to will be the action matrix build 10 | % prime - we are computing modulo this prime 11 | % filter - a list of rows that have to remain in the matrix M 12 | 13 | function [filter, foundVar] = gbs_RemoveUnnecessary_fixed(M, amStats, foundVar, prime) 14 | 15 | % remove not necesary polynomials 16 | fprintf('Removing not necessary polynomials:'); 17 | rows = size(M, 1); 18 | step = max([floor(rows/32) 1]); 19 | up = 1; 20 | filter = 1:rows; 21 | 22 | while up <= rows 23 | down = up + step - 1; 24 | if down > rows 25 | down = rows; 26 | step = down - up + 1; 27 | end 28 | 29 | filterOld = filter; 30 | filter = setdiff(filter, up:down); 31 | 32 | var = gbs_CheckActionMatrixConditions(M(filter, :), amStats, false, prime); 33 | 34 | if var == foundVar 35 | if step > 1 36 | fprintf([' ', int2str(up), '-', int2str(down)]); 37 | else 38 | fprintf([' ', int2str(down)]); 39 | end 40 | foundVar = var; 41 | up = down + 1; 42 | step = 2*step; 43 | else 44 | if step == 1 45 | up = up + 1; 46 | else 47 | step = max([floor(step/4) 1]); 48 | end 49 | filter = filterOld; 50 | end 51 | 52 | end 53 | fprintf('\n'); 54 | 55 | end 56 | -------------------------------------------------------------------------------- /generator/gbs_RemoveUnnecessary_nonfixed.m: -------------------------------------------------------------------------------- 1 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, May 2015 2 | % 3 | % Remove polynomials that are not necessary for building of the action 4 | % matrix. 5 | % 6 | % M - a matrix from which we are removing polynomials 7 | % amStats - inforamtion about what is required for buiding of the action 8 | % matrix 9 | % foundVar - variable with respect to will be the action matrix build 10 | % prime - we are computing modulo this prime 11 | % filter - a list of rows that have to remain in the matrix M 12 | 13 | function [filter, foundVar] = gbs_RemoveUnnecessary_nonfixed(M, amStats, foundVar, prime) 14 | 15 | % remove not necesary polynomials 16 | fprintf('Removing not necessary polynomials:'); 17 | rows = size(M, 1); 18 | step = max([floor(rows/32) 1]); 19 | up = 1; 20 | filter = 1:rows; 21 | 22 | while up <= rows 23 | down = up + step - 1; 24 | if down > rows 25 | down = rows; 26 | step = down - up + 1; 27 | end 28 | 29 | filterOld = filter; 30 | filter = setdiff(filter, rows-down+1:rows-up+1);%up:down); 31 | 32 | var = gbs_CheckActionMatrixConditions(M(filter, :), amStats, false, prime); 33 | 34 | if var ~= 0 %== foundVar 35 | if step > 1 36 | fprintf([' ', int2str(up), '-', int2str(down)]); 37 | else 38 | fprintf([' ', int2str(down)]); 39 | end 40 | foundVar = var; 41 | up = down + 1; 42 | step = 2*step; 43 | else 44 | if step == 1 45 | up = up + 1; 46 | else 47 | step = max([floor(step/4) 1]); 48 | end 49 | filter = filterOld; 50 | end 51 | 52 | end 53 | fprintf('\n'); 54 | 55 | end 56 | -------------------------------------------------------------------------------- /generator/gbs_ResetFromLog.m: -------------------------------------------------------------------------------- 1 | % log recovery parser 2 | % (GBsolver subroutine) 3 | % by Martin Bujnak, sep2008 4 | 5 | function [used last max_deg] = gbs_ResetFromLog(filename) 6 | 7 | fid = fopen(filename, 'r'); 8 | 9 | used = []; 10 | max_deg = 0; 11 | last = 9999999; 12 | while (true) 13 | tline = fgets(fid); 14 | if isnumeric(tline) && tline == -1 15 | break; 16 | end 17 | 18 | [eq cnt err] = sscanf(tline, '...removing equation %d failed *\n'); 19 | 20 | if (~isempty(err)) 21 | [eq cnt err] = sscanf(tline, '...removing equation %d \t[t:%fsec]\tfailed *\n'); 22 | if isempty(err) 23 | err = []; 24 | eq = eq(1); 25 | end 26 | end 27 | 28 | if (isempty(err)) 29 | 30 | used = [used;eq]; 31 | last = min(last, eq); 32 | end 33 | 34 | [eq cnt err] = sscanf(tline, '...removing equation %d succeeded\n'); 35 | if (~isempty(err)) 36 | [eq cnt err] = sscanf(tline, '...removing equation %d \t[t:%fsec]\tsucceeded\n'); 37 | if isempty(err) 38 | err = []; 39 | eq = eq(1); 40 | end 41 | end 42 | if (isempty(err)) 43 | 44 | last = min(last, eq); 45 | end 46 | 47 | [deg cnt err] = sscanf(tline, '...max. poly. degree %d\n'); 48 | if (isempty(err)) 49 | 50 | max_deg = deg; 51 | end 52 | 53 | pos = strfind(tline, '...coefficient matrix '); 54 | if ~isempty(pos) 55 | 56 | [deg cnt err] = sscanf(tline(pos:end), '...coefficient matrix reallocaction, adding %d(%d degree) monomials\n'); 57 | if (isempty(err)) 58 | 59 | max_deg = deg(2); 60 | end 61 | end 62 | end 63 | 64 | fclose(fid); 65 | end -------------------------------------------------------------------------------- /generator/gbs_findAlgB_macaulay.m: -------------------------------------------------------------------------------- 1 | % find algebra B basis (macaulay2 GB solver) 2 | % (GBsolver subroutine) 3 | % 4 | % by Martin Bujnak, mar 2008 5 | % last edit by Pavel Trutman, February 2015 6 | 7 | function [algB, res] = gbs_findAlgB_macaulay(cfg, eq, known, unknown) 8 | 9 | algB = []; 10 | res = 0; 11 | 12 | %detect OS 13 | if strcmp(computer('arch'), 'win32') || strcmp(computer('arch'), 'win64') 14 | os = 'win'; 15 | elseif strcmp(computer('arch'), 'glnxa64') 16 | os = 'unix'; 17 | end 18 | 19 | mcCode = 'gbsMacaulay/code.m2'; 20 | mcCodeTemplate = 'gbsMacaulay/code_template.m2'; 21 | if strcmp(os, 'win') 22 | mcExecCode = 'gbsMacaulay\calc.bat'; 23 | elseif strcmp(os, 'unix') 24 | mcExecCode = ['M2 ' mcCode]; 25 | end 26 | 27 | fprintf('calculating Grobner basis using Macaulay2 \n'); 28 | 29 | if ~isfield(cfg, 'eqinstance') 30 | 31 | eqs = cfg.InstanceGenerator(cfg, eq, known, unknown); 32 | else 33 | eqs = cfg.eqinstance; 34 | end 35 | 36 | if ~isempty(cfg.GBrestrictEq) 37 | eqs = eqs(cfg.GBrestrictEq); 38 | end 39 | 40 | % subst unknowns to x_0 ... x_N 41 | unkcnt = length(unknown); 42 | eqcnt = length(eqs); 43 | mcideal = 'f = ('; 44 | mceqs = ''; 45 | for i = 1:eqcnt 46 | 47 | eq = Monomial_PerformSubst(unknown, {}, char(eqs(i))); 48 | 49 | if eq == '0' 50 | continue; 51 | end 52 | 53 | % 54 | mceqs = [mceqs 'f' int2str(i) '=' eq ';\r\n']; 55 | mcideal = [mcideal 'f' int2str(i)]; 56 | if i < eqcnt 57 | mcideal = [mcideal ' || ']; 58 | end 59 | end 60 | mcideal = [mcideal ' );']; 61 | 62 | 63 | % prepare macaulay code 64 | 65 | repm = [{'$PRIME$'} {int2str(cfg.prime)}]; 66 | repm = [repm; {'$UNKCNT$'} {int2str(unkcnt)} ]; 67 | repm = [repm; {'$UNKNOWN$'} {c2s(unknown, ', ')} ]; 68 | repm = [repm; {'$EQUATIONS$'} {mceqs} ]; 69 | repm = [repm; {'$EQUATIONSVEC$'} {mcideal} ]; 70 | 71 | % create output file 72 | fid = fopen(mcCode, 'w'); 73 | 74 | templ = ReadTemplate(mcCodeTemplate); 75 | for re = repm' 76 | 77 | templ = strrep(templ, re{1}, re{2}); 78 | end 79 | if strcmp(os, 'win') 80 | templ = strrep(templ, 'gbTrace = 3;', 'gbTrace 3;'); 81 | end 82 | 83 | fprintf(fid, templ); 84 | fclose(fid); 85 | 86 | % call macaulay 87 | 88 | [res, val] = system(mcExecCode); 89 | 90 | dimpos = strfind(val, 'dim:'); 91 | degpos = strfind(val, 'deg:'); 92 | if isempty(dimpos) || isempty(degpos) 93 | 94 | fprintf('Error executing Macaulay2. Check paths.\n'); 95 | fprintf([val '\n']); 96 | return; 97 | end 98 | 99 | % parse dimension 100 | dim = sscanf(val(dimpos:dimpos+10), 'dim:\r\n%d'); 101 | 102 | % parse number of solutions 103 | deg = sscanf(val(degpos:degpos+10), 'deg:\r\n%d'); 104 | 105 | if dim < 0 106 | 107 | fprintf('WARNING ! non-zero-dimensional variety (select a subset of equations and try again).\n'); 108 | 109 | elseif dim > 0 110 | 111 | fprintf('WARNING ! expected module to be a finite dimensional module.\n'); 112 | 113 | else 114 | 115 | basispos = strfind(val, '@@@@@@@@@@@@@@'); 116 | basisstr = val((basispos(1)+14):basispos(2)-1); 117 | sep = strfind(basisstr, '|'); 118 | basisstr = basisstr(sep(1)+1:sep(2)-1); 119 | 120 | % add * between terms 121 | xs = strfind(basisstr, 'x'); 122 | res = ''; 123 | prev = 1; 124 | for xidx = xs 125 | 126 | star = ''; 127 | if (xidx > 0) && (basisstr(xidx-1) ~= ' ') 128 | star = '*'; 129 | end 130 | res = [res basisstr(prev:(xidx-1)) star]; 131 | prev = xidx; 132 | end 133 | res = [res basisstr(prev:end)]; 134 | 135 | % rename x_i to original names 136 | basisstr = Monomial_PerformSubst({}, unknown, res); 137 | 138 | % create string list... 139 | algB = {}; 140 | fprintf('...algebra B basis :\n '); 141 | 142 | rem = basisstr; 143 | i = 1; 144 | while true 145 | 146 | [t, rem] = strtok(rem, ' '); 147 | if isempty(t), break; end 148 | 149 | algB{i} = t; 150 | fprintf('%s ', t); 151 | i = i + 1; 152 | end 153 | 154 | fprintf('\n'); 155 | 156 | fprintf('...system is expected to have %d solutions\n', deg); 157 | 158 | end 159 | end 160 | -------------------------------------------------------------------------------- /generator/gbs_findAlgB_maple.m: -------------------------------------------------------------------------------- 1 | % find algebra B basis (maple GB solver) 2 | % (GBsolver subroutine) 3 | % 4 | % by Martin Bujnak, mar 2008 5 | 6 | function [algB res] = gbs_findAlgB_maple(cfg, eq, known, unknown) 7 | 8 | fprintf('calculating Grobner basis\n'); 9 | 10 | % if ~isfield(cfg, 'eqinstance') 11 | % 12 | % eqs = cfg.InstanceGenerator(cfg, eq, known, unknown); 13 | % else 14 | % eqs = cfg.eqinstance; 15 | % end 16 | 17 | eqs = gbs_RandomInstance(cfg, eq, known, unknown); 18 | 19 | if ~isempty(cfg.GBrestrictEq) 20 | eqs = eqs(cfg.GBrestrictEq); 21 | end 22 | 23 | maple('with(Groebner)'); 24 | ord = maple(['tdeg(' c2s(unknown, ', ') ')']); 25 | 26 | % load equations in maple 27 | eqstr = '['; 28 | for i=1:length(eqs) 29 | if i > 1 30 | eqstr = [eqstr ',' char(eqs(i))]; 31 | else 32 | eqstr = [eqstr char(eqs(i))]; 33 | end 34 | end 35 | eqstr = [eqstr ']']; 36 | 37 | F = maple(eqstr); 38 | G = maple('gbasis', F, ord); 39 | 40 | str = strrep(char(G), 'matrix([', ''); 41 | str = strrep(str, '])', ''); 42 | 43 | GG = maple(str); 44 | [ns, res] = maple('SetBasis', GG , ord); 45 | 46 | if res > 0 47 | 48 | fprintf('WARNING ! non-zero-dimensional variety (select a subset of equations and try again).\n'); 49 | algB = []; 50 | else 51 | reg = regexp(char(ns), '\[.*?\]', 'match'); 52 | ns = reg{1}; 53 | ns = sym(ns); 54 | 55 | fprintf('...algebra B basis :\n '); 56 | 57 | % create string list... 58 | algB = {}; 59 | for i=1:length(ns) 60 | 61 | algB{i} = char(ns(i)); 62 | fprintf('%s ', algB{i}); 63 | end 64 | 65 | fprintf('\n'); 66 | end 67 | end -------------------------------------------------------------------------------- /generator/helpers/CreateSubstBlock.m: -------------------------------------------------------------------------------- 1 | % create substitution table of the form x^2 -> x2 for each monomial from the 2 | % input set. Return all monomials in compact form x2, y2, y2x2, etc. 3 | % 4 | % by Martin Bujnak, nov2007 5 | 6 | function [subst smonomials] = CreateSubstBlock(monomials) 7 | 8 | % prepare subst table 9 | subst = {}; 10 | smonomials = {}; 11 | for i=1:size(monomials, 2) 12 | 13 | str = monomials(1, i); 14 | str2 = strrep(str, '^', ''); 15 | str2 = strrep(str2, '*', ''); 16 | subst = [subst {[char(str) '=' char(str2)]}]; 17 | smonomials = [smonomials {char(str2)}]; 18 | end 19 | 20 | end -------------------------------------------------------------------------------- /generator/helpers/EquationModulus.m: -------------------------------------------------------------------------------- 1 | % Perform modulus on coefficients of given equation 2 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, August 2014 3 | % 4 | % [eq] = EquationModulus(eq, unknown, prime) 5 | % Extracts coefficients of equation, perform modulus by prime and restore 6 | % the equation 7 | 8 | function [eq] = EquationModulus(eq, unknown, prime) 9 | 10 | % use normal mod function, if only number given 11 | if isnumeric(eq) 12 | eq = mod(eq, prime); 13 | 14 | % if equation given 15 | else 16 | % use symbolic variables 17 | for u = unknown 18 | eval(['syms ' char(u) ';']); 19 | end 20 | % extract coefficients a monomials 21 | [coeff, monomials] = coeffs(eq, unknown); 22 | % mod the coefficients 23 | coeff = mod(coeff, prime); 24 | % restore the equation 25 | eq = sum(coeff.*monomials); 26 | end 27 | end -------------------------------------------------------------------------------- /generator/helpers/ExtractMonomials.m: -------------------------------------------------------------------------------- 1 | % monomials extraction utility 2 | % (c) Martin Bujnak, martinb@dataexpert.sk, aug2006 3 | % 4 | % [monomials degree] = ExtractMonomials(P, unknowns, orderingfnc) 5 | % usage: 6 | % P is cell array of polynomial equations 7 | % unknowns are list of unknown variables (reminding vars are considered 8 | % as const) - example unknowns = {'x_0' 'x_1' 'x_2' 'x_3' 'x_4' 'x_5') 9 | % 10 | % orderingfnc(a,b) compare two monomials (where a, b are sets of powers) 11 | % and return 1 to indicat a>b or -1 to indicat a 1 64 | divs = [divs; dvars(2:end)]; 65 | end 66 | end 67 | 68 | div = size(vars, 1); 69 | if ~isempty(divs) 70 | vars = [vars; divs]; 71 | end 72 | 73 | for k = 1:size(vars,1) 74 | 75 | e = strread(char(vars(k)), '%s', 'delimiter', '^'); 76 | fs = ['#' strtrim(char(e(1))) '#']; 77 | 78 | if ~isempty(strfind(uns, fs)) 79 | 80 | if isempty(monomial) 81 | monomial = [monomial strtrim(char(vars(k))) ]; 82 | else 83 | 84 | if k > div 85 | monomial = [monomial '/' strtrim(char(vars(k))) ]; 86 | else 87 | monomial = [monomial '*' strtrim(char(vars(k))) ]; 88 | end 89 | end 90 | end 91 | 92 | end 93 | 94 | if ~isempty(monomial) 95 | 96 | % Monomials_order requires monomial singletons to be of 97 | % the form "x_1 ... x_N" - this defines ordering too. 98 | % First we substitute monomials and then fix it back. 99 | 100 | [monomial mcnt]= Monomial_PerformSubst(unknowns, {}, monomial); 101 | monomial = Monomials_order(monomial, unkcnt+1, 'x_1'); 102 | 103 | monomials = union(monomials, cellstr(monomial)); 104 | end 105 | end 106 | end 107 | 108 | end 109 | 110 | % sort monimials by degree (+ lex ordering) 111 | monscnt = size(monomials, 2); 112 | monsdeg = zeros(1, monscnt); 113 | monsdegre = zeros(monscnt, unkcnt); 114 | for i=1:monscnt 115 | 116 | [monsdeg(i) mdeg]= Monomial_degree(monomials(i), unkcnt); 117 | monsdegre(i, :) = mdeg; 118 | 119 | % back subsitute monomials... 120 | monomials(i) = Monomial_PerformSubst({}, unknowns, monomials(i)); 121 | end 122 | 123 | if nargin > 2 124 | 125 | if isnumeric(orderingfnc) 126 | 127 | switch orderingfnc 128 | case 1 129 | orderingfnc = @Monomial_lexorder; 130 | case 2 131 | orderingfnc = @Monomial_grlexorder; 132 | case 3 133 | orderingfnc = @Monomial_grevlexorder; 134 | end 135 | end 136 | 137 | % reorder monomials (max-sort) 138 | for i=1:size(monomials, 2) 139 | 140 | maxmon = monsdegre(i,:); 141 | maxidx = i; 142 | for j=i+1:size(monomials, 2) 143 | 144 | if orderingfnc(maxmon, monsdegre(j,:)) < 0 145 | 146 | maxmon = monsdegre(j,:); 147 | maxidx = j; 148 | end 149 | end 150 | 151 | % swap monomials 152 | zl = monomials(i); 153 | monomials(i) = monomials(maxidx); 154 | monomials(maxidx) = zl; 155 | 156 | monsdegre(maxidx,:) = monsdegre(i,:); 157 | monsdegre(i,:) = maxmon; 158 | 159 | degree(i,:) = maxmon; 160 | end 161 | 162 | else 163 | [v i] = sort(monsdeg,'descend'); 164 | monomials = monomials(i); 165 | degree = monsdegre(i, :); 166 | end 167 | end 168 | -------------------------------------------------------------------------------- /generator/helpers/GenerateMonomials.m: -------------------------------------------------------------------------------- 1 | % Generate and sort all monomials of given degree from a set of given unknowns 2 | % 3 | % by Martin Bujnak, feb2008 4 | 5 | function [mons degs] = GenerateMonomials(deg, unk, order) 6 | 7 | if (deg == 0) 8 | 9 | mons = {}; 10 | degs = []; 11 | 12 | elseif (deg == 1) 13 | 14 | mons = unk; 15 | degs = eye(length(unk)); 16 | 17 | elseif length(unk) == 1 18 | 19 | mons = {[unk{1} '^' int2str(deg)]}; 20 | degs = [deg]; 21 | 22 | else 23 | 24 | mons = {}; 25 | degs = []; 26 | for i=0:deg 27 | 28 | [monsi degsi] = GenerateMonomials(deg-i, unk(2:end)); 29 | 30 | if i > 0 31 | if (i == 1) 32 | m = unk{1}; 33 | else 34 | m = [unk{1} '^' int2str(i)]; 35 | end 36 | if isempty(monsi) 37 | 38 | monsi = {m}; 39 | degsi = [zeros(1, length(unk)-1)]; 40 | else 41 | for j=1:length(monsi) 42 | 43 | monsi{j} = [m '*' monsi{j}]; 44 | end 45 | end 46 | 47 | end 48 | degsi = [i*ones(size(degsi,1),1) degsi]; 49 | 50 | mons = [mons monsi]; 51 | degs = [degs; degsi]; 52 | end 53 | end 54 | 55 | if nargin > 2 56 | 57 | [mons degs] = ReorderMonomials(mons, unk, order); 58 | 59 | % remove ^1 60 | for i=1:length(mons) 61 | 62 | mons{i} = strrep(mons{i}, '^1', ''); 63 | end 64 | end 65 | end -------------------------------------------------------------------------------- /generator/helpers/GetDivisors.m: -------------------------------------------------------------------------------- 1 | % Returns list of all divisors of given monomial 2 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, April 2015 3 | % 4 | % [divisors] = GetDivisors(monomial) 5 | % monomial - array with degrees of monomial 6 | % divisors - list of all divisors of given monomial 7 | 8 | function [divisors] = GetDivisors(monomial) 9 | 10 | N = size(monomial, 2); 11 | possibillities = cell(1, N); 12 | for i = 1:N 13 | possibillities{i} = [0:monomial(1, i)]; 14 | end 15 | v = cell(N, 1); 16 | [v{:}] = ndgrid(possibillities{:}); 17 | divisors = reshape(cat(N + 1, v{:}), [], N); 18 | 19 | end 20 | -------------------------------------------------------------------------------- /generator/helpers/GetMonomialOrder.m: -------------------------------------------------------------------------------- 1 | % calc monomial order (rank) in coefficient matrix ordered using grevlex. 2 | % 3 | % by Martin Bujnak, mar2008 4 | % 5 | % function [r] = GetMonomialOrder(mon, unknowns) 6 | % mon - monomial which order are we interested in (either string 7 | % 'x^2*y*z^2', or array form [2 1 2]) 8 | % unknowns - set of unknown variables (define ordering) (ex. {'x' 'y' 'z'}) 9 | 10 | 11 | function [r] = GetMonomialOrder(mon, unknowns) 12 | 13 | if isstr(mon) 14 | 15 | [mons, degs] = ExtractMonomials(sym(mon), unknowns); 16 | mon = degs; 17 | 18 | if isempty(mons) 19 | r = 1; 20 | return; 21 | end 22 | end 23 | 24 | unkcnt = length(mon); 25 | deg = sum(mon); 26 | 27 | smaller = GetMonomialsCnt(unkcnt, 0, deg-1); 28 | 29 | % trim leading zeros (reduce unknowns) 30 | i = 1; 31 | while (i <= unkcnt) && (mon(i) == 0) 32 | i = i + 1; 33 | end 34 | head = i; 35 | 36 | % count number of monomials with the same degree 37 | r = smaller; 38 | 39 | remdeg = deg; 40 | for i=unkcnt:-1:1 41 | 42 | for j=(mon(i)+1):remdeg 43 | 44 | r = r + GetMonomialsCnt(i - 1, remdeg-j, remdeg-j); 45 | end 46 | remdeg = remdeg - mon(i); 47 | if remdeg < 1 48 | break; 49 | end 50 | 51 | end 52 | 53 | r = r + 1; 54 | end 55 | 56 | -------------------------------------------------------------------------------- /generator/helpers/GetMonomialsCnt.m: -------------------------------------------------------------------------------- 1 | % calc number of monomials from degree 'fromdeg', to degree 'todeg', 2 | % containing 'unkcnt' unknowns 3 | % 4 | % by Martin Bujnak, mar2008 5 | 6 | function [k] = GetMonomialsCnt(unkcnt, fromdeg, todeg) 7 | 8 | if unkcnt == 0 9 | % by def 10 | k = 0; 11 | return; 12 | end 13 | 14 | k = 0; 15 | for i=fromdeg:todeg 16 | c = nchoosek(unkcnt+i-1, i); 17 | k = k + c; 18 | end 19 | 20 | end -------------------------------------------------------------------------------- /generator/helpers/Monomial_PerformSubst.m: -------------------------------------------------------------------------------- 1 | % switch monomial in general form/to one where monimials are 2 | % of the form x_i ... 3 | % 4 | % by Martin Bujnak, mar2007 5 | 6 | function [mon moncnt] = Monomial_PerformSubst(from, to, str) 7 | 8 | if (isempty(from)) 9 | eval([' from = {' sprintf('''x_%d'' ',1:size(to, 2)) '};']); 10 | end 11 | 12 | if (isempty(to)) 13 | eval([' to = {' sprintf('''x_%d'' ',1:size(from, 2)) '};']); 14 | end 15 | 16 | to = strrep(to, 'x', '#'); 17 | 18 | for i=min(size(from, 2), size(to, 2)):-1:1 19 | 20 | f = char(from(i)); 21 | t = char(to(i)); 22 | 23 | str = strrep(str, f, t); 24 | end 25 | 26 | k = strfind(str, '#'); 27 | moncnt = length(k); 28 | 29 | str = strrep(str, '#', 'x'); 30 | mon = str; 31 | end 32 | 33 | -------------------------------------------------------------------------------- /generator/helpers/Monomial_degree.m: -------------------------------------------------------------------------------- 1 | % Given string in monomial is of the form x_i1^j1*x_i2^j2*...*x_imax^jmax 2 | % Return degree of the monomial deg = sum(ji) and vec = [j1 j2 ... jmax]. 3 | % 4 | % by Martin Bujnak, oct 2007 5 | 6 | function [deg vec] = Monomial_degree(monstr, max) 7 | 8 | deg = 0; 9 | 10 | if nargin < 2 11 | max = 8; 12 | end 13 | 14 | vec = []; 15 | 16 | % extract coefs...and add sentinel 'x' 17 | str = [char(monstr) 'x']; 18 | k = strfind(str, 'x'); 19 | 20 | svec = zeros(1, max); 21 | for j=1:(size(k,2)-1) 22 | 23 | mon = str(k(j):k(j+1)-1); 24 | [a b c] = strread(mon, '%s%d%d', 'delimiter', '_^*'); 25 | if (size(c,1) == 0) 26 | 27 | c = 1; 28 | end 29 | 30 | svec(b) = svec(b) + c; 31 | deg = deg + c; 32 | end 33 | 34 | vec = [vec; svec]; 35 | end -------------------------------------------------------------------------------- /generator/helpers/Monomial_grevlexorder.m: -------------------------------------------------------------------------------- 1 | % function compares two arbitary vectors and return 2 | % -1 if a < b 3 | % 0 if a = b 4 | % +1 if a > b 5 | % 6 | % by Martin Bujnak, nov2007 7 | 8 | function [c] = Monomial_grevlexorder(a, b) 9 | 10 | sa = sum(a); 11 | sb = sum(b); 12 | 13 | if sa < sb 14 | 15 | c = -1; 16 | return; 17 | 18 | elseif sa > sb 19 | 20 | c = 1; 21 | return 22 | end 23 | 24 | a = a - b; 25 | l = length(a); 26 | 27 | for i=l:-1:1 28 | 29 | if a(i) > 0 30 | 31 | c = -1; 32 | return; 33 | 34 | elseif a(i) < 0 35 | 36 | c = 1; 37 | return; 38 | end 39 | end 40 | 41 | c = 0; 42 | end -------------------------------------------------------------------------------- /generator/helpers/MonomialsDegree.m: -------------------------------------------------------------------------------- 1 | % Gets the degrees of monomials 2 | % Pavel Trutman, pavel.trutman@fel.cvut.cz, oct2014 3 | % 4 | % degree = MonomialsDegree(monomial, unknown) 5 | % Degree is an array, rows for monomials, colums for unknowns 6 | 7 | function degree = MonomialsDegree(monomial, unknown) 8 | degree = zeros(length(monomial), length(unknown)); 9 | 10 | for i = 1:length(monomial) 11 | for j = 1:length(unknown) 12 | 13 | % get the exponent 14 | deg = regexp(monomial{i}, [unknown{j} '\^(\d*)'], 'tokens'); 15 | if isempty(deg) == 1 16 | deg = regexp(monomial{i}, unknown{j}, 'tokens'); 17 | if isempty(deg) == 1 18 | % unknown{j} is not in this monomial 19 | degree(i, j) = 0; 20 | else 21 | % unknown{j} only with exponent 1 22 | degree(i, j) = 1; 23 | end 24 | else 25 | % higher exponents of unknown{j} 26 | degree(i, j) = str2num(char(deg{1})); 27 | end 28 | 29 | end 30 | end 31 | 32 | end -------------------------------------------------------------------------------- /generator/helpers/Monomials_order.m: -------------------------------------------------------------------------------- 1 | % function [corrected] = Monomials_order(strin, varscnt, unkmon) 2 | % 3 | % this function fixes and update order of monomials in input term 4 | % unknown monomials (singletons) must be of the form "x_1" ... "x_N" 5 | % 6 | % by Martin Bujnak 7 | 8 | function [corrected] = Monomials_order(strin, varscnt, unkmon) 9 | 10 | if nargin < 2 11 | varscnt = 7; 12 | end 13 | 14 | if nargin < 3 15 | 16 | unkmon = 'x'; 17 | end 18 | 19 | if size(unkmon, 2) > 1 & unkmon( size(unkmon, 2) - 1 ) == '_' 20 | 21 | %mutiple monomials with the same prefix... 22 | multi = true; 23 | unkmon = unkmon(1:end-2); 24 | else 25 | multi = false; 26 | end 27 | 28 | coefs = zeros(1, varscnt); 29 | coefscnt = size(coefs, 2); 30 | 31 | % extract coefs...and add sentinel 'x' 32 | str = [char(strin) unkmon]; 33 | p__k = strfind(str, unkmon); 34 | 35 | for p__j=1:(size(p__k,2)-1) 36 | 37 | mon = str(p__k(p__j):p__k(p__j+1)-1); 38 | if (multi) 39 | [p__a p__b p__c] = strread(mon, '%s%d%d', 'delimiter', '_^*'); 40 | else 41 | [p__a p__c] = strread(mon, '%s%d', 'delimiter', '^*'); 42 | p__b = 0; 43 | end 44 | p__b = p__b + 1; 45 | if (size(p__c,1) == 0) 46 | 47 | p__c = 1; 48 | end 49 | coefs(coefscnt - p__b + 1) = p__c; 50 | end 51 | 52 | % composite 53 | corrected = ''; 54 | first = true; 55 | for p__j=1:coefscnt 56 | 57 | if (coefs(p__j) > 0) 58 | 59 | if (multi) 60 | 61 | if (~first) 62 | corrected = [corrected '*' unkmon '_' int2str(coefscnt - p__j) '^' int2str(coefs(p__j))]; 63 | else 64 | corrected = [corrected unkmon '_' int2str(coefscnt - p__j) '^' int2str(coefs(p__j))]; 65 | first = false; 66 | end 67 | else 68 | if (~first) 69 | corrected = [corrected '*' unkmon '^' int2str(coefs(p__j))]; 70 | else 71 | corrected = [corrected unkmon '^' int2str(coefs(p__j))]; 72 | first = false; 73 | end 74 | end 75 | end 76 | end 77 | 78 | end -------------------------------------------------------------------------------- /generator/helpers/ReadTemplate.m: -------------------------------------------------------------------------------- 1 | % read text file to string 2 | % 3 | % by Martin Bujnak, oct 2005 4 | 5 | function [str] = ReadTemplate(filename); 6 | 7 | fid = fopen(filename, 'r'); 8 | 9 | str = []; 10 | while (fid >= 0) 11 | 12 | tline = fgets(fid); 13 | if isnumeric(tline) && tline == -1 14 | break; 15 | end 16 | str = [str tline]; 17 | end 18 | 19 | fclose(fid); 20 | end -------------------------------------------------------------------------------- /generator/helpers/ReorderMonomials.m: -------------------------------------------------------------------------------- 1 | % reorder a set of monomials stored in cell array. 2 | % 3 | % function [mons] = ReorderMonomials(P, unknowns, orderingfnc) 4 | % 5 | % P - set of monomials 6 | % 7 | % unknowns are list of unknown variables (reminding vars are considered 8 | % as const) - example unknowns = {'x_0' 'x_1' 'x_2' 'x_3' 'x_4' 'x_5') 9 | % 10 | % orderingfnc(a,b) compare two monomials (where a, b are sets of powers) 11 | % and return 1 to indicat a>b or -1 to indicat a 2 52 | 53 | if isnumeric(orderingfnc) 54 | 55 | switch orderingfnc 56 | case 1 57 | orderingfnc = @Monomial_lexorder; 58 | case 2 59 | orderingfnc = @Monomial_grlexorder; 60 | case 3 61 | orderingfnc = @Monomial_grevlexorder; 62 | end 63 | end 64 | 65 | % reorder monomials (max-sort) 66 | for i=1:size(monomials, 2) 67 | 68 | maxmon = monsdegre(i,:); 69 | maxidx = i; 70 | for j=i+1:size(monomials, 2) 71 | 72 | if orderingfnc(monsdegre(j,:), maxmon) > 0 73 | 74 | maxmon = monsdegre(j,:); 75 | maxidx = j; 76 | end 77 | end 78 | 79 | % swap monomials 80 | zl = monomials(i); 81 | monomials(i) = monomials(maxidx); 82 | monomials(maxidx) = zl; 83 | 84 | monsdegre(maxidx,:) = monsdegre(i,:); 85 | monsdegre(i,:) = maxmon; 86 | 87 | degree(i,:) = maxmon; 88 | end 89 | 90 | else 91 | [v i] = sort(monsdeg,'descend'); 92 | monomials = monomials(i); 93 | degree = monsdegre(i, :); 94 | end 95 | end -------------------------------------------------------------------------------- /generator/helpers/c2s.m: -------------------------------------------------------------------------------- 1 | % cell array to string 2 | % 3 | % by Martin Bujnak, mar 2008 4 | 5 | function [s] = c2s(a, separator) 6 | 7 | s = ''; 8 | for i=1:length(a) 9 | 10 | if i==1 11 | s = char(a{i}); 12 | else 13 | s = [s separator char(a{i})]; 14 | end 15 | end 16 | end -------------------------------------------------------------------------------- /generator/helpers/gbs_Matrix.m: -------------------------------------------------------------------------------- 1 | % create symbolic 'r' by 'c' matrix 2 | % 3 | % 4 | % [A] = gbs_Matrix(format, r, c, flag) 5 | % use: 6 | % format - variable name (format specifier %d optional) 7 | % r - number of rows 8 | % c - number of cols 9 | % flag (optional) - 'real', 'unreal',... see 'sym' for the reference 10 | % 11 | % example: 12 | % [A] = gbs_Matrix('a', 2, 3) 13 | % 14 | % A = 15 | % 16 | % [ a11, a12, a13] 17 | % [ a21, a22, a23] 18 | % 19 | % [A] = gbs_Matrix('a(%d,%d)', 2, 3) 20 | % 21 | % A = 22 | % 23 | % [ a(1,1), a(1,2), a(1,3)] 24 | % [ a(2,1), a(2,2), a(2,3)] 25 | % 26 | % by Martin Bujnak, mar 2008 27 | 28 | function [A] = gbs_Matrix(format, r, c, flag) 29 | 30 | cnt = length(strfind(format, '%d')); 31 | switch cnt 32 | case 0 33 | format = [format '%d%d']; 34 | case 1 35 | format = [format '%d']; 36 | end 37 | 38 | idx1 = repmat((1:r)', 1, c); 39 | idx2 = repmat(1:c, r, 1); 40 | M=[idx1(:)'; idx2(:)']; 41 | 42 | v = transpose(sym(['[' sprintf([format ' '],M(:)) ']'])); 43 | A = reshape(v, r, c); 44 | 45 | if nargin > 3 46 | for i=1:(r*c) 47 | sym(A(i), flag); 48 | end 49 | end 50 | 51 | end -------------------------------------------------------------------------------- /generator/helpers/gbs_Vector.m: -------------------------------------------------------------------------------- 1 | % create symbolic column vector 2 | % 3 | % [v] = gbs_Vector(format, dim, flag) 4 | % use: 5 | % format - variable name (format specifier %d optional) 6 | % dim - vector dimension 7 | % flag (optional) - 'real', 'unreal',... see 'sym' for the reference 8 | % 9 | % example: 10 | % [v] = gbs_Vector('a', 3) 11 | % 12 | % v = 13 | % 14 | % a1 15 | % a2 16 | % a3 17 | % 18 | % [v] = gbs_Vector('a_%d', 3) 19 | % 20 | % v = 21 | % 22 | % a_1 23 | % a_2 24 | % a_3 25 | % 26 | % by Martin Bujnak, mar 2008 27 | 28 | function [v] = gbs_Vector(format, dim, flag) 29 | 30 | if isempty(strfind(format, '%d')) 31 | format = [format '%d']; 32 | end 33 | v = transpose(sym(['[' sprintf([format ' '],1:dim) ']'])); 34 | 35 | if nargin > 2 36 | for i=1:dim 37 | sym(v(i), flag); 38 | end 39 | end 40 | 41 | end -------------------------------------------------------------------------------- /generator/helpers/gjzpsp.c: -------------------------------------------------------------------------------- 1 | /* gauss-jordan elimination in finite field (Zp) 2 | (semi-sparse version) 3 | by Martin Bujnak, mar2008 4 | last edit by Pavel Trutman, oct 2014 5 | */ 6 | 7 | #include "mex.h" 8 | #include "math.h" 9 | #include 10 | 11 | void gcd(int a, int b, int *g, int *c, int *d) 12 | { 13 | int q; 14 | int u[3]; 15 | int v[3]; 16 | int t[3]; 17 | 18 | u[0] = 1; 19 | u[1] = 0; 20 | u[2] = abs(a); 21 | 22 | v[0] = 0; 23 | v[1] = 1; 24 | v[2] = b; 25 | 26 | while (v[2]) { 27 | 28 | q = u[2]/v[2]; 29 | 30 | t[0] = u[0] - v[0]*q; 31 | t[1] = u[1] - v[1]*q; 32 | t[2] = u[2] - v[2]*q; 33 | 34 | u[0] = v[0]; 35 | u[1] = v[1]; 36 | u[2] = v[2]; 37 | 38 | v[0] = t[0]; 39 | v[1] = t[1]; 40 | v[2] = t[2]; 41 | } 42 | 43 | if (a < 0) u[0] = -u[0]; 44 | 45 | *c = u[0]; 46 | *d = u[1]; 47 | *g = u[2]; 48 | } 49 | 50 | int invZp(int x, int prime) 51 | { 52 | int g, c, d; 53 | gcd(x, prime, &g, &c, &d); 54 | return c; 55 | } 56 | 57 | int max(int a, int b) { 58 | if (a >= b) { 59 | return a; 60 | } 61 | else { 62 | return b; 63 | } 64 | } 65 | 66 | void mexFunction(int nlhs , mxArray *plhs[] , int nrhs , const mxArray *prhs[]){ 67 | 68 | /* 69 | B = gjzp(A, prime); 70 | */ 71 | 72 | /* in */ 73 | int r = 0; /* row */ 74 | int c = 0; /* col */ 75 | int k; 76 | int l; 77 | int b; 78 | int dstofs; 79 | int srcofs; 80 | int ofs = 0; 81 | int pofs = 0; 82 | int pivot_i; 83 | int endcol = 0; 84 | int *tmp; 85 | int *B; 86 | double *Bres; 87 | int *r_nonzero; 88 | int *crow; 89 | double *A = mxGetPr(prhs[0]); 90 | int rcnt = mxGetM(prhs[0]); 91 | int ccnt = mxGetN(prhs[0]); 92 | int prime = (int)*mxGetPr(prhs[1]); 93 | 94 | /* out */ 95 | plhs[0] = mxCreateDoubleMatrix(rcnt, ccnt , mxREAL); 96 | Bres = mxGetPr(plhs[0]); 97 | B = (int*)malloc(rcnt*ccnt*sizeof(int)); 98 | 99 | /* copy transposed */ 100 | pofs = 0; 101 | for (k=0;k crow[0] && *(B+ofs) == 0) { 131 | ofs--; 132 | l--; 133 | }; 134 | crow[1] = l; 135 | 136 | crow += 2; 137 | } 138 | 139 | /* gj */ 140 | ofs = 0; 141 | pofs = 0; 142 | while (r < rcnt && c < ccnt) { 143 | 144 | /* find pivot (in Zp == find first nonzero element) */ 145 | int pivot = 0; 146 | int pivot_r = -1; 147 | int pofs = ofs; 148 | for (k = r; k < rcnt; k++) { 149 | 150 | if (*(B+pofs)) { 151 | 152 | pivot = *(B+pofs); 153 | pivot_r = k; 154 | break; 155 | } 156 | pofs += ccnt; 157 | } 158 | 159 | if (pivot == 0) { 160 | 161 | /* shift to next col */ 162 | c++; 163 | ofs++; 164 | 165 | } else { 166 | 167 | /* exchange pivot and selected rows */ 168 | endcol = max(*(r_nonzero+2*pivot_r+1), *(r_nonzero+2*r+1)); 169 | k = (endcol - c)*sizeof(int); 170 | 171 | memcpy(tmp, B+ccnt*r+c, k); 172 | memcpy(B+ccnt*r+c, B+ccnt*pivot_r+c, k); 173 | memcpy(B+ccnt*pivot_r+c, tmp, k); 174 | 175 | endcol = *(r_nonzero+2*pivot_r+1); 176 | 177 | /* swap row limits */ 178 | pofs = *(r_nonzero+2*pivot_r); 179 | *(r_nonzero+2*pivot_r) = *(r_nonzero+2*r); 180 | *(r_nonzero+2*r) = pofs; 181 | 182 | pofs = *(r_nonzero+2*pivot_r+1); 183 | *(r_nonzero+2*pivot_r+1) = *(r_nonzero+2*r+1); 184 | *(r_nonzero+2*r+1) = pofs; 185 | 186 | /* process rows */ 187 | 188 | pivot_i = invZp(pivot, prime); 189 | 190 | /* divide pivot row */ 191 | srcofs = ofs; 192 | *(B+srcofs) = 1; 193 | srcofs++; 194 | for (l = c+1; l < endcol; l++) { 195 | 196 | *(B+srcofs) = (*(B+srcofs)*pivot_i) % prime; 197 | srcofs++; 198 | } 199 | 200 | /* zero bottom */ 201 | pofs = ofs + ccnt; 202 | for (k = r + 1; k < rcnt; k++) { 203 | 204 | if (*(B+pofs) != 0) { 205 | 206 | /* nonzero row */ 207 | b = *(B+pofs); 208 | 209 | dstofs = pofs + 1; 210 | srcofs = ofs + 1; 211 | 212 | for (l = c + 1; l < endcol; l++) { 213 | 214 | int v = (*(B+dstofs) - *(B+srcofs) * b) % prime; 215 | *(B+dstofs) = v; 216 | dstofs++; 217 | srcofs++; 218 | } 219 | 220 | *(B+pofs) = 0; 221 | if (*(r_nonzero+2*k+1) < endcol) *(r_nonzero+2*k+1) = endcol; 222 | } 223 | pofs += ccnt; 224 | } 225 | 226 | /* zero top */ 227 | pofs = c; 228 | for (k = 0; k < r; k++) { 229 | 230 | if (*(B+pofs) != 0) { 231 | 232 | /* nonzero row */ 233 | b = *(B+pofs); 234 | 235 | dstofs = pofs + 1; 236 | srcofs = ofs + 1; 237 | 238 | for (l = c + 1; l < endcol; l++) { 239 | 240 | int v = (*(B+dstofs) - *(B+srcofs) * b) % prime; 241 | *(B+dstofs) = v; 242 | dstofs++; 243 | srcofs++; 244 | } 245 | 246 | *(B+pofs) = 0; 247 | if (*(r_nonzero+2*k+1) < endcol) *(r_nonzero+2*k+1) = endcol; 248 | } 249 | pofs += ccnt; 250 | } 251 | 252 | r++; 253 | c++; 254 | ofs += ccnt + 1; 255 | 256 | } 257 | } 258 | 259 | /* transpose back to matlab format */ 260 | pofs = 0; 261 | for (k=0;k 2 45 | sW = screen(3); 46 | sH = screen(4); 47 | fW = sW/cols; 48 | fH = (sH+(rows-1)*hSize)/rows; 49 | i = ceil(ord/cols); 50 | j = rem(ord-1,cols); 51 | left = j * fW + screen(1); 52 | bottom = screen(2) + screen(4) - i * fH; 53 | else 54 | left = rows(1)+screen(1); 55 | bottom = rows(2)+screen(2); 56 | fH = rows(3); 57 | fW = rows(4); 58 | f = cols; 59 | end 60 | if i>1 61 | bottom = bottom + (i-1)*hSize; 62 | end 63 | set(f,'OuterPosition',[left bottom fW fH]); 64 | set(f,'Visible','on'); 65 | return 66 | -------------------------------------------------------------------------------- /installation.txt: -------------------------------------------------------------------------------- 1 | Introduction 2 | ------------ 3 | 4 | This software package contains Groebner basis solvers generator as 5 | described in paper 6 | 7 | Kukelova Z., Bujnak M., Pajdla T., Automatic Generator of Minimal 8 | Problem Solvers, ECCV 2008, Marseille, France, October 12-18, 2008 9 | 10 | Please refer to the license.txt for licensing details. 11 | 12 | 13 | Installation 14 | ----------------------- 15 | 16 | This package does not require any installation. Package contains all 17 | necessary modules. By default the solvers generator uses Macaulay2 to 18 | compute Groefner basis (GB). Or it is possible to use Maple toolbox to 19 | compute GB. 20 | 21 | Please refer to "generator\gbs_InitConfig.m" for further generator 22 | configuration. The file should be self explanatory enough. 23 | 24 | 25 | Groebner basis solver 26 | --------------------- 27 | 28 | We recommend to install Macaulay2 software package which provides fast and 29 | stable Groebner basis solver. 30 | Download it from "http://www.math.uiuc.edu/Macaulay2/" or install one 31 | (for Windows) located in prerequisites directory ("macaulay2-0.9.2-3.msi"). 32 | 33 | If you are using this package for Windows, update all "!!TODO:" labeled 34 | items in "gbsMacaulay\calc.bat". Please remove "!!TODO:" label and fill 35 | correct full paths to Macaulay2 installation directory according to 36 | example in "calc.bat". 37 | 38 | Then, check that "% cfg.GBSolver = @gbs_findAlgB_macaulay;" line in 39 | "generator\gbs_InitConfig.m" is uncommented. This will enable Macaulay 40 | Groebner basis solver in the solvers generator. 41 | 42 | 43 | Custom Groebner basis solver 44 | ---------------------------- 45 | 46 | Note that "cfg.GBSolver" is any function of the form: 47 | 48 | [algB res] = GBSolver(cfg, eq, known, unknown); 49 | 50 | which returns basis of algebra B (please refer to the paper) given list of 51 | equations, known and unknown variables. By default, the package contains 52 | "gbs_findAlgB_macaulay" and "gbs_findAlgB_maple" which are wrappers to 53 | Macaulay2 and Maple Groebner basis solvers. However, you can implement your 54 | own wrapper. 55 | 56 | 57 | Using matrix patitioning 58 | ------------------------ 59 | 60 | To enable matrix patitioning change variable "cfg.cfg.matrixPartitioning" 61 | in config file "generator\gbs_InitConfig.m" according to the description in 62 | this file. 63 | 64 | This package uses tool PaToH to partition sparse matrices to speed up the 65 | Gauss-Jordan eliminations. This tool is not available for Windows. To 66 | download this tool see "http://bmi.osu.edu/~umit/software.html#patoh" or 67 | use downloaded packages located in "prerequisites/PaToH/". For installation 68 | see instructions enclosed in these packages. 69 | 70 | 71 | Limitations 72 | ----------- 73 | 74 | This package has been tested on Matlab 2015 64bit and 32bit. Code 75 | generator does not handle all cases when basis of algebra A does not 76 | contain action matrix variable. Then, eigenvalues of the action matrix are 77 | solutions to the action variable and corresponding eigenvectors contain 78 | solution to remaining unknowns. 79 | 80 | 81 | First test 82 | ---------- 83 | 84 | To add all required paths run script "setpaths.m". 85 | 86 | Set of some examples of minimal problems are stored in folder 87 | "minimalProblems". To generate solver for some exmaple execute function 88 | "gbs_GenerateSolver(nameOfMinimalProblem)", for example 89 | "gbs_GenerateSolver('sw6pt')". All examples of minimal problems are self 90 | explanatory and will teach you how to use the generator. 91 | 92 | The solver generator must be called from its root directory (the place, 93 | where "setpath.m" file is located). 94 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2 | 3 | 2008 Martin Bujnak, Zuzana Kukelova, Tomas Pajdla CTU in Prague. 4 | 2014 Pavel Trutman, Zuzana Kukelova, Tomas Pajdla CTU in Prague 5 | 6 | All Rights Reserved. 7 | 8 | Permission to use [*] this software for academic purposes is hereby 9 | granted without fee or royalty, subject to the following conditions. 10 | 11 | 1. The software is provided "as is" by the copyright holder, with 12 | absolutely no actual or implied warranty of correctness, fitness, 13 | intellectual property ownership, or anything else whatsoever. You use 14 | the software entirely at your own risk. In no event shall the copyright 15 | holder be liable for any direct, indirect or perceived damage whatsoever 16 | connected with the use of this work. 17 | 18 | 2. The software may not be distributed [*], whether in its original 19 | or modified form, without explicit written consent from the copyright 20 | holder. 21 | 22 | 3. The copyright holder retains all copyright to the work. 23 | 24 | 4. Any scholarly work, research or publication making use of this 25 | software must explicitly acknowledge the copyright holder. In the 26 | case of a publication, citation of the work, and authors thereof, 27 | titled 28 | 29 | "Kukelova Z., Bujnak M., Pajdla T., Automatic Generator of Minimal 30 | Problem Solvers, ECCV 2008, Marseille, France, October 12-18, 2008" 31 | 32 | is deemed sufficient acknowledgement. 33 | 34 | Permission to use or distribute [*] this software for commercial or 35 | military purposes, or under any conditions not covered by the conditions 36 | 1-4 above, is NOT granted. Such permission may be obtained subject to 37 | explicit prior written consent from the copyright holder. 38 | 39 | [*] `Use' denotes any use whatsoever including downloading, compilation, 40 | execution and modification. `Distribution' includes any distribution of 41 | the software and any derived works such as object files, executable 42 | programs and libraries. 43 | 44 | Contact: Tomas Pajdla: pajdla@cmp.felk.cvut.cz 45 | 46 | -------------------------------------------------------------------------------- /minimalProblems/ku9pt.m: -------------------------------------------------------------------------------- 1 | function [eq, known, unknown, kngroups, cfg, algB] = ku9pt() 2 | 3 | g1 = transpose(gbs_Vector('g1', 7)); 4 | g2 = transpose(gbs_Vector('g2', 7)); 5 | g3 = transpose(gbs_Vector('g3', 7)); 6 | g4 = transpose(gbs_Vector('g4', 7)); 7 | g5 = transpose(gbs_Vector('g5', 7)); 8 | g6 = transpose(gbs_Vector('g6', 7)); 9 | g7 = transpose(gbs_Vector('g7', 7)); 10 | g8 = transpose(gbs_Vector('g8', 7)); 11 | g9 = transpose(gbs_Vector('g9', 7)); 12 | 13 | syms f31 f32 k1 k2; 14 | 15 | mon = [k1*f32,k1*k2,f31,f32,k1,k2,1].'; 16 | 17 | % parametrization of the fundamental matrix with four unknowns 18 | f11 = -g1*mon; 19 | f12 = -g2*mon; 20 | f13 = -g6*mon; 21 | f21 = -g3*mon; 22 | f22 = -g4*mon; 23 | f23 = -g8*mon; 24 | 25 | % fundamental matrix 26 | F = [f11 f12 f13; f21 f22 f23; f31 f32 1]; 27 | 28 | % four polynomial equations 29 | eq(1) = -(k2*g6)*mon + g5*mon; 30 | eq(2) = -(k2*g8)*mon + g7*mon; 31 | eq(3) = det(F); 32 | eq(4) = k1*f31+g9*mon; 33 | 34 | % four unknowns 35 | unknown = {'f31' 'f32' 'k1' 'k2'}; 36 | 37 | % known parameters 38 | vars = transpose([g1(:); g2(:); g3(:); g4(:); g5(:); g6(:); g7(:); g8(:); g9(:)]); 39 | known = {}; 40 | for var = vars 41 | known = [known {char(var)}]; 42 | end 43 | 44 | kngroups = []; 45 | cfg = gbs_InitConfig(); 46 | algB = []; 47 | 48 | end -------------------------------------------------------------------------------- /minimalProblems/rolling_shutter_generator_linear_I_planar.m: -------------------------------------------------------------------------------- 1 | % 2 | % P6P rolling shutter (eliminated) 3 | function [eq, known, unknown, kngroups, cfg, algB] = minimal_rolling_shutter_generator_linear_I_planar() 4 | 5 | g1 = transpose(gbs_Vector('g1', 8)); 6 | g2 = transpose(gbs_Vector('g2', 8)); 7 | g3 = transpose(gbs_Vector('g3', 8)); 8 | g4 = transpose(gbs_Vector('g4', 8)); 9 | g5 = transpose(gbs_Vector('g5', 8)); 10 | g6 = transpose(gbs_Vector('g6', 8)); 11 | 12 | 13 | 14 | syms v_1 v_2 v_3 w_1 w_2 w_3; 15 | 16 | 17 | mon = [v_3*w_3 v_1 v_2 v_3, w_1, w_2, w_3, 1]; 18 | 19 | cfg = gbs_InitConfig(); 20 | 21 | clear eq; 22 | 23 | 24 | % g1(1) = 1 25 | % g2(1)=0 26 | % g3(1)=0 27 | % g4(1)=1 28 | % g5(1)=0 29 | % g6(1)=0 30 | % 31 | % g1(5)=0 32 | % g2(5)=0 33 | % g3(5)=0 34 | % g4(5)=0 35 | % g5(5)=0 36 | % g6(5) = 1; 37 | % 38 | % g1(6)=0 39 | % g2(6)=0 40 | % g3(6)=0 41 | % g4(6)=0 42 | % g5(6)=-1 43 | % g6(6)=0 44 | % 45 | % g1(7) = 0 46 | % g2(7) = -1 47 | % g3(7) = 1 48 | % g4(7) = 0 49 | % g5(7)=0 50 | % g6(7)=0 51 | 52 | 53 | eq(1) = v_1*w_1 + g1*transpose(mon); 54 | eq(2) = v_1*w_2 + g2*transpose(mon); 55 | eq(3) = v_2*w_1 + g3*transpose(mon); 56 | eq(4) = v_2*w_2 + g4*transpose(mon); 57 | eq(5) = v_3*w_1 + g5*transpose(mon); 58 | eq(6) = v_3*w_2 + g6*transpose(mon); 59 | 60 | 61 | % g1 = transpose(gbs_Vector('g1', 8)); 62 | % g2 = transpose(gbs_Vector('g2', 8)); 63 | % g3 = transpose(gbs_Vector('g3', 8)); 64 | % g4 = transpose(gbs_Vector('g4', 8)); 65 | % g5 = transpose(gbs_Vector('g5', 8)); 66 | % g6 = transpose(gbs_Vector('g6', 8)); 67 | 68 | unknown = {'v_1' 'v_2' 'v_3' 'w_1' 'w_2' 'w_3'}; 69 | vars = transpose([g1(:); g2(:); g3(:); g4(:); g5(:); g6(:)]); 70 | known = {}; 71 | for var = vars 72 | known = [known {char(var)}]; 73 | end 74 | 75 | % create symbolic vars 76 | for mon = unknown 77 | eval(['syms ' char(mon) ';']); 78 | end 79 | 80 | %cfg.eqinstance = R6P_planar_inst(cfg); 81 | 82 | % call code generator 83 | kngroups = ones(8,1)*[1 2 3 4 5 6]; 84 | %[res export] = gbs_CreateCode('p6p_rs_lin_I_planar', eq, known, unknown, kngroups); 85 | algB = []; 86 | 87 | %[A symcoefs] = rsSolver('imu3pr_peieg.m', eq, 'tan', unknown, known, kngroups); 88 | end -------------------------------------------------------------------------------- /minimalProblems/sw5pt.m: -------------------------------------------------------------------------------- 1 | function [eq, known, unknown, kngroups, cfg, algB] = sw5pt() 2 | %% 3 | % 5point relative pose problem 4 | % http://cmp.felk.cvut.cz/minimal/5_pt_relative.php 5 | 6 | %% 7 | % register the generator 8 | setpaths; 9 | 10 | %% 11 | % create symbolic matrices 12 | % these matrices represent basis of null space of linearized equation y'*E*x = 0 13 | % matrices E1, E2, E3, E4 will be treated as known 14 | E1 = gbs_Matrix('E1%d%d', 3 ,3); 15 | E2 = gbs_Matrix('E2%d%d', 3 ,3); 16 | E3 = gbs_Matrix('E3%d%d', 3 ,3); 17 | E4 = gbs_Matrix('E4%d%d', 3 ,3); 18 | 19 | % create essential matrix as a linear combination of the null space 20 | % (symbolicaly - variables x, y, z are unknown) 21 | syms x y z; 22 | E = x*E1 + y*E2 + z*E3 + E4; 23 | 24 | % build equations 25 | % 1. essential matrix is singular 26 | eq(1) = det(E); 27 | 28 | % 2. essential matrix "trace" constrain - two singular values are equal 29 | % and one zero (note that this constrain ensures essential matrix 30 | % sinularity too. However, adding the equation comming from determinant 31 | % causes that generator does not need to generate new polynomials in order 32 | % to find solution. 33 | % 34 | Et = transpose(E); 35 | te = 2*(E*Et)*E - trace(E*Et)*E; 36 | eq(2:10) = te(:); 37 | 38 | %% 39 | % collect known & unknown variables 40 | unknown = {'x' 'y' 'z'}; 41 | vars = transpose([E1(:); E2(:); E3(:); E4(:)]); 42 | known = {}; 43 | for var = vars 44 | known = [known {char(var)}]; 45 | end 46 | 47 | %% 48 | % specify which "known" variables should be grouped into a single input argument (as 49 | % a vector). "kngroups" is a vector where kngroups(k) = l says that k-th 50 | % known variable should be grouped into l-th vector. 51 | kngroups = ones(9,1)*[1 2 3 4]; 52 | 53 | % optionaly you can call the code generator with 54 | % different configuration (cfg) or custom basis of algebra A (algB). 55 | cfg = gbs_InitConfig(); 56 | algB = []; 57 | 58 | end -------------------------------------------------------------------------------- /minimalProblems/sw6pt.m: -------------------------------------------------------------------------------- 1 | function [eq, known, unknown, kngroups, cfg, algB] = sw6pt() 2 | %% 3 | % 6point focal length problem 4 | % http://cmp.felk.cvut.cz/minimal/6_pt_relative.php 5 | 6 | %% 7 | setpaths; 8 | 9 | %% 10 | % create symbolic matrices 11 | % these matrices represent basis of null space of linearized equation y'*E*x = 0 12 | % matrices F1, F2, F3 will be treated as known 13 | F1 = gbs_Matrix('F1%d%d', 3 ,3); 14 | F2 = gbs_Matrix('F2%d%d', 3 ,3); 15 | F3 = gbs_Matrix('F3%d%d', 3 ,3); 16 | 17 | % create fundamental matrix as a linear combination of the null space, 18 | % w = 1/focal^2 19 | % (symbolicaly - variables x, y, w are unknown) 20 | syms x y w real; 21 | F = x*F1 + y*F2 + F3; 22 | 23 | % build equations 24 | % 1. fundamental matrix is singular 25 | eq(1) = det(F); 26 | 27 | Q = diag([1 1 w]); 28 | 29 | % calibrate fundamental matrix using unknown focal length and use "trace" 30 | % constrain for obtained essential matrix 31 | Ft = transpose(F); 32 | te = 2*(F*Q*Ft*Q)*F - trace(F*Q*Ft*Q)*F; 33 | eq(2:10) = te(:); 34 | 35 | %% 36 | % collect known & unknown variables 37 | unknown = {'x' 'y' 'w'}; 38 | vars = transpose([F1(:); F2(:); F3(:)]); 39 | known = {}; 40 | for var = vars 41 | known = [known {char(var)}]; 42 | end 43 | 44 | %% 45 | 46 | % define variable groups (optional) 47 | kngroups = ones(9,1)*[1 2 3]; 48 | 49 | % define configuration 50 | cfg = gbs_InitConfig(); 51 | 52 | % no algB yet computed 53 | algB = []; 54 | 55 | end -------------------------------------------------------------------------------- /minimalProblems/test.m: -------------------------------------------------------------------------------- 1 | function [eq, known, unknown, kngroups, cfg, algB] = test() 2 | 3 | % symbolic variables 4 | syms a0 a1 a2 a3 a4 b0 b1 b2 b3 b4; 5 | syms x y; 6 | 7 | % two equations representing an ellipse and a hyperbola 8 | eq(1) = a0*x^2 + a1*x + a2*y^2 + a3*y + a4; 9 | eq(2) = b0*x^2 + b1*x - b2*y^2 + b3*y + b4; 10 | 11 | % known parameters 12 | known = {'a0' 'a1' 'a2' 'a3' 'a4' 'b0' 'b1' 'b2' 'b3' 'b4'}; 13 | 14 | %two unknowns 15 | unknown = {'x' 'y'}; 16 | 17 | %no kngroups 18 | kngroups = []; 19 | 20 | %config file 21 | cfg = gbs_InitConfig(); 22 | 23 | %we do not have precomputed algB 24 | algB = []; 25 | 26 | end 27 | -------------------------------------------------------------------------------- /prerequisites/PaToH/patoh-Linux-i386.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PavelTrutman/Automatic-Generator/71e530a55fd07d381bc022e1e18a3d46ef5be460/prerequisites/PaToH/patoh-Linux-i386.tar.gz -------------------------------------------------------------------------------- /prerequisites/PaToH/patoh-Linux-x86_64.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PavelTrutman/Automatic-Generator/71e530a55fd07d381bc022e1e18a3d46ef5be460/prerequisites/PaToH/patoh-Linux-x86_64.tar.gz -------------------------------------------------------------------------------- /prerequisites/PaToH/patoh-matlab.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PavelTrutman/Automatic-Generator/71e530a55fd07d381bc022e1e18a3d46ef5be460/prerequisites/PaToH/patoh-matlab.tar.gz -------------------------------------------------------------------------------- /prerequisites/macaulay2-0.9.2-3.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PavelTrutman/Automatic-Generator/71e530a55fd07d381bc022e1e18a3d46ef5be460/prerequisites/macaulay2-0.9.2-3.msi -------------------------------------------------------------------------------- /setpaths.m: -------------------------------------------------------------------------------- 1 | start_path = pwd; 2 | addpath([start_path]); 3 | addpath(genpath([start_path filesep 'generator'])); 4 | addpath(genpath([start_path filesep 'minimalProblems'])); 5 | addpath(genpath([start_path filesep 'benchmark'])); 6 | addpath(genpath([start_path filesep 'solvers'])); -------------------------------------------------------------------------------- /solvers/.gitignore: -------------------------------------------------------------------------------- 1 | *.m 2 | *.txt --------------------------------------------------------------------------------