Corrected some bugs

This commit is contained in:
Wojciech Politarczyk 2017-02-08 12:05:23 +01:00
parent 816e2eef59
commit 6374563de1
4 changed files with 231 additions and 294 deletions

330
kk.cpp
View File

@ -2,14 +2,10 @@
#include <periodicity.h>
#include <fstream>
#include <sstream>
#include <thread>
#include <future>
#include <vector>
#include <utility>
#include <cctype>
const unsigned max_threads = 4;
const char *program_name;
void
@ -91,11 +87,10 @@ void tex_footer ()
const char *knot = 0;
const char *invariant = 0;
const char *field = "Z2";
std::string periodicity_test = "Przytycki";
int period = 5;
knot_diagram kd;
bool reduced = 0;
std::string in_file_name = "/home/wojtek/ownCloud/Lokalny/khovanov-homology-computation/homflypt_test/to_test_kh.txt";
extern int period;
extern std::string periodicity_test;
class hg_grading_mapper
{
@ -334,154 +329,6 @@ int compute_s_inv(knot_diagram& kd) {
return qmin + 1;
}
inline std::string parse_data_from_file(const std::string& data) {
auto p_start = data.find(":") + 2;
auto p_stop = data.find("]");
return data.substr(p_start, p_stop - p_start);
}
std::string perform_computations(const std::string& knot_name) {
std::ostringstream res;
knot_diagram kd = parse_knot(knot_name.c_str());
kd.marked_edge = 1;
Kh_periodicity_checker Kh_pc(kd, knot_name);
for(auto p: primes_list) {
res << "Kh criterion: " << Kh_pc(p) << std::endl;
}
return res.str();
}
void check_periodicity(std::string out_file) {
if(periodicity_test == "all") {
Kh_periodicity_checker Kh_pc(kd, std::string(knot));
for(auto& p : primes_list) {
std::cout << "Kh criterion: "
<< Kh_pc(p) << std::endl;
}
}
else if(periodicity_test == "Kh_from_file") {
std::ifstream in_file(in_file_name);
if(!in_file) {
std::cerr << "Cannot open file " << in_file_name << "\n";
exit(EXIT_FAILURE);
}
unsigned num_threads = std::min(max_threads, std::thread::hardware_concurrency());
std::string line;
std::string previous_knot;
std::vector<std::future<std::string>> v_future(num_threads);
bool stop = false;
while(!stop) {
unsigned i = 0;
while(i < num_threads) {
if(!in_file.eof()) {
std::getline(in_file, line);
std::string knot_name = parse_data_from_file(line);
if(knot_name == previous_knot)
continue;
else {
v_future[i] = std::async(std::launch::async, perform_computations, knot_name);
++i;
std::cerr << "Checking " << knot_name << "\n";
previous_knot = knot_name;
}
}
else {
stop = true;
break;
}
}
for(auto& v_f : v_future)
std::cout << v_f.get();
}
}
else if(periodicity_test == "all_seq") {
std::string k(knot);
// first check whether the number of crossings is bigger or lower than 10
if(isdigit(k[1])) {
// at least 10 crossings
if(k[1] == '0') {
// ten crossings
int num_cr = 10;
int knot_index = stoi(k.substr(3));
for(unsigned i = knot_index; i < rolfsen_crossing_knots(num_cr); i++) {
std::string knot_name = std::to_string(num_cr) + "_" + std::to_string(i);
knot_diagram kd_temp = parse_knot(knot_name.c_str());
kd.marked_edge = 1;
Kh_periodicity_checker Kh_pc(kd_temp, knot_name);
for(auto& p : primes_list) {
std::cout << "Kh criterion: "
<< Kh_pc(p) << std::endl;
}
}
}
else {
int num_cr = stoi(k.substr(0,2));
int knot_index = stoi(k.substr(3));
char alt = k[2];
bool alternating = (alt == 'a' ? true : false);
for(unsigned i = knot_index; i <= htw_knots(num_cr, alternating); i++) {
std::string knot_name = std::to_string(num_cr) + alt + std::to_string(i);
knot_diagram kd_temp = parse_knot(knot_name.c_str());
kd.marked_edge = 1;
Kh_periodicity_checker Kh_pc(kd_temp, knot_name);
for(auto& p : primes_list) {
std::cout << "Kh criterion: "
<< Kh_pc(p) << std::endl;
}
}
}
}
else {
// at most nine crossings
int num_cr = stoi(k.substr(0, 1));
int knot_index = stoi(k.substr(2));
for(unsigned i = knot_index; i <= rolfsen_crossing_knots(num_cr); i++) {
std::string knot_name = std::to_string(num_cr) + "_" + std::to_string(i);
knot_diagram kd_temp = parse_knot(knot_name.c_str());
kd.marked_edge = 1;
Kh_periodicity_checker Kh_pc(kd_temp, knot_name);
for(auto& p : primes_list) {
std::cout << "Kh criterion: "
<< Kh_pc(p) << std::endl;
}
}
}
}
else {
if(period == 2 || period == 3) {
std::cout << "Sorry, the criterion doesn't work for period "
<< period << "...\n";
exit(EXIT_FAILURE);
}
auto result = std::find(primes_list.begin(), primes_list.end(), period);
if(result == primes_list.end()) {
std::cout << "For now you can only check periodicity for primes up to 19..." << "\n";
exit(EXIT_FAILURE);
}
std::ofstream out(out_file, std::ios_base::app);
if(periodicity_test == "Przytycki") {
Przytycki_periodicity_checker P_pc(compute_jones(kd));
if(out_file.size() != 0)
out << P_pc(period) << std::endl;
else
std::cout << P_pc(period) << std::endl;
}
else if(periodicity_test == "Kh") {
Kh_periodicity_checker Kh_pc(kd, std::string(knot));
if(out_file.size() != 0)
out << Kh_pc(period) << std::endl;
else
std::cout << Kh_pc(period) << std::endl;
}
else {
std::cout << "Sorry, I don't recognize this option..." << "\n";
exit(EXIT_FAILURE);
}
}
}
template<class R> void
compute_invariant ()
{
@ -563,58 +410,56 @@ compute_invariant ()
ss.texshow (outfp, mapper);
tex_footer ();
}
else if (!strcmp (invariant, "leess"))
{
cube<R> c (kd, reduced);
ptr<const module<R> > C = c.khC;
else if (!strcmp (invariant, "leess")) {
cube<R> c (kd, reduced);
ptr<const module<R> > C = c.khC;
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
for (unsigned i = 1; i <= kd.n_crossings; i ++)
d = d + c.H_i (i);
assert (d.compose (d) == 0);
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
for (unsigned i = 1; i <= kd.n_crossings; i ++)
d = d + c.H_i (i);
assert (d.compose (d) == 0);
unsigned m = kd.num_components ();
hg_grading_mapper mapper (m);
unsigned m = kd.num_components ();
hg_grading_mapper mapper (m);
sseq_bounds b (C, mapper);
basedvector<sseq_page, 1> pages;
sseq_bounds b (C, mapper);
basedvector<sseq_page, 1> pages;
int k = 0;
for (;;) {
chain_complex_simplifier<R> s (C, d,
maybe<int> (1), maybe<int> (2*k));
C = s.new_C;
d = s.new_d;
k ++;
int k = 0;
for (;;)
{
chain_complex_simplifier<R> s (C, d,
maybe<int> (1), maybe<int> (2*k));
C = s.new_C;
d = s.new_d;
k ++;
grading dk_gr (1, 2*k);
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
if (d == 0)
break;
}
sseq ss (b, pages);
tex_header ();
fprintf (outfp, "$E_k = %s^{BN}_k(\\verb~%s~; \\verb~%s~)$:\\\\\n",
(reduced
? "\\widetilde{E}"
: "E"),
knot, field);
ss.texshow (outfp, mapper);
tex_footer ();
grading dk_gr (1, 2*k);
pages.append (sseq_page (b, k, dk_gr, d.graded_piece (dk_gr), mapper));
if (d == 0)
break;
}
sseq ss (b, pages);
tex_header ();
fprintf (outfp, "$E_k = %s^{BN}_k(\\verb~%s~; \\verb~%s~)$:\\\\\n",
(reduced
? "\\widetilde{E}"
: "E"),
knot, field);
ss.texshow (outfp, mapper);
tex_footer ();
}
else if (!strcmp (invariant, "s"))
{
int s = compute_s_inv<R>(kd);
fprintf (outfp, "s(%s; %s) = %d\n", knot, field, s);
}
else
{
fprintf (stderr, "error: unknown invariant %s\n", invariant);
exit (EXIT_FAILURE);
}
else {
fprintf (stderr, "error: unknown invariant %s\n", invariant);
exit (EXIT_FAILURE);
}
}
void
@ -818,14 +663,6 @@ main (int argc, char **argv)
}
periodicity_test = argv[i];
}
else if(!strcmp(argv[i], "-i")) {
i++;
if(i == argc) {
fprintf (stderr, "error: missing argument to option `-t'\n");
exit (EXIT_FAILURE);
}
in_file_name = argv[i];
}
else {
fprintf (stderr, "error: unknown argument `%s'\n", argv[1]);
fprintf (stderr, " use -h for usage\n");
@ -867,48 +704,41 @@ main (int argc, char **argv)
kd = parse_knot (knot);
kd.marked_edge = 1;
if (!strcmp (invariant, "gauss"))
{
if (!strcmp (invariant, "gauss")) {
basedvector<basedvector<int, 1>, 1> gc = kd.as_gauss_code ();
for (unsigned i = 1; i <= gc.size (); i ++)
{
if (i > 1)
printf (":");
for (unsigned j = 1; j <= gc[i].size (); j ++)
{
if (j > 1)
printf (",");
printf ("%d", gc[i][j]);
}
}
newline ();
}
for (unsigned i = 1; i <= gc.size (); i ++) {
if (i > 1)
printf (":");
for (unsigned j = 1; j <= gc[i].size (); j ++) {
if (j > 1)
printf (",");
printf ("%d", gc[i][j]);
}
}
newline ();
}
if (!strcmp (invariant, "sq2"))
{
if (strcmp (field, "Z2"))
{
fprintf (stderr, "warning: sq2 only defined over Z2, ignoring -f %s\n", field);
field = "Z2";
}
compute_sq2 ();
if (!strcmp (invariant, "sq2")) {
if (strcmp (field, "Z2")) {
fprintf (stderr, "warning: sq2 only defined over Z2, ignoring -f %s\n", field);
field = "Z2";
}
else if (!strcmp (invariant, "gss"))
{
if (strcmp (field, "Z2"))
{
fprintf (stderr, "warning: gss only defined over Z2, ignoring -f %s\n", field);
field = "Z2";
}
compute_gss ();
compute_sq2 ();
}
else if (!strcmp (invariant, "gss")) {
if (strcmp (field, "Z2")) {
fprintf (stderr, "warning: gss only defined over Z2, ignoring -f %s\n", field);
field = "Z2";
}
compute_gss ();
}
else if(!strcmp(invariant, "jones")) {
std::cout << "Jones polynomial of " << knot << " = " << compute_jones(kd, reduced) << "\n";
}
else if(!strcmp(invariant, "periodicity")) {
check_periodicity((file ? std::string(file) : std::string()));
check_periodicity(kd, std::string(knot), period, std::string(field));
}
else if(!strcmp(invariant, "khp")) {
multivariate_laurentpoly<Z> khp;
@ -931,20 +761,18 @@ main (int argc, char **argv)
<< ") of " << knot << " = " << std::endl
<< khp << std::endl;
}
else
{
if (!strcmp (field, "Z2"))
compute_invariant<Z2> ();
else if (!strcmp (field, "Z3"))
compute_invariant<Zp<3> > ();
else if (!strcmp (field, "Q"))
compute_invariant<Q> ();
else
{
fprintf (stderr, "error: unknown field %s\n", field);
exit (EXIT_FAILURE);
}
else {
if (!strcmp (field, "Z2"))
compute_invariant<Z2> ();
else if (!strcmp (field, "Z3"))
compute_invariant<Zp<3>> ();
else if (!strcmp (field, "Q"))
compute_invariant<Q> ();
else {
fprintf (stderr, "error: unknown field %s\n", field);
exit (EXIT_FAILURE);
}
}
if (file)
fclose (outfp);

View File

@ -2,6 +2,12 @@
#include <simplify_chain_complex.h>
#include <algorithm>
#include <utility>
#include <fstream>
std::string periodicity_test = "Przytycki";
int period = 5;
extern multivariate_laurentpoly<Z> compute_jones(const knot_diagram& k, bool reduced = false);
using polynomial_tuple = std::vector<std::tuple<multivariate_laurentpoly<Z>, multivariate_laurentpoly<Z>, multivariate_laurentpoly<Z>>>;
@ -39,7 +45,7 @@ bool Przytycki_periodicity_checker::check(int period) const {
std::string Przytycki_periodicity_checker::operator () (int period) const {
std::ostringstream res;
res << knot << ": period = " << period << ": "
res << knot_name << ": period = " << period << ": "
<< (check(period) ? "Maybe" : "No");
return res.str();
}
@ -82,8 +88,9 @@ multivariate_laurentpoly<Z> Kh_bounds_iterator::get_polynomial() const {
return p;
}
template<>
std::vector<multivariate_laurentpoly<Z>>
Kh_periodicity_checker::compute_knot_polynomials(knot_diagram& kd) {
Kh_periodicity_checker::compute_knot_polynomials<Z2>(knot_diagram& kd) {
unsigned m = kd.num_components ();
if (m != 1) {
std::cerr << "warning: this implementation of the criterion works for knots only...";
@ -122,21 +129,86 @@ Kh_periodicity_checker::compute_knot_polynomials(knot_diagram& kd) {
std::cerr << "KhP = " << khp << "\n";
std::cerr << "LeeP = " << leep << "\n";
}
// for(unsigned i = 0; i < lee_ss_polynomials.size(); ++i) {
// std::cerr << "lee_ss_polynomials[" << i << "]= "
// << lee_ss_polynomials[i] << "\n";
// std::cerr << "mul[" << i << "] = " << mul[i] << "\n";
// }
return lee_ss_polynomials;
}
template<typename R>
std::vector<multivariate_laurentpoly<Z>>
Kh_periodicity_checker::compute_knot_polynomials(knot_diagram& kd) {
unsigned m = kd.num_components ();
if (m != 1) {
std::cerr << "warning: this implementation of the criterion works for knots only...";
exit (EXIT_FAILURE);
}
cube<R> c (kd, 0);
ptr<const module<R> > C = c.khC;
mod_map<R> d = c.compute_d (1, 0, 0, 0, 0);
for (unsigned i = 1; i <= kd.n_crossings; i ++)
d = d + c.H_i (i);
assert (d.compose (d) == 0);
// computing Khovanov homology
if(verbose)
std::cerr << "Computing Khovanov homology" << std::endl;
std::vector<polynomial> lee_ss_polynomials;
int k = 0;
for(;;) {
chain_complex_simplifier<R> s(C, d, maybe<int>(1), maybe<int>(2*k));
C = s.new_C;
d = s.new_d;
if(k % 2 == 0) {
lee_ss_polynomials.push_back(C->free_poincare_polynomial());
if(k != 0)
mul.push_back(polynomial(Z(1)) + polynomial(Z(1), VARIABLE, 1, 1) * polynomial(Z(1), VARIABLE, 2, 2 * k));
}
if(d == 0)
break;
k++;
}
khp = *lee_ss_polynomials.begin();
leep = *lee_ss_polynomials.rbegin();
if(verbose) {
std::cerr << "KhP = " << khp << "\n";
std::cerr << "LeeP = " << leep << "\n";
}
return lee_ss_polynomials;
}
Kh_periodicity_checker::Kh_periodicity_checker(knot_diagram& kd,
std::string knot_n,
std::string f = "Z2") :
knot_name(knot_n), field(f) {
ev_index = 1;
index = 2;
quot = std::vector<polynomial>();
mul = std::vector<polynomial>();
if(field == "Z2")
compute_quot(compute_knot_polynomials<Z2>(kd));
else if(field == "Z3")
compute_quot(compute_knot_polynomials<Zp<3>>(kd));
else if(field == "Z5")
compute_quot(compute_knot_polynomials<Zp<3>>(kd));
else if(field == "Z7")
compute_quot(compute_knot_polynomials<Zp<7>>(kd));
else if(field == "Z11")
compute_quot(compute_knot_polynomials<Zp<11>>(kd));
else if(field == "Q")
compute_quot(compute_knot_polynomials<Q>(kd));
else {
std::cerr << "Sorry, I don't recognize field " << f << ". Exiting..." << "\n";
exit(EXIT_FAILURE);
}
}
void Kh_periodicity_checker::compute_quot(const std::vector<polynomial>& lee_ss_polynomials) {
// quot.push_back(polynomial(Z(0)));
for(unsigned i = 1; i < lee_ss_polynomials.size(); ++i) {
polynomial diff = lee_ss_polynomials[i-1] - lee_ss_polynomials[i];
polynomial q = 0;
// std::cerr << "diff = " << diff << "\n";
// std::cerr << "mul = " << mul[i-1] << "\n";
while(diff != 0) {
pair<monomial, Z> m = diff.head();
if(m.first.m[1] == 1) {
@ -160,9 +232,6 @@ void Kh_periodicity_checker::compute_quot(const std::vector<polynomial>& lee_ss_
}
quot.push_back(q);
}
// for(unsigned i = 0; i < quot.size(); ++i) {
// std::cerr << "quot[" << i << "] = " << quot[i] << "\n";
// }
}
polynomial_tuple
@ -222,13 +291,9 @@ Kh_periodicity_checker::compute_bounds(const polynomial_tuple& p_tuple, int peri
mon *= monomial(VARIABLE, j.key(), v);
}
}
// std::cerr << polynomial(i.val() * pow(-1,exp), mon) << "\n";
Z v_temp = i.val() * pow(-1, exp);
polynomial p_temp = (polynomial(1, mon) * mul).evaluate(-1, ev_index);
p_temp = pcc.reduce(p_temp - invert_variable(p_temp, index));
// std::cerr << "p_temp = " << p_temp << "\n";
// std::cerr << "v_temp = " << v_temp << "\n";
// std::cerr << "min_exp = " << min_exp << "\n";
if(bounds_v.count(p_temp)) {
if(v_temp >= 0)
bounds_v[p_temp].second += (v_temp * period);
@ -259,7 +324,8 @@ Kh_periodicity_checker::compute_bounds(const polynomial_tuple& p_tuple, int peri
return bounds_v;
}
Test_Result Kh_periodicity_checker::check(const polynomial_tuple& polynomials,
Kh_periodicity_checker::Test_Result
Kh_periodicity_checker::check(const polynomial_tuple& polynomials,
int period) const {
periodic_congruence_checker<Z> pcc(period);
polynomial t = polynomial(COPY, leep);
@ -299,8 +365,23 @@ Test_Result Kh_periodicity_checker::check(const polynomial_tuple& polynomials,
std::string Kh_periodicity_checker::operator () (int period) const {
std::ostringstream out;
if(field == "Z5" && Zp<5>(period) == Zp<5>(0))
return "Period (" + std::to_string(period)
+ ") has to be relatively prime to "
+ "the characteristic of the field ("
+ field + ")...";
else if(field == "Z7" && Zp<7>(period) == Zp<7>(0))
return "Period (" + std::to_string(period)
+ ") has to be relatively prime to "
+ "the characteristic of the field ("
+ field + ")...";
else if(field == "Z11" && Zp<11>(period) == Zp<11>(0))
return "Period (" + std::to_string(period)
+ ") has to be relatively prime to "
+ "the characteristic of the field ("
+ field + ")...";
// first check Przytycki's criterion
Przytycki_periodicity_checker P_pc(evaluate_with_copy<Z>(khp, -1, ev_index));
Przytycki_periodicity_checker P_pc(evaluate_with_copy<Z>(khp, -1, ev_index), knot_name);
if(!P_pc.check(period)) {
out << knot_name << ": period = " << period << ": No (Przytycki's criterion).";
}
@ -309,7 +390,42 @@ std::string Kh_periodicity_checker::operator () (int period) const {
Test_Result res = check(q_r, period);
out << knot_name << ": period = " << period << ": "
<< (res == Test_Result::MAYBE ? "Maybe" :
(res == Test_Result::NO ? "No" : "No (Nontrivial decomposition)."));
(res == Test_Result::NO ? "No" : "No (Nontrivial decomposition) ("
+ field + ")"));
}
return out.str();
}
void check_periodicity(knot_diagram& kd, const std::string knot_name, int period, std::string field) {
if(periodicity_test == "all") {
Kh_periodicity_checker Kh_pc(kd, knot_name, field);
for(auto& p : primes_list) {
std::cout << "Kh criterion: "
<< Kh_pc(p) << std::endl;
}
}
else {
if(period == 2 || period == 3) {
std::cout << "Sorry, the criterion doesn't work for period "
<< period << "...\n";
exit(EXIT_FAILURE);
}
auto result = std::find(primes_list.begin(), primes_list.end(), period);
if(result == primes_list.end()) {
std::cout << "For now you can only check periodicity for primes up to 19..." << "\n";
exit(EXIT_FAILURE);
}
if(periodicity_test == "Przytycki") {
Przytycki_periodicity_checker P_pc(compute_jones(kd), knot_name);
std::cout << P_pc(period) << std::endl;
}
else if(periodicity_test == "Kh") {
Kh_periodicity_checker Kh_pc(kd, std::string(knot_name), field);
std::cout << Kh_pc(period) << std::endl;
}
else {
std::cout << "Sorry, I don't recognize this option..." << "\n";
exit(EXIT_FAILURE);
}
}
}

View File

@ -9,16 +9,11 @@
#include <tuple>
extern bool verbose;
extern const char* knot;
extern std::string periodicity_test;
constexpr std::array<int, 6> primes_list = {5, 7, 11, 13, 17, 19};
const std::vector<int> primes_list = {5, 7, 11, 13, 17, 19};
enum class Test_Result { MAYBE, NO, NO_NONTRIVIAL_DECOMP };
const unsigned eval_index = 1;
const unsigned invert_index = 2;
constexpr unsigned eval_index = 1;
constexpr unsigned invert_index = 2;
template<class T>
class periodic_congruence_checker {
@ -35,9 +30,9 @@ protected:
}
public:
periodic_congruence_checker(int pprime = 5,
periodic_congruence_checker(int p = 5,
unsigned ind = invert_index) :
prime(pprime),
prime(p),
index(ind)
{}
@ -47,7 +42,6 @@ public:
bool operator() (const polynomial& pol) const {
return reduce(prepare_polynomial(pol)) == 0;
// return reduce(prepare_polynomial(pol)) == 0;
}
};
@ -62,8 +56,6 @@ periodic_congruence_checker<T>::reduce(const multivariate_laurentpoly<T>& pol) c
monomial mon = monomial(VARIABLE, index, c);
res += polynomial(i.val(), mon);
}
// if(verbose)
// std::cout << "res = " << res << "\n";
return res;
}
@ -72,9 +64,11 @@ class Przytycki_periodicity_checker {
using monomial = multivariate_laurent_monomial;
polynomial jones_pol;
std::string knot_name;
public:
Przytycki_periodicity_checker(polynomial j) : jones_pol(j) {}
Przytycki_periodicity_checker(polynomial j, std::string knot_n) :
jones_pol(j), knot_name(knot_n) {}
~Przytycki_periodicity_checker() {}
@ -117,11 +111,15 @@ class Kh_periodicity_checker {
unsigned ev_index;
unsigned index;
enum class Test_Result { MAYBE, NO, NO_NONTRIVIAL_DECOMP };
polynomial khp, leep;
std::vector<polynomial> quot, mul, quotients, remainders;
std::string knot_name;
std::string field;
template<typename R>
std::vector<polynomial> compute_knot_polynomials(knot_diagram& kd);
void compute_quot(const std::vector<polynomial>& lee_ss_polynomials);
polynomial_tuple
@ -131,14 +129,7 @@ class Kh_periodicity_checker {
Test_Result check(const polynomial_tuple& polynomials, int period) const;
public:
Kh_periodicity_checker(knot_diagram& kd, std::string knot_n) :
knot_name(knot_n) {
ev_index = 1;
index = 2;
quot = std::vector<polynomial>();
mul = std::vector<polynomial>();
compute_quot(compute_knot_polynomials(kd));
}
Kh_periodicity_checker(knot_diagram& kd, std::string knot_n, std::string f);
~Kh_periodicity_checker() {}
@ -153,4 +144,7 @@ class Kh_periodicity_checker {
}
};
void check_periodicity(knot_diagram& kd, const std::string knot_name,
int period = 5, const std::string field = "Z2");
#endif // _KNOTKIT_PERIODICITY_H

View File

@ -1,4 +1,3 @@
class smoothing : public refcounted
{
public: