ASSIGN = 'assign'
class VarInfo(object):
class GoalInfo(object):
class BPCompiler(object):
  def __init__(self,v):
  def __repr__(self):
  def __init__(self,j):
  def __str__(self):
    def _ss(s): return "<" + ",".join(map(str,s)) + ">"
  def __repr__(self):
  def __init__(self,lhsMode,tensorlogProg,depth,rule):
  def getFunction(self):
  def showVars(self):
      def _gs(j):
  def showRule(self):
    def goalStr(j): return str(self.goalDict[j])
  def showOps(self):
  def inferredTypes(self):
  def compile(self):
  def reorderRHS(self,rule,lhsMode):
    def readyToExecute(goal):
    def varsIn(goal):
  def validateRuleBeforeAnalysis(self):
  def inferFlow(self):
  def inferTypes(self):
    def informativeType(t): return (t is not None) and (t != matrixdb.THING)
  def compileDefinedPredicates(self):
  def toMode(self,j):
    def argIOMode(x):
  def collectInputTypes(self,j):
  def generateOps(self):
    def addOp(op,traceDepth,msgFrom,msgTo):
      def jToGoal(msg): return str(self.goals[msg]) if type(msg)==type(0) else msg
    def makeMessageName(stem,v,j=None,j2=None):
    def msgGoal2Var(j,v,traceDepth):
        def hasOutputVarUsedElsewhere(gin):
    def msgVar2Goal(v,j,traceDepth):
def _only(c): class Config(object):
class ConfigHelp(object):
    def __init__(self):
    def pprint(self,depth=0):
    def _explain(self,depth,key,val): def parseCommandLine(argv,extraArgConsumer=None,extraArgSpec=[],extraArgUsage=[]):
    def usage():
    def status(msg): logging.info('%s time %.3f sec mem %.3f Gb' % (msg,time.time()-startTime,util.memusage()))
def isUncachefromSrc(s): return s.find("|")>=0
def getCacheSrcPair(s): return s.split("|")
def makeCacheSrcPair(s1,s2): return "%s|%s" % (s1,s2)
def parseDatasetSpec(spec,db):
def parseDBSpec(spec):
def parseProgSpec(spec,db,proppr=False): def asMode(spec):
    def __init__(self,goal):
    def args(self):
    def arg(self,i):
    def getArity(self):
    def getFunctor(self):
    def __str__(self):
    def __repr__(self):
    def __hash__(self):
    def __eq__(self,other):
    def __init__(self,goal,strict=True):
    def isInput(self,i):
    def isOutput(self,i):
    def isConst(self,i):
    def __str__(self):
    def __init__(self,goal):
    def getType(self,i):
    def typeSet(self):
class AbstractDeclaration(object):
class ModeDeclaration(AbstractDeclaration):
class TypeDeclaration(AbstractDeclaration): class Function(object):
class OpSeqFunction(Function):
class NullFunction(Function):
class LogFunction(Function):
class SumFunction(Function):
class SoftmaxFunction(Function):
    def __init__(self):
    def eval(self,db,values,pad):
    def backprop(self,delta,gradAccum,pad):
    def _checkDuplications(self):
    def install(self,nextId=1):
    def copy(self):
    def pprint(self,depth=0):
    def pprintSummary(self):
    def pprintComment(self):
    def children(self):
    def __init__(self,opInputs,opOutput,ops,rule=None,inputTypes=None,outputType=None):
    def __repr__(self):
    def pprintSummary(self):
    def pprintComment(self):
    def _doEval(self,db,values,pad):
    def _doBackprop(self,delta,gradAccum,pad):
    def children(self):
    def copy(self):
    def __init__(self,lhsMode):
    def __repr__(self):
    def pprintSummary(self):
    def _doEval(self,db,values,pad):
    def _doBackprop(self,delta,gradAccum,pad):
    def children(self):
    def copy(self):
    def __init__(self,fun):
    def __repr__(self):
    def pprintSummary(self):
    def _doEval(self,db,values,pad):
    def _doBackprop(self,delta,gradAccum,pad):
    def children(self):
    def copy(self):
    def __init__(self,funs):
    def __repr__(self):
    def pprintSummary(self):
    def _doEval(self,db,values,pad):
    def _doBackprop(self,delta,gradAccum,pad):
    def children(self):
    def copy(self):
    def __init__(self,fun):
    def __repr__(self):
    def pprintSummary(self):
    def _doEval(self,db,values,pad):
    def _doBackprop(self,delta,pad):
    def children(self):
    def copy(self): NULL_ENTITY_NAME = dbschema.NULL_ENTITY_NAME
