Skip to content

Commit

Permalink
Boundary function optimization working.
Browse files Browse the repository at this point in the history
  • Loading branch information
Folláth János committed Jun 13, 2014
1 parent 191464a commit a1fefc0
Show file tree
Hide file tree
Showing 20 changed files with 1,413 additions and 713 deletions.
77 changes: 68 additions & 9 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ cleanbkz is a library to find short vectors in a lattice. Once finished
it will contain an improved enumeration algorithm using extreme pruning,
the bkz2.0 and probably an improved random sampler algorithm.

To compile and test it, you can follow these steps:

------------------------
1. Compile cleanbkz sources
1. Compiling the cleanbkz sources
------------------------

cleanbkz requires the NTL library. Version 5.4.2 (or higher) is needed.
Expand All @@ -15,11 +13,70 @@ $ cmake .
$ make

Now both the library and the tests are compiled. You can find the test
executables in the bin/ folder.
executables and the command line interface in the bin/ folder.

The scripts plot.sh and debug.sh require gnuplot to function properly
and visualize the generated data.


------------------------
2. The command line interface
------------------------

Every command line tool has a built-in help accessible with the -h switch.
Examples:

0) Measuring the rate of reduction and enumeration:

./bin/timing -d 60 -k 20 -n 960

Wait until it finishes. On a AMD Opteron(tm) 3380 it took 15 minutes and
gave the following result:

Measuring dimension 60:
t_node= 6.26296e-08
t_reduc= 0.855437


1) Generating a lattice:

./bin/genlattice -d 60 -c 0.94 -s 11 -k 20 > data/d60s11k20c0_94.lat


2) Generating a boundary function:

./bin/boundtool -f data/d60s11k20c0_94.lat -n 6.26296e-08 -r 0.855437 -l 60 > data/d60s11k20c0_94.plt

Wait until it finishes. On a AMD Opteron(tm) 3380 it took 20 minutes. You
also can generate a pdf chart of the bounding function:

./plot.sh data/d60s11k20c0_94.plt

This bounding function will not yet be optimal. To get a close to optimal
bounding function run the optimization a little longer:

./bin/boundtool -f data/d60s11k20c0_94.lat -n 6.26296e-08 -r 0.855437 -l 60 -c 3000 > data/d60s11k20c0_94_tri.plt


3) Running the actual enumeration:

The file produced in the previous step contains data for gnuplot and
other information like the bounding function in NTL's format, the
predicted success probability and the expected running time.

The following program requires the boundary function in NTL's format,
so first we need to copy the line (without the starting '#' sign) in
a new text file. In this example the name of this new text file is
'd60s11k20c0_94.bnd'. Now issue the command

./bin/eprune -l data/d60s11k20c0_94.lat -b data/d60s11k20c0_94.bnd

and wait until it finishes. On a AMD Opteron(tm) 3380 it took around
89 seconds, fairly close to the promised 95 seconds.


------------------------
2. Generate documentation
3. Generate API documentation
------------------------

The source files are annotated for doxygen documentation. To generate
Expand All @@ -31,14 +88,16 @@ Now the documentation is in the doc/ folder.


------------------------
3. File extensions and formats
4. File extensions and formats
------------------------

.lat These are the data files generated by the lattice_gen tool and
.lat These are the data files generated by the genlattice tool and
contain the lattice basis in NTL's output format.

.plt Boundary function generated by the boudtool application in a form
readable by gnuplot.
.plt Boundary function generated by the boundtool application in a
form readable by gnuplot.

.bnd Boundary function in NTL's format. It is usually created by
copying the corresponding line from a .plt file.


72 changes: 18 additions & 54 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,65 +1,29 @@
- Minimális pruning function keresését kikisérletezni:
- tesztelni a gyakorlatban a képletemet állitható kezdőértékkel (dupla és sima random lattice-el is)
- konstans pruninggal megkeresni a megfelelő arányokat az egyes dimenziókban (dupla és sima random lattice-el is)
- több különböző lattice-ra és összehasonlitani

