<commit_before>/* Copyright 2017, <NAME>. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.platanios.tensorflow.api.ops

import org.platanios.tensorflow.api._
import org.platanios.tensorflow.api.core.{Graph, Indexer, Shape}
import org.platanios.tensorflow.api.core.client.{FeedMap, Session}
import org.platanios.tensorflow.api.ops
import org.platanios.tensorflow.api.ops.Basic.BasicOps
import org.platanios.tensorflow.api.ops.Op.{createWith, getGraphFromInputs}
import org.platanios.tensorflow.api.tensors.{SparseTensor, Tensor, TensorIndexedSlices, TensorLike}
import org.platanios.tensorflow.api.tensors.ops.{Basic => TensorBasic, Math => TensorMath}
import org.platanios.tensorflow.api.types.{DataType, INT32, INT64}
import org.platanios.tensorflow.api.utilities.using
import org.platanios.tensorflow.jni.{Op => NativeOp}

/** Trait representing outputs of an [[Op]]'s computation.
  *
  * @author <NAME>
  */
sealed trait OutputLike {
  /** Graph where the op belongs. */
  def graph: Graph

  /** Name of this op output. */
  def name: String

  /** Data type of this op output. */
  def dataType: DataType

  /** Device on which this op output will be placed. */
  def device: String

  /** Op that generates this output. */
  def op: Op

  /** Consumers of this op output (i.e., ops that use this op output as one of their inputs). */
  def consumers: Array[Input]

  /** Returns the [[Output]] that this [[OutputLike]] object represents. */
  def toOutput: Output

  /** Returns an [[OutputIndexedSlices]] that has the same value as this [[OutputLike]].
    *
    * @param  optimize Boolean flag indicating whether to optimize this conversion by using a constant op with the
    *                  shape of this tensor at graph creation time (instead of execution time), if known.
    * @return [[OutputIndexedSlices]] that has the same value as this [[OutputLike]].
    */
  def toOutputIndexedSlices(optimize: Boolean = true): OutputIndexedSlices
}

object OutputLike {
  implicit def outputLikeToOutput[T <: OutputLike](outputLike: T): Output = outputLike.toOutput
}

/** Type trait for defining functions operating on and returning op outputs. */
private[ops] trait OutputOps[T] {
  /** Applies a unary function to the provided output and returns the result.
    *
    * @param  outputLike Output-like object to apply the unary function on.
    * @param  opFunction Unary function to apply.
    * @return Resulting output-like object that matches the type of `outputLike`.
    */
  @inline
  def applyUnary(outputLike: T, opFunction: Output => Output): T
}

/** Companion object that defines supported [[OutputOps]] implicit values. */
private[ops] object OutputOps {
  implicit val outputOps: OutputOps[Output] = new OutputOps[Output] {
    @inline
    override def applyUnary(outputLike: Output, opFunction: (Output) => Output): Output = opFunction(outputLike)
  }

  implicit val outputIndexedSlicesOps: OutputOps[OutputIndexedSlices] = new OutputOps[OutputIndexedSlices] {
    @inline
    override def applyUnary(outputLike: OutputIndexedSlices, opFunction: Output => Output): OutputIndexedSlices = {
      outputLike.copy(values = opFunction(outputLike.values))
    }
  }

  implicit val sparseOutputOps: OutputOps[SparseOutput] = new OutputOps[SparseOutput] {
    @inline
    override def applyUnary(outputLike: SparseOutput, opFunction: Output => Output): SparseOutput = {
      outputLike.copy(values = opFunction(outputLike.values))
    }
  }

  implicit val outputLikeOps: OutputOps[OutputLike] = new OutputOps[OutputLike] {
    @inline
    override def applyUnary(outputLike: OutputLike, opFunction: (Output) => Output): OutputLike = {
      outputLike match {
        case o: Output => opFunction(o)
        case o: OutputIndexedSlices => o.copy(values = opFunction(o.values))
        case o: SparseOutput => o.copy(values = opFunction(o.values))
      }
    }
  }
}