THING = dbschema.THING
OOV_ENTITY_NAME = dbschema.OOV_ENTITY_NAME
TRAINABLE_DECLARATION_FUNCTOR = 'trainable'
class MatrixDB(object):
  def __init__(self,initSchema=None):
  def checkTyping(self):
  def isTypeless(self):
  def _fillDefault(self,typeName):
  def dim(self,typeName=None):
  def onehot(self,s,typeName=None,outOfVocabularySymbolsAllowed=False):
  def zeros(self,numRows=1,typeName=None):
  def ones(self,typeName=None):
  def nullMatrix(self,numRows=1,typeName=None,numCols=0):
  def transposeNeeded(mode,transpose=False):
  def matrix(self,mode,transpose=False):
  def vector(self,mode):
  def matrixPreimage(self,mode):
  def matrixPreimageMat(self,mode):
  def matrixPreimageOnesType(self,mode):
  def matrixPreimageOnes(self,mode):
  def isParameter(self,mode):
  def markAsParam(self,functor,arity):
  def markAsParameter(self,functor,arity):
  def clearParameterMarkings(self):
  def getParameter(self,functor,arity):
  def parameterIsInitialized(self,functor,arity):
  def setParameter(self,functor,arity,replacement):
  def asSymbol(self,symbolId,typeName=None):
  def asSymbolId(self,symbol,typeName=None):
  def rowAsSymbolDict(self,row,typeName=None):
  def arrayAsSymbolDict(self,arr,typeName=None):
  def matrixAsSymbolDict(self,m,typeName=None):
  def matrixAsPredicateFacts(self,functor,arity,m):
  def inDB(self,functor,arity):
  def summary(self,functor,arity):
  def listing(self):
  def numMatrices(self):
  def size(self):
  def parameterSize(self):
  def createPartner(self):
  def serialize(self,direc):
  def serializeDataTo(self,fileLike,filter=None):
  def importSerializedDataFrom(self,fileLike):
  def deserializeDataFrom(fileLike):
  def _saveMatDictWithScipy(fileLike,d):
  def _restoreMatDictWithScipy(fileLike):
  def deserialize(direc):
  def uncache(dbFile,factFile,initSchema=None):
  def addLines(self,lines):
  def loadFile(filenames,initSchema=None):
  def startBuffers(self):
  def bufferFile(self,filename):
  def flushBuffers(self):
  def _flushBuffer(self,functor,arity):
  def _bufferTriplet(self,functor,arity,a1,a2,w,filename,k):
  def _bufferLine(self,line,filename,k):
    def _atof(s): 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): 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): def isProcessedConstant(a):
def isProcessedVariable(a):
def isVariableAtom(a):
    def __init__(self,functor,args):
    def _setArgs(self,args):
    def __str__(self):
    def __repr__(self):
    def __init__(self,lhs,rhs,features=None,findall=None):
    def variabilize(self):
            def convertArgs(args):
            def convertGoal(g):
    def __str__(self):
    def asString(self,syntax=None):
    def __init__(self,syntax=None):
    def _key(self,g):
    def add(self,r):
    def size(self):
    def rulesFor(self,g):
    def mapRules(self,mapfun):
    def listing(self):
    def __iter__(self):
    def equals(self,other):
  def __init__(self,syntax=None):
  def setSyntax(self,syntax):
  def _convertGoal(self,ptree):
  def _convertRule(self,ptree):
  def parseGoal(self,s):
  def parseGoalList(self,s):
  def parseRule(self,s):
  def parseQuery(self,s):
  def parseFile(self,filename,rules=None):
  def parseStream(self,fileLike,rules=None):
class Goal(object):
class Rule(object):
class RuleCollection(object):
class Parser(object): def memusage():
def linesIn(fileLike):
import sys
import logging
import collections
import numpy as np
import os
from tensorlog import bpcompiler
from tensorlog import config
from tensorlog import comline
from tensorlog import declare
from tensorlog import funs
from tensorlog import matrixdb
from tensorlog import mutil
from tensorlog import opfunutil
from tensorlog import parser
from tensorlog import util
#

