 you load them into variables...
    isTrainable = (key in self.db.paramSet)
    v = self._reparameterizeAndRecordVar(val,name,isTrainable)
    self._handleExprVar[key] = v
    self._handleExpr[key] = self._reparameterizedVarExpr(v,isTrainable)

  def _reparameterizeAndRecordVar(self,val,name,isTrainable):
    initVal = self._softPlusInverse(val) if (isTrainable and xcomp.conf.reparameterizeMatrices) else val
    v = tf.Variable(initVal, name="tensorlog/"+name, trainable=isTrainable)
    #v = tf.Variable(val, name="tensorlog/"+name, trainable=isTrainable)
    self.summarize(name,v)
    self.tfVarsToInitialize.append(v)
    return v

  def _reparameterizedVarExpr(self,var,isTrainable):
    return tf.nn.softplus(var) if (isTrainable and xcomp.conf.reparameterizeMatrices) else var

  def summarize(self,name,v):
    if self.summaryFile:
      tf.summary.scalar('summaries/%s/size' % name, tf.size(v))

  def _wrapMsg(self,vec):
    """ Convert a vector from the DB into a vector value used by the
    target language """
    return vec.todense()

  def _wrapDBVector(self,vec):
    """ Convert a vector from the DB into a vector value used by the
    target language """
    return vec.todense()

  def _wrapDBMatrix(self,mat):
    """ Convert a matrix from the DB into a vector value used by the
    target language """
    return mat.todense()

  def _unwrapUpdate(self,key,up):
    return self._unwrapOutput(up)

  def _unwrapOutput(self,x):
    """Convert a matrix produced by the target language to the usual
    sparse-vector output of tensorlog"""
    sx = ss.csr_matrix(x)
    sx.eliminate_zeros()
    return sx

  def _unwrapDBVector(self,key,vec):
    return self._unwrapOutput(vec)

  def _unwrapDBMatrix(self,key,mat):
    return self._unwrapOutput(vec)

  def _softmaxFun2Expr(self,subExpr,typeName):
    # zeros are actually big numbers for the softmax,
    # so replace them with a big negative number
    subExprReplacing0WithNeg10 = tf.where(
        subExpr>0.0,
        subExpr,
        tf.ones(tf.shape(subExpr), tf.float32)*(-10.0))
    return tf.nn.softmax(subExprReplacing0WithNeg10 + self._nullSmoother[typeName])

  def _transposeMatrixExpr(self,m):
    return tf.transpose(m)

  def _vecMatMulExpr(self,v,m):
    return tf.matmul(v,m)

  def _componentwiseMulExpr(self,v1,v2):
    return tf.multiply(v1,v2)

  def _weightedVecExpr(self,vec,weighter):
    return tf.multiply(vec, tf.reduce_sum(weighter, axis=1, keep_dims=True))

###############################################################################
# implementation for dense messages, sparse relation matrices
###############################################################################

class SparseMatDenseMsgCrossCompiler(DenseMatDenseMsgCrossCompiler):

  def __init__(self,db,summaryFile=None):
    logging.debug('SparseMatDenseMsgCrossCompiler calling %r %.3f Gb' % (super(SparseMatDenseMsgCrossCompiler,self).__init__,util.memusage()))
    super(SparseMatDenseMsgCrossCompiler,self).__init__(db,summaryFile=summaryFile)
    logging.debug('SparseMatDenseMsgCrossCompiler finished super.__init__ %.3f Gb' % util.memusage())
    # we will need to save the original indices/indptr representation
    # of each sparse matrix
    self.sparseMatInfo = {}
    logging.debug('SparseMatDenseMsgCrossCompiler initialized %.3f Gb' % util.memusage())

  def _insertHandleExpr(self,key,name,val,broadcast=False):
    (functor,arity) = key
    isTrainable = (key in self.db.paramSet)
    if arity<2:
      initVal = self._softPlusInverse(val) if isTrainable else val
      v = self._reparameterizeAndRecordVar(val,name,isTrainable)
      self._handleExprVar[key] = v
      self._handleExpr[key] = self._reparameterizedVarExpr(v,isTrainable)
    else:
      # matrixes are sparse so we need to convert them into
      # a handle expression that stores a SparseTensor, and
      # do some additional bookkeeping.

      # first convert from scipy csr format of indices,indptr,data to
      # tensorflow's format, where the sparseindices are a 2-D tensor.
      sparseIndices = []
      (nRows,nCols) = val.shape
      for i in range(nRows):
        for j in val.indices[val.indptr[i]:val.indptr[i+1]]:
          sparseIndices.append([i,j])
      logging.debug('%d sparseIndices for %d x %d relation %s: sparsity %g' %
                    (len(sparseIndices),nRows,nCols,functor,len(sparseIndices)/float(nRows*nCols)))
      # save the old shape and indices for the scipy matrix so we can
      # reconstruct a scipy matrix in unwrapUpdate.
      self.sparseMatInfo[key] = (val.indices,val.indptr,val.shape)
      # create the handle expression, and save a link back to the
      # underlying varable which will be optimized, ie., the 'values'
      # of the SparseTensor,
      indiceVar = tf.Variable(np.array(sparseIndices), name="tensorlog/%s_indices" % name)
      valueVar = self._reparameterizeAndRecordVar(val.data,name,isTrainable)
      # note: the "valueVar+0.0" seems to be necessary to get a non-zero
      # gradient, but I don't understand why.  w/o this there is no "read"
      # node in for the variable in the graph and the gradient fails
      self._handleExpr[key] = tf.SparseTensor(indiceVar,self._reparameterizedVarExpr(valueVar,isTrainable)+0.0,[nRows,nCols])
      self._handleExprVar[key] = valueVar
      # record the index variable, which also needs to be initialized
      self.tfVarsToInitialize.append(indiceVar)
      self.summarize("%s_indices" % name,indiceVar)

  def _unwrapDBVector(self,key,vec):
    return ss.csr_matrix(vec)

  def _unwrapDBMatrix(self,key,mat):
    (indices,indptr,shape) = self.sparseMatInfo[key]
    # note mat will be a SparseTensor in this case.....
    return ss.csr_matrix((mat.values,indices,indptr),shape=shape)


  def _unwrapUpdate(self,key,up):
    # we will optimize by updating the _handleExprVar's, which are,
    # for a SparseTensor, the value expressions.  to check gradients
    # and such we will need to convert the value updates to tensorlog
    # sparse matrix updates.
    (functor,arity) = key
    if arity==1:
      return ss.csr_matrix(up)
    elif arity==2:
      (indices,indptr,shape) = self.sparseMatInfo[key]
      return ss.csr_matrix((up,indices,indptr),shape=shape)
    else:
      assert False

  #
  # override the dense-matrix operations with sparse ones
  #

  def _wrapDBMatrix(self,mat):
    return mat

  def _transposeMatrixExpr(self,m):
    return tf.sparse_transpose(m)

  def _vecMatM