# Path: tensorlog/opfunutil.py
# class OperatorOrFunction(object):
# class MutableObject(object):
# class Scratchpad(object):
# class Envir(object):
#     def pprint(self,depth=0):
#     def pprintSummary(self):
#     def pprintComment(self):
#     def install(self,nextId=1):
#     def children(self):
#     def __init__(self):
#     def __getitem__(self,key):
#     def __setitem__(self,key,val):
#     def __init__(self,db):
#     def bindList(self,vars,vals):
#     def __repr__(self):
#     def __getitem__(self,key):
#     def __setitem__(self,key,val):
# 
# Path: tensorlog/mutil.py
# NONETYPE=type(None) 
#         D = SS.csr_matrix((mat.data,mat.indices-loIndex,mat.indptr),shape=newShape,dtype='float32').todense()
#     D1 = SS.csr_matrix((m1.data,m1.indices-loIndex,m1.indptr),shape=newShape1,dtype='float32').todense()
#     D2 = SS.csr_matrix((m2.data,m2.indices-loIndex,m2.indptr),shape=newShape2,dtype='float32').todense()
# def summary(mat):
# def pprintSummary(mat):
# def checkCSR(mat,context='unknown'):
# def checkNoNANs(mat,context='unknown'):
# def maxValue(mat):
# def densify(mat,maxExpandFactor=-1,maxExpandIntercept=-1):
# def denseSize(m,loIndex,hiIndex):
# def sparseSize(m,loIndex,hiIndex):
# def codensify(m1,m2,maxExpandFactor=-1,maxExpandIntercept=-1):
# def undensify(denseMat, info):
# def mean(mat):
# def rowsum(mat):
# def mapData(dataFun,mat):
# def stack(mats):
# def numRows(m):
# def numCols(m):
# def nzCols(m,i):
# def repeat(row,n):
# def alterMatrixRows(mat,alterationFun):
# def softmax(db,mat):
#         def softMaxAlteration(data,lo,hi,unused):
# def denseSoftmax(m):
# def broadcastAndComponentwiseMultiply(m1,m2):
# def multiplyByBroadcastRowVec(m,v):
# def broadcastAndWeightByRowSum(m1,m2):
# def shuffleRows(m,shuffledRowNums=None):
# def selectRows(m,lo,hi):
# 
# Path: tensorlog/config.py
# class Config(object):
# class ConfigHelp(object):
#     def __init__(self):
#     def pprint(self,depth=0):
#     def _explain(self,depth,key,val):


import logging
import scipy.sparse
import copy
from tensorlog import opfunutil
from tensorlog import mutil
from tensorlog import config
  """Implements dst = vec * weighter.sum(), where dst and vec are row
  vectors.
  """
  def __init__(self,dst,weighter,vec):
    super(WeightedVec,self).__init__(dst)
    self.weighter = weighter
    self.vec = vec
    #self.src = "[%s,%s]" % (weighter,vec)  #TODO: remove?
  def __repr__(self):
    return "WeightedVec(%s,%s.sum(),%s)" % (self.dst,self.weighter,self.vec)
  def _ppLHS(self):
    return "%s * %s.sum()" % (self.vec,self.weighter)
  def _doEval(self,env,pad):
    env[self.dst] = mutil.broadcastAndWeightByRowSum(env[self.vec],env[self.weighter])
  def _doBackprop(self,env,gradAccum,pad):
    # This is written as a single operation
    #  dst = vec * weighter.sum()
    # but we will break into two steps conceptually
    #   1. weighterSum = weighter.sum()
    #   2. dst = vec * weighterSum
    # and then backprop through step 2, then step 1
    # step 2a: bp from delta[dst] to delta[vec]
    #   delta[vec] = delta[dst]*weighterSum
    env.delta[self.vec] = mutil.broadcastAndWeightByRowSum(env.delta[self.dst],env[self.weighter]) 
    # step 2b: bp from delta[dst] to delta[weighterSum]
    #   would be: delta[weighterSum] = (delta[dst].multiply(vec)).sum
    # followed by
    # step 1: bp from delta[weighterSum] to weighter
    #   delta[weighter] = delta[weighterSum]*weighter
    # but we can combine 2b and 1 as follows (optimized):