class ProPPRProgram(Program):

    def __init__(self, db=None, rules=parser.RuleCollection(), weights=None, plugins=None):
        super(ProPPRProgram,self).__init__(db=db, rules=rules, plugins=plugins, calledFromProPPRProgram=True)
        # dictionary mapping parameter name to list of modes that can
        # be used to determine possible non-zero values for the
        # parameters
        self.paramDomains = collections.defaultdict(list)
        # list of constants used as rule features
        self.ruleIds = []
        #expand the syntactic sugar used by ProPPR
        self.rules.mapRules(self._moveFeaturesToRHS)
        # set weights if they are given
        if weights!=None: self.setRuleWeights(weights)

    def setRuleWeights(self,weights=None,epsilon=1.0,ruleIdPred=None):
        """Set the db predicate 'weighted/1' as a parameter, and initialize it
        to the given vector.  If no vector 'weights' is given, default
        to a constant vector of epsilon for each rule.  'weighted/1'
        is the default parameter used to weight rule-ids features,
        e.g., "r" in p(X,Y):-... {r}.  You can also specify the
        ruleIds with the name of a unary db relation that holds all
        the rule ids.
        """
        if len(self.ruleIds)==0:
            pass
        elif ruleIdPred is not None:
            # TODO check this stuff and add type inference!
            assert (ruleIdPred,1) in self.db.matEncoding,'there is no unary predicate called %s' % ruleIdPred
            self.db.markAsParameter("weighted",1)
            self.db.setParameter("weighted",1,self.db.vector(declare.asMode('%s(o)' % ruleIdPred)) * epsilon)
        else:
            assert self.db.isTypeless(), 'cannot setRuleWeights for db with declared types unless ruleIdPred is given'
            self.db.markAsParameter("weighted",1)
            if weights==None:
                weights = self.db.onehot(self.ruleIds[0])
                for rid in self.ruleIds[1:]:
                    weights = weights + self.db.onehot(rid)
                weights = mutil.mapData(lambda d:np.clip(d,0.0,1.0), weights)
            self.db.setParameter("weighted",1,weights*epsilon)

    def getRuleWeights(self):
        """ Return a vector of the weights for a rule """
        return self.db.matEncoding[('weighted',1)]

    def setFeatureWeights(self,epsilon=1.0):
        def possibleModes(rule):
            # cycle through all possible modes
            f = rule.lhs.functor
            a = rule.lhs.arity
            for k in range(a):
                io = ['i']*a
                io[k] = 'o'
                yield declare.asMode("%s/%s" % (f,"".join(io)))
        if self.db.isTypeless():
            self._setFeatureWeightsForTypelessDB(epsilon=epsilon)
        else:
            inferredParamType = {}
            # don't assume types for weights have been declared
            for rule in self.rules:
              for m in possibleModes(rule):
                varTypes = bpcompiler.BPCompiler(m,self,0,rule).inferredTypes()
                for goal in rule.rhs:
                  if goal.arity==1 and (goal.functor,goal.arity) in self.db.paramSet:
                    newType = varTypes.get(goal.args[0])
                    decl = declare.TypeDeclaration(parser.Goal(goal.functor,[newType]))
                    self.db.schema.declarePredicateTypes(decl.functor,decl.args())
            for (functor,arity) in self.db.paramList:
                if arity==1:
                    typename = self.db.schema.getArgType(functor,arity,0)
                    self.db.setParameter(functor,arity,self.db.ones(typename)*epsilon)
                else:
                    logging.warn('cannot set weights of matrix parameter %s/%d automatically',functor,arity)


    def _setFeatureWeightsForTypelessDB(self,epsilon=1.0):
        """Initialize each feature used in the feature part of a rule, i.e.,
        for all rules annotated by "{foo(F):...}", declare 'foo/1' to
        be a parameter, and initialize it to something plausible.  The
        'something plausible' is based on looking at how the variables
        defining foo are defined, eg for something like "p(X,Y):-
        ... {posWeight(F):hasWord(X,F)}" a constant sparse vector with
        non-zero weights for all second arguments of hasWord will be
        used to initialize posWeight.  The constant will be epsilon.
        """
        for paramName,domainModes in list(self.paramDomains.items()):
            # we also need to infer a type for the parameter....
            def typeOfWeights(mode):
                for i in range(mode.arity):
                    if mode.isInput(i):
                        return self.db.schema.getArgType(mode.functor,mode.arity,i)
                assert False
            weights = self.db.matrixPreimage(domainModes[0])
            weightType = typeOfWeights(domainModes[0])
            for mode in domainModes[1:]:
                weights = weights + self.db.matrixPreimage(mode)
                assert typeOfWeights(mode)==weightType, 'feature weights have incompatible types: derived from %s and %s' % (mode,domainModes[0])
            weights = weights * 1.0/len(domainModes)
            weights = mutil.mapData(lambda d:np.clip(d,0.0,1.0), weights)
            self.db.setParameter(paramName,1,weights*epsilon)
        for (paramName,arity) in self.getParamList():
            if not self.db.parameterIsInitialized(paramName,arity):
                logging.warn("Parameter %s could not be set automatically")
        logging.debug('total parameter size: %d', self.db.parameterSize())

    def setFeatureWeight(self,paramName,arity,weight):
        """ Set a particular parameter weight. """
        self.db.markAsParameter(paramName,arity)
        self.db.setParameter(paramName,arity,weight)

    def _moveFeaturesToRHS(self,rule0):
        rule = parser.Rule(rule0.lhs, rule0.rhs)
        if not rule0.findall and (rule0.features is not None):
            #parsed format is {f1,f2,...} but we only support {f1}
            assert len(rule0.features)==1,'multiple constant features not supported'
            assert rule0.features[0].arity==0, '{foo(A,...)} not allowed, use {foo(A,...):true}'
            constFeature = rule0.features[0].functor
            constAsVar = constFeature.upper()

            rule.rhs.append( parser.Goal(bpcompiler.ASSIGN, [constAsVar,constFeature]) )