/** Representation of one of the outputs of an [[Op]]'s computation.
  *
  * An `Output` is a symbolic handle to one of the outputs of an [[Op]]. It does not hold the values of that op's
  * output, but instead provides a means of computing those values in a TensorFlow [[Session]].
  *
  * This class has two primary purposes:
  *
  *   1. An [[Output]] can be passed as input to another [[Op]]. This builds a dataflow connection between ops, which
  *      enables TensorFlow to execute an entire [[Graph]] that represents a large, multi-step computation.
  *   2. After the graph has been launched in a [[Session]], the value of an [[Output]] can be computed by passing
  *      it to [[Session.run]].
  *   3. `Output.evaluate` can also be used to compute the value of an [[Output]] If no session is provided,
  * then the default session is used.
  *
  * In the following example, `c`, `d`, and `e` are symbolic [[Output]] objects, whereas `result` is a Scala array
  * that stores a concrete value:
  * {{{
  *   val c = constant(Array(Array(1.0, 2.0), Array(3.0, 4.0)))
  *   val d = constant(Array(Array(1.0, 1.0), Array(0.0, 1.0)))
  *   val e = matmul(c, d)
  *   val result = e.evaluate() // 'result' now holds the result of the matrix multiplication.
  * }}}
  *
  * @param  op    Op whose output this class represents.
  * @param  index Output index.
  *
  * @author <NAME>
  */