# Path: tensorlog/opfunutil.py
# class OperatorOrFunction(object):
# class MutableObject(object):
# class Scratchpad(object):
# class Envir(object):
#     def pprint(self,depth=0):
#     def pprintSummary(self):
#     def pprintComment(self):
#     def install(self,nextId=1):
#     def children(self):
#     def __init__(self):
#     def __getitem__(self,key):
#     def __setitem__(self,key,val):
#     def __init__(self,db):
#     def bindList(self,vars,vals):
#     def __repr__(self):
#     def __getitem__(self,key):
#     def __setitem__(self,key,val):
# 
# Path: tensorlog/mutil.py
# NONETYPE=type(None) 
#         D = SS.csr_matrix((mat.data,mat.indices-loIndex,mat.indptr),shape=newShape,dtype='float32').todense()
#     D1 = SS.csr_matrix((m1.data,m1.indices-loIndex,m1.indptr),shape=newShape1,dtype='float32').todense()
#     D2 = SS.csr_matrix((m2.data,m2.indices-loIndex,m2.indptr),shape=newShape2,dtype='float32').todense()
# def summary(mat):
# def pprintSummary(mat):
# def checkCSR(mat,context='unknown'):
# def checkNoNANs(mat,context='unknown'):
# def maxValue(mat):
# def densify(mat,maxExpandFactor=-1,maxExpandIntercept=-1):
# def denseSize(m,loIndex,hiIndex):
# def sparseSize(m,loIndex,hiIndex):
# def codensify(m1,m2,maxExpandFactor=-1,maxExpandIntercept=-1):
# def undensify(denseMat, info):
# def mean(mat):
# def rowsum(mat):
# def mapData(dataFun,mat):
# def stack(mats):
# def numRows(m):
# def numCols(m):
# def nzCols(m,i):
# def repeat(row,n):
# def alterMatrixRows(mat,alterationFun):
# def softmax(db,mat):
#         def softMaxAlteration(data,lo,hi,unused):
# def denseSoftmax(m):
# def broadcastAndComponentwiseMultiply(m1,m2):
# def multiplyByBroadcastRowVec(m,v):
# def broadcastAndWeightByRowSum(m1,m2):
# def shuffleRows(m,shuffledRowNums=None):
# def selectRows(m,lo,hi):
# 
# Path: tensorlog/config.py
# class Config(object):
# class ConfigHelp(object):
#     def __init__(self):
#     def pprint(self,depth=0):
#     def _explain(self,depth,key,val):


# Path: tensorlog/ops.py
import logging
import scipy.sparse
import copy
from tensorlog import opfunutil
from tensorlog import mutil
from tensorlog import config

  """Implements dst = vec * weighter.sum(), where dst and vec are row
  vectors.
  """
  def __init__(self,dst,weighter,vec):
    super(WeightedVec,self).__init__(dst)
    self.weighter = weighter
    self.vec = vec
    #self.src = "[%s,%s]" % (weighter,vec)  #TODO: remove?
  def __repr__(self):
    return "WeightedVec(%s,%s.sum(),%s)" % (self.dst,self.weighter,self.vec)
  def _ppLHS(self):
    return "%s * %s.sum()" % (self.vec,self.weighter)
  def _doEval(self,env,pad):
    env[self.dst] = mutil.broadcastAndWeightByRowSum(env[self.vec],env[self.weighter])
  def _doBackprop(self,env,gradAccum,pad):
    # This is written as a single operation
    #  dst = vec * weighter.sum()
    # but we will break into two steps conceptually
    #   1. weighterSum = weighter.sum()
    #   2. dst = vec * weighterSum
    # and then backprop through step 2, then step 1
    # step 2a: bp from delta[dst] to delta[vec]
    #   delta[vec] = delta[dst]*weighterSum
    env.delta[self.vec] = mutil.broadcastAndWeightByRowSum(env.delta[self.dst],env[self.weighter]) 
    # step 2b: bp from delta[dst] to delta[weighterSum]
    #   would be: delta[weighterSum] = (delta[dst].multiply(vec)).sum
    # followed by
    # step 1: bp from delta[weighterSum] to weighter
    #   delta[weighter] = delta[weighterSum]*weighter
    # but we can combine 2b and 1 as follows (optimized):

    tmp = mutil.broadcastAndComponentwiseMultiply(env.delta[self.dst],env[self.vec])