import math, cmath;
import operator as op;
import functools as ft;
import itertools as it;

#------------------------------------------------------------------------------#

def flatten(listOfLists):
   return ft.reduce(op.concat,listOfLists);

def flatten1(listOfLists):
   return it.chain.from_iterable(listOfLists);
       # ok but raises AssertionError, see below
       # <itertools.chain object at 0x00000000031BDF28>

# For testing purposest only (from Python 3.4.2 documentation)
#
def tReduce(function, iterable, initializer=None):
   it = iter(iterable);
   if initializer is None:
       value = next(it);
   else:
       value = initializer;
   for element in it:
       value = function(value, element);
       print(element,' # ',value,'\n'); ### ra
   return value;
# end def

#------------------------------------------------------------------------------#

def sortList(cList):
   tupleList=[(round(z.real,6),round(z.imag,6))
                  for z in cList];
   sortedList=sorted(tupleList,key=lambda t : t[0]);
   sortedList=sorted(sortedList,key=lambda t : t[1]);
   
   return [complex(re,im) for (re,im) in sortedList];
# end def

#------------------------------------------------------------------------------#

def cRoot(z,n):
       # Pre: n!=0
   rn=pow(z,1/n);
   cn=2*math.pi/n;
   
   return [rn*cmath.rect(1,cn*k)
               for k in range(n)];
# end def

cRoot2=ft.partial(cRoot,n=2);
cRoot3=ft.partial(cRoot,n=3);
cRoot4=ft.partial(cRoot,n=4);
cRoot6=ft.partial(cRoot,n=6);
cRoot8=ft.partial(cRoot,n=8);

#------------------------------------------------------------------------------#

rows=list(map(int,list('123456789')));
cols=list(map(int,list('123456789')));

def getSudokuCells():
   return (mBind(rows, lambda row:
               mBind(cols, lambda col:
                   mUnit((row,col))
           )));
# end def
   
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#

def mBind(vList,f):
   assert isinstance(vList,list);
   return flatten(map(f,vList));

def mUnit(x):
   return [x];

#------------------------------------------------------------------------------#

def foldWithBind(x,fList):
   assert isinstance(fList,list);
   return ft.reduce(mBind,fList,mUnit(x));

#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#

if __name__ == '__main__':
   
   print('\n# Beginning...');
#------------------------------------------------------------------------------#

   if False:
       x=-1;
       y=cRoot(x,2); print(sortList(y));
       y=cRoot(x,4); print(sortList(y));
       y=cRoot2(x);  print(sortList(y));
       y=cRoot3(x);  print(sortList(y));
       y=cRoot6(x);  print(sortList(y));
   # end if

#------------------------------------------------------------------------------#

   x=-1;
   y1=sortList(mBind(mBind(mUnit(x),cRoot2),cRoot3));
   #
   y2=sortList(cRoot6(x));
   assert y1==y2;
   if False:
       print(' ',y1,'\n ',y2);

#------------------------------------------------------------------------------#

   x=-1;
   y1=mUnit(x);
   y1=mBind(y1,cRoot2);
   y1=mBind(y1,cRoot3);
   #
   y1=sortList(y1);
   y2=sortList(cRoot6(x));
   assert y1==y2;
   if False:
       print(' ',y1,'\n ',y2)

#------------------------------------------------------------------------------#

   x=-1;
   y1=mBind(mBind(mBind(mUnit(x),cRoot2),cRoot2),cRoot2);
   #
   y1=sortList(y1);
   y2=sortList(cRoot8(x));
   assert y1==y2;
   if False:
       print(' ',y1,'\n\n ',y2);

#------------------------------------------------------------------------------#

   x=-1; n=3;
   y1=mUnit(x);
   for ix in range(3):
       y1=mBind(y1,cRoot2);
   #
   y1=sortList(y1);
   y2=sortList(cRoot8(x));
   assert y1==y2;
   if False:
       print(' ',y1,'\n\n ',y2);

#------------------------------------------------------------------------------#

   x=-1;
   fList=[cRoot2,cRoot3];
   y1=foldWithBind(x,fList);
   #
   y1=sortList(y1);
   y2=sortList(cRoot6(x));
   assert y1==y2;
   if False:
       print(' ',y1,'\n\n ',y2);

#------------------------------------------------------------------------------#

   x=-1;
   fList=[cRoot2,cRoot2,cRoot2];
   y1=foldWithBind(x,fList);
   #
   y1=sortList(y1);
   y2=sortList(cRoot8(x));
   assert y1==y2;
   if False:
       print(' ',y1,'\n\n ',y2);

#------------------------------------------------------------------------------#

   sudokuCells1=getSudokuCells();
   #
   Range9=range(1,10);
   sudokuCells2=[(i,k) for i in Range9
                       for k in Range9];
   assert sudokuCells1==sudokuCells2;

# Beginning...
# [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9), (7, 1), (7, 2), (7, 3), (7, 4), (7, 5), (7, 6), (7, 7), (7, 8), (7, 9), (8, 1), (8, 2), (8, 3), (8, 4), (8, 5), (8, 6), (8, 7), (8, 8), (8, 9), (9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6), (9, 7), (9, 8), (9, 9)]
# Finished

#------------------------------------------------------------------------------#

   # Not shown: Left identity, Right identity, Associativity

#------------------------------------------------------------------------------#
   print('\n# Finished\n');
# end if main

#------------------------------------------------------------------------------#