- a random lattice-s tesztprogramból automatikus teszteket irni
- node számlálás full (double)
- extreme pruning tesztet külön lefuttatni, hogy ha van még valami gond, akkor az itt kiderüljön
- node számlálás pruned (double)
- node számlálás full
- node számlálás pruned
- elküldeni a többieknek a linket a github projektre
- implementálni az adaptiv a keresést: kezd egy viszonylag nagy deltával, megy amig nem tud javitani, osztja a deltát 10-el majd szintén megy amig nem tud javitani és igy tovább (betenni a unit tesztbe)

- elküldeni a többieknek a linket a github projektre és a generált teszt-adatokat
- Közvetlenül előtte persze commitolni

************ Szünet *******************
- optimalizálni a számitásokat:
- a négyzetreemeléseket kihozni amennyire csak lehet
- előre számitani és táblázatból olvasni
- az egységgömbök térfogatát
- a faktoriálisokat
- a normalizáló konstansokat
- kikisérletezni, hogy mi az a legkisebb RR pontosság amire a 120-150 dimenziós számitás stabil
- letekerni a pontosságot amennyire csak lehet
- implementálni az adaptiv a keresést: kezd egy viszonylag nagy deltával, megy amig nem tud javitani, osztja a deltát 10-el majd szintén megy amig nem tud javitani és igy tovább
- print scriptet egyesiteni és paraméterezhetőre megirni

******** Itt lesz kész az extreme pruning *****
- Megnézni az early termination-ös cikkeket, hogy milyen blokkméretet lenne érdemes használni egy 128 dimenziós bázis előfeldolgozásához
- Megirni a pruningos BKZ-t, enumerationt külön függvénybe tenni
- Minden enumeration hivást és a vonatkozó unit teszteket átirni az új enumeration-re
- kikisérletezni a paramétereket a bkz automatikus bounding function keresőjéhez
- Implementálni a radius reductiont és az early terminationt
- Implementálni az unexpected early terminationt (mindig kiirja lemezre, hogy hanyadik iterációnál jár és hogy mi az aktuális bázis)
Kérdések:
- miért használt a bkz 2.0-nál 10%-os sikeresélyűt, amikor nekem 95% körüliek sikerülnek és az is baromi gyorsra igéri magát?
- miért más a formája az én boundary functionjeimnek?
Opcionálisan:
- Megnézni, hogy milyen hatással van a mu korrigálása az enumerationra
- valszeg semmilyen, mert a főátlót eleve 1-nek veszi. Megkeresni a vonatkozó részt az algoritmusban
+ átirni, hogy mindig az R_i négyzetekkel dolgozzon és ne kelljen gyököt vonogatni. - Nem éri meg: ugyanolyan macerás, mert a gömbök sugaránál R_i kell.
- hermite faktoros optimalizálást implementálni
- refaktorálni a toolok paraméterfeldolgozását
- letisztázni és kibőviteni a unit teszteket
- a unit tesztekhez használt referenciaimplementációkat kiszedni a libből a teszt könyvtárba
- a boundtool.cpp -ek és a boundary.cpp -nek értelmesebb neveket találni
- Tesztet irni, hogy a double sqrt négyzete egyezik-e az eredetivel (különbség 0)

******** Itt lesz kész a BKZ1.5 **********
- a rekurzive hivás paramétereit kikisérletezni :
- Hermite faktorokat lemérni (early terminatiönnel és anélkül)
- várható futási időket a bounding function számolóval összevetni
- random lattice-ekre is elvégezni a méréseket és összehasonlitani a cjlossosokkal (ehhez előtte megnézni Gama-Nguyent)
- saját namespace-t csinálni hasonlón dinamikusan mint az NTL-ben
- polytopvol unit tesztet kiegésziteni 15 dimenzióra
- megirni a cikket és a megjelenés után átirni a dokumentációban a hivatkozásokat amiket lehet a saját cikkemre
- Általános BKZ-t implementálni: LLL -el redukálni bkz helyett és úgy lemérni az időket (10000000 node kell a viszonylagos stabilitáshoz és 45-nél már elég gyakran nem éri ezt el, szóval az az eredmény nem lesz olyan pontos)
+ paraméterezni a programot a sample mérettel (hogy tudjam becsülni a magas mintás futási időt alacsony mintamérettel), futási időket megbecsülni
- 50 dimenzióval kikisérletezni a sample méretet ami kell a 3 stabil tizedesjegyhez
- lemérni 50, 55, 60, 65, 70, 75, 80 -ra (automatizálva)
- extrapolálni 40, 45 -re (automatizálni)
- Általános bounding function-öket találni (erősen opcionális: lehet róla irni, de kicsi a siker valószinűsége és nem egy nagy eredmény)
- GSA feltételes bounding function keresőt implementálni
- tesztelni, hogy hogyan változik a bounding function a gs hossz változtatásával
- tesztelni, hogy hogyan változik a futási idők változtatásával

Problémák:
- az NTL szabványos függvényeit használva külön kell kiszámolni a GS együtthatókat, pedig azokat már a redukcióhoz kiszámolja. Lehetséges megoldások:
- igy hagyni és a számitásokat úgy végezni mintha nem lenne ott (ugyanis magas dimenziókban tényleg elhanyagolható a költsége)
- duplikálni és módositani a szükséges NTL függvényeket
- a cjloss bázisát publikussá kellett tennem, hogy működjenek a dolgok, lehet, hogy át kéne szerveznem, hogy a bázis ne csak adattag legyen, hanem a mat_ZZ kiterjesztése - vagy nem: az egész csak egy teszt, nem is kell a libbe, át fogom tenni a tests könyvtárba
- a méréshez egyéb utasitásokat is bele kell tennem az algoritmusba. Ez tényleges futás esetén lassithatja és olyan paramétereket is megkövetel, amik egy sima enumeration hiváskor nem kellenek. Lehetőségek
- bevállalom az ezzel járó lassulást (mennyivel is lesz ettől lassabb? (méréshez rögziteni a cjloss seedet))
- duplikálom a kódot
- alacsony dimenzióban többnyire csak nagyon kevés node-ot kell megvizsgálnia, igy olyan kevés időt tölt vele, hogy nem tudja mérni. Lehetséges megoldások:
- ha megtalálta a legrövidebb vektort akkor resetelem és futtatom amig elég idő nem lesz -nagyon torzit
- magasabb dimenziós mérésekből approximálom
- bármilyen dimenzióban változó és bázistól függő a futási idő, kérdés, hogy hogyan rendeljek egy adott dimenzióhoz egy konkrét értéket. Tapasztalati várható érték (átlag tűnik a legjobbnak), de kérdés,
- hogy mennyi mintát vegyek alapul
- milyen (cjloss vagy teljesen random) lattice-t vegyek alapul (majdnem mindegy, mert az LLL redukció úgyis hasonló formára hozza)
- eddig b_0^* hosszát használtam kezdő sugárnak. Mi az amit a BKZ használ és mi az amit Phong használt a BKZ 2.0-ában? A méréseknek is úgy lenne értelme, ha onnan inditanám (és akkor a kicsik is lehet hogy végigmennek)
4 changes: 4 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
SET(TARGET1 timing)
SET(TARGET2 boundtool)
SET(TARGET3 genlattice)
SET(TARGET4 eprune)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
LINK_DIRECTORIES(${LIBRARY_OUTPUT_PATH})

Expand All @@ -12,3 +13,6 @@ TARGET_LINK_LIBRARIES(${TARGET2} cleanbkz ntl)

ADD_EXECUTABLE(${TARGET3} genlattice.cpp)
TARGET_LINK_LIBRARIES(${TARGET3} cleanbkz ntl)

ADD_EXECUTABLE(${TARGET4} eprune.cpp)
TARGET_LINK_LIBRARIES(${TARGET4} cleanbkz ntl)
82 changes: 55 additions & 27 deletions app/boundtool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,15 @@
using namespace std;

// Defined in boundary.cpp
// TODO: ehelyett majd egy get_p_succ nevűt irni, ami megcsinálja amit kell
double polytope_volume(double vols[], double bounds[], int dim);
extern double ball_vol(int k, double r);

// Defined in tools.cpp
char* get_cmd_option(char** begin, char** end, const string& option);
bool cmd_option_exists(char** begin, char** end, const string& option);