final case class Output private(op: Op, index: Int) extends OutputLike {
  /** Graph where the op belongs. */
  override def graph: Graph = op.graph

  /** Name of this op output. This is simply set to `"<op.name>:<index>"`. */
  override def name: String = s"${op.name}:$index"

  /** Data type of this op output. */
  override def dataType: DataType = using(graph.reference) { r =>
    DataType.fromCValue(NativeOp.outputDataType(r.nativeHandle, op.nativeHandle, index))
  }

  /** Device on which this op output will be placed. */
  override def device: String = op.device

  /** Consumers of this op output (i.e., ops that use this op output as one of their inputs). */
  override def consumers: Array[Input] = using(graph.reference) { _ =>
    val array = NativeOp.consumers(op.nativeHandle, index)
    if (array == null) {
      Array.empty[Input]
    } else {
      array.map(jniOutput => {
        val op = graph.opsCache.getOrElseUpdate(jniOutput.opHandle, Op(graph, jniOutput.opHandle))
        Input(op = op, index = index)
      })
    }
  }

  /** Shape of the tensor that this op output represents. */
  def shape: Shape = {
    val s = using(op.graph.reference)(r => NativeOp.shape(r.nativeHandle, op.nativeHandle, index))
    if (s == null) Shape.unknown() else Shape.fromSeq(s.map(_.toInt))
  }

  /** Rank of the tensor that this op output represents. */
  def rank: Int = shape.rank

  /** Size of the tensor that this op output represents. */
  def size: Int = shape.numElements

  /** Sets the shape of this op output to the provided shape.
    *
    * This method can be useful in cases when shape inference fails, but the shape of the op output is known by the
    * user of the library.
    *
    * @param  shape Shape to use.
    */
  def setShape(shape: Shape): Unit = using(op.graph.reference) { r =>
    NativeOp.setShape(r.nativeHandle, op.nativeHandle, index, shape.asArray.map(_.toLong), shape.rank)
  }

  /** Evaluates this op output.
    *
    * If `feeds` is non-empty, then the provided feed values are fed into the session for computing the value of this
    * op output.
    *
    * If `session` is `null` (i.e., not provided), then the default session is used. Otherwise, `session` is used for
    * the evaluation.
    *
    * @param  feeds   Tensors to feed into the session for this evaluation.
    * @param  session Optional session to use for the evaluation.
    * @return Value of this op output, for this evaluation.
    */
  def evaluate(feeds: Map[Output, Tensor] = Map.empty, session: Session = null): Tensor = {
    val effectiveSession = if (session == null) graph.defaultSession else session
    effectiveSession.run(feeds, this)
  }<commit_msg>Minor bug fix for when setting an output's shape to unknown.<commit_after>/* Copyright 2017, <NAME>. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.platanios.tensorflow.api.ops

import org.platanios.tensorflow.api._
import org.platanios.tensorflow.api.core.{Graph, Indexer, Shape}
import org.platanios.tensorflow.api.core.client.{FeedMap, Session}
import org.platanios.tensorflow.api.ops
import org.platanios.tensorflow.api.ops.Basic.BasicOps
import org.platanios.tensorflow.api.ops.Op.{createWith, getGraphFromInputs}
import org.platanios.tensorflow.api.tensors.{SparseTensor, Tensor, TensorIndexedSlices, TensorLike}
import org.platanios.tensorflow.api.tensors.ops.{Basic => TensorBasic, Math => TensorMath}
import org.platanios.tensorflow.api.types.{DataType, INT32, INT64}
import org.platanios.tensorflow.api.utilities.using
import org.platanios.tensorflow.jni.{Op => NativeOp}

/** Trait representing outputs of an [[Op]]'s computation.
  *
  * @author <NAME>
  */
sealed trait OutputLike {
  /** Graph where the op belongs. */
  def graph: Graph

  /** Name of this op output. */
  def name: String

  /** Data type of this op output. */
  def dataType: DataType

  /** Device on which this op output will be placed. */
  def device: String

  /** Op that generates this output. */
  def op: Op

  /** Consumers of this op output (i.e., ops that use this op output as one of their inputs). */
  def consumers: Array[Input]

  /** Returns the [[Output]] that this [[OutputLike]] object represents. */
  def toOutput: Output

  /** Returns an [[OutputIndexedSlices]] that has the same value as this [[OutputLike]].
    *
    * @param  optimize Boolean flag indicating whether to optimize this conversion by using a constant op with the
    *                  shape of this tensor at graph creation time (instead of execution time), if known.
    * @return [[OutputIndexedSlices]] that has the same value as this [[OutputLike]].
    */
  def toOutputIndexedSlices(optimize: Boolean = true): OutputIndexedSlices
}

object OutputLike {
  implicit def outputLikeToOutput[T <: OutputLike](outputLike: T): Output = outputLike.toOutput
}

/** Type trait for defining functions operating on and returning op outputs. */
private[ops] trait OutputOps[T] {
  /** Applies a unary function to the provided output and returns the result.
    *
    * @param  outputLike Output-like object to apply the unary function on.
    * @param  opFunction Unary function to apply.
    * @return Resulting output-like object that matches the type of `outputLike`.
    */
  @inline
  def applyUnary(outputLike: T, opFunction: Output => Output): T
}

/** Companion object that defines supported [[OutputOps]] implicit values. */
private[ops] object OutputOps {
  implicit val outputOps: OutputOps[Output] = new OutputOps[Output] {
    @inline
    override def applyUnary(outputLike: Output, opFunction: (Output) => Output): Output = opFunction(outputLike)
  }

  implicit val outputIndexedSlicesOps: OutputOps[OutputIndexedSlices] = new OutputOps[OutputIndexedSlices] {
    @inline
    override def applyUnary(outputLike: OutputIndexedSlices, opFunction: Output => Output): OutputIndexedSlices = {
      outputLike.copy(values = opFunction(outputLike.values))
    }
  }

  implicit val sparseOutputOps: OutputOps[SparseOutput] = new OutputOps[SparseOutput] {
    @inline
    override def applyUnary(outputLike: SparseOutput, opFunction: Output => Output): SparseOutput = {
      outputLike.copy(values = opFunction(outputLike.values))
    }
  }

  implicit val outputLikeOps: OutputOps[OutputLike] = new OutputOps[OutputLike] {
    @inline
    override def applyUnary(outputLike: OutputLike, opFunction: (Output) => Output): OutputLike = {
      outputLike match {
        case o: Output => opFunction(o)
        case o: OutputIndexedSlices => o.copy(values = opFunction(o.values))
        case o: SparseOutput => o.copy(values = opFunction(o.values))
      }
    }
  }
}

/** Representation of one of the outputs of an [[Op]]'s computation.
  *
  * An `Output` is a symbolic handle to one of the outputs of an [[Op]]. It does not hold the values of that op's
  * output, but instead provides a means of computing those values in a TensorFlow [[Session]].
  *
  * This class has two primary purposes:
  *
  *   1. An [[Output]] can be passed as input to another [[Op]]. This builds a dataflow connection between ops, which
  *      enables TensorFlow to execute an entire [[Graph]] that represents a large, multi-step computation.
  *   2. After the graph has been launched in a [[Session]], the value of an [[Output]] can be computed by passing
  *      it to [[Session.run]].
  *   3. `Output.evaluate` can also be used to compute the value of an [[Output]] If no session is provided,
  * then the default session is used.
  *
  * In the following example, `c`, `d`, and `e` are symbolic [[Output]] objects, whereas `result` is a Scala array
  * that stores a concrete value:
  * {{{
  *   val c = constant(Array(Array(1.0, 2.0), Array(3.0, 4.0)))
  *   val d = constant(Array(Array(1.0, 1.0), Array(0.0, 1.0)))
  *   val e = matmul(c, d)
  *   val result = e.evaluate() // 'result' now holds the result of the matrix multiplication.
  * }}}
  *
  * @param  op    Op whose output this class represents.
  * @param  index Output index.
  *
  * @author <NAME>
  */
final case class Output private(op: Op, index: Int) extends OutputLike {
  /** Graph where the op belongs. */
  override def graph: Graph = op.graph

  /** Name of this op output. This is simply set to `"<op.name>:<index>"`. */
  override def name: String = s"${op.name}:$index"

  /** Data type of this op output. */
  override def dataType: DataType = using(graph.reference) { r =>
    DataType.fromCValue(NativeOp.outputDataType(r.nativeHandle, op.nativeHandle, index))
  }

  /** Device on which this op output will be placed. */
  override def device: String = op.device

  /** Consumers of this op output (i.e., ops that use this op output as one of their inputs). */
  override def consumers: Array[Input] = using(graph.reference) { _ =>
    val array = NativeOp.consumers(op.nativeHandle, index)
    if (array == null) {
      Array.empty[Input]
    } else {
      array.map(jniOutput => {
        val op = graph.opsCache.getOrElseUpdate(jniOutput.opHandle, Op(graph, jniOutput.opHandle))
        Input(op = op, index = index)
      })
    }
  }

  /** Shape of the tensor that this op output represents. */
  def shape: Shape = {
    val s = using(op.graph.reference)(r => NativeOp.shape(r.nativeHandle, op.nativeHandle, index))
    if (s == null) Shape.unknown() else Shape.fromSeq(s.map(_.toInt))
  }

  /** Rank of the tensor that this op output represents. */
  def rank: Int = shape.rank

  /** Size of the tensor that this op output represents. */
  def size: Int = shape.numElements

  /** Sets the shape of this op output to the provided shape.
    *
    * This method can be useful in cases when shape inference fails, but the shape of the op output is known by the
    * user of the library.
    *
    * @param  shape Shape to use.
    */
  def setShape(shape: Shape): Unit = using(op.graph.reference) { r =>
    NativeOp.setShape(
      r.nativeHandle, op.nativeHandle, index, if (shape.rank != -1) shape.asArray.map(_.toLong) else null, shape.rank)
  }

  /** Evaluates this op output.
    *
    * If `feeds` is non-empty, then the provided feed values are fed into the session for computing the value of this
    * op output.
    *
    * If `session` is `null` (i.e., not provided), then the default session is used. Otherwise, `session` is used for
    * the evaluation.
    *
    * @param  feeds   Tensors to feed into the session for this evaluation.
    * @param  session Optional session to use for the evaluation.
    * @return Value of this op output, for this evaluation.
    */
  def evaluate(feeds: Map[Output, Tensor] = Map.empty, session: Session = null): Tensor = {
    val effectiveSession = if (session == null) graph.defaultSession else session
    effectiveSession.run(feeds, this)
  }
{'fraction_non_alphanumeric': 0.10873877027184693, 'fraction_numerical': 0.0036751837591879593, 'mean_word_length': 3.435446313065977, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3749906', 'n_tokens_mistral': 5114, 'n_tokens_neox': 5023, 'n_words': 1872}