int main(int argc, char** argv) {

double v= 0;
double t_node= 0;
double t_reduc= 0;
double delta= 1e-1;
Expand All @@ -56,8 +55,8 @@ int main(int argc, char** argv) {
<< "\t-n n\t\tThe (avarage) time the enumeration algorithm takes to process a single node. (required)" << endl
<< "\t-r n\t\tThe (avarege) running time of the preprocessing reduction algorithm. (required)" << endl
<< "\t-c n\t\tNumber of random changes to make during the numerical optimization. (default: 1000)" << endl
<< "\t-t n\t\tThe number of unchanged rounds to require before exiting. It is ignored when -c is given." << endl
<< "\t-d n\t\tThe size of the single random changes to meke during the optimization. (default: 0.1)" << endl;
<< "\t-d n\t\tThe size of the single random changes to meke during the optimization. (default: 0.1)" << endl
<< "\t-l n\t\tOptimize for shortest vector with length square root of n. (the Gaussian heuristic is default)" << endl;
return 0;
}

Expand Down Expand Up @@ -120,6 +119,18 @@ int main(int argc, char** argv) {
}
}

act_arg= get_cmd_option(argv, argv + argc, "-l");
if (act_arg) {
ss << act_arg;
ss >> v;
ss.clear();
if(v <= 0) {
cerr << "ERROR: invalid shortest vector length. The shortest vector length should be greater than zero. Aborting." << endl;
return 1;
}
}


act_arg= get_cmd_option(argv, argv + argc, "-f");
if (act_arg) {
ifstream basis_file(act_arg);
Expand All @@ -145,32 +156,49 @@ int main(int argc, char** argv) {
int dim= mu1.NumRows();
double* boundary= new double[dim];

//length of the shortest vector in the cjloss latticr
double R= sqrt(dim-1);
cout << "# Generated with cleanbkz " << CBKZ_VERSION << endl
<< "# Copyright (C) 2014 Janos Follath" << endl
<< "# This is free software with ABSOLUTELY NO WARRANTY." << endl << "#" << endl;

//length of the shortest vector in the cjloss lattice
if(v>0) {
v= sqrt(v);
cout << "# Using supplied lambda : " << v << endl;
}
else {
double tmp,gh= 1;
double* gsghs= new double[dim];
for(int i= 0; i < mu1.NumRows(); i++) {
conv(tmp, c1[i]);
gh*= tmp;
gsghs[i]= pow(gh/ball_vol(i+1, 1),1.0/(i+1));
}
delete gsghs;
gh= pow(gh/ball_vol(dim, 1),1.0/dim);
cout << "# No lambda supplied, using Gaussian heuristic: " << gh << endl;
}



// TODO: csinálni egy változatot, ahol nem iterationt hanem thressholdot adunk meg
double p_succ;
double t_enum;
generate_boundary(c, t_node, t_reduc, dim, boundary, R, delta, iterations, p_succ, t_enum, false);

cout << "# Generated with cleanbkz " << CBKZ_VERSION << endl
<< "# Copyright (C) 2014 Janos Follath" << endl
<< "# This is free software with ABSOLUTELY NO WARRANTY." << endl << "#" << endl;

cout << "# basis: '" << act_arg << "' " << endl
<< "# estimated enumeration time: " << t_enum << endl
<< "# success probability: " << p_succ << endl
<< "# boudary function: " << endl;

vec_RR out;
out.SetLength(dim);
for(int i= 0; i < dim; i++)
out[i]= boundary[i];
cout << "# " << out << endl << endl;

for(int i= 0; i < dim; i++)
cout << i << " " << boundary[i] << endl;
cout << endl;
generate_boundary(c, t_node, t_reduc, dim, boundary, v, delta, iterations, p_succ, t_enum, false);

cout << "# basis: '" << act_arg << "' " << endl
<< "# estimated enumeration time: " << t_enum << endl
<< "# success probability: " << p_succ << endl
<< "# boudary function: " << endl;

vec_RR out;
out.SetLength(dim);
for(int i= 0; i < dim; i++)
out[i]= boundary[i];
cout << "# " << out << endl << endl;

for(int i= 0; i < dim; i++)
cout << i << " " << boundary[i] << endl;
cout << endl;

return 0;
}
Loading

0 comments on commit a1fefc0

Please sign in to comment.