<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.learn

import org.platanios.tensorflow.api.core.Graph
import org.platanios.tensorflow.api.learn.layers.{Input, Layer}
import org.platanios.tensorflow.api.ops.{Math, Op, Output}
import org.platanios.tensorflow.api.ops.training.optimizers.Optimizer
import org.platanios.tensorflow.api.ops.io.Iterator
import org.platanios.tensorflow.api.ops.metrics.Metric
import org.platanios.tensorflow.api.types.FLOAT32

/**
  * @author <NAME>
  */
trait Model

trait InferenceModel[IT, IO, ID, IS, I] extends Model {
  def buildInferenceOps(graph: Graph = Op.currentGraph): Model.InferenceOps[IT, IO, ID, IS, I]
}

trait TrainableModel[IT, IO, ID, IS, I, TT, TO, TD, TS, T] extends InferenceModel[IT, IO, ID, IS, I] {
  def buildTrainOps(graph: Graph = Op.currentGraph): Model.SupervisedTrainOps[IT, IO, ID, IS, I, TT, TO, TD, TS, T]
  def buildEvaluationOps(
      graph: Graph = Op.currentGraph, metrics: Seq[Metric[(I, T), Output]]
  ): Model.EvaluationOps[(IT, TT), (IO, TO), (ID, TD), (IS, TS), I]
}

trait UnsupervisedTrainableModel[IT, IO, ID, IS, I] extends InferenceModel[IT, IO, ID, IS, I] {
  def buildTrainOps(graph: Graph = Op.currentGraph): Model.UnsupervisedTrainOps[IT, IO, ID, IS, I]
  def buildEvaluationOps(
      graph: Graph = Op.currentGraph, metrics: Seq[Metric[I, Output]]
  ): Model.EvaluationOps[IT, IO, ID, IS, I]
}

object Model {
  case class InferenceOps[IT, IO, ID, IS, I](inputIterator: Iterator[IT, IO, ID, IS], input: IO, output: I)

  case class UnsupervisedTrainOps[IT, IO, ID, IS, I](
      inputIterator: Iterator[IT, IO, ID, IS],
      input: IO,
      output: I,
      loss: Output,
      trainOp: Op)

  case class SupervisedTrainOps[IT, IO, ID, IS, I, TT, TO, TD, TS, T](
      inputIterator: Iterator[(IT, TT), (IO, TO), (ID, TD), (IS, TS)],
      input: (IO, TO),
      output: I,
      trainOutput: T,
      loss: Output,
      trainOp: Op)

  object SupervisedTrainOps {
    def apply[IT, IO, ID, IS, I](
        inputIterator: Iterator[(IT, IT), (IO, IO), (ID, ID), (IS, IS)],
        input: (IO, IO),
        output: I,
        loss: Output,
        trainOp: Op): SupervisedTrainOps[IT, IO, ID, IS, I, IT, IO, ID, IS, I] = {
      SupervisedTrainOps(inputIterator, input, output, output, loss, trainOp)
    }
  }

  case class EvaluationOps[IT, IO, ID, IS, I](
      inputIterator: Iterator[IT, IO, ID, IS],
      input: IO,
      output: I,
      metricValues: Seq[Output],
      metricUpdates: Seq[Output],
      metricResets: Seq[Op])

  trait API {
    def Model[IT, IO, ID, IS, I, TT, TO, TD, TS, T](
        input: Input[IT, IO, ID, IS],
        layer: Layer[IO, I],
        trainingInput: Input[TT, TO, TD, TS],
        trainingInputLayer: Layer[TO, T],
        loss: Layer[(I, T), Output],
        optimizer: Optimizer): TrainableModel[IT, IO, ID, IS, I, TT, TO, TD, TS, T] = {
      new SimpleTrainableModel(input, layer, trainingInput, trainingInputLayer, loss, optimizer)
    }
  }

  object API extends API
}

private[learn] class SimpleInferenceModel[IT, IO, ID, IS, I] private[learn](
    val input: Input[IT, IO, ID, IS],
    val layer: Layer[IO, I]
) extends InferenceModel[IT, IO, ID, IS, I] {
  def buildInferenceOps(graph: Graph = Op.currentGraph): Model.InferenceOps[IT, IO, ID, IS, I] = {
    Op.createWith(graph) {
      val tfInputIterator = input()
      val tfInput = tfInputIterator.next()
      val tfOutput = layer(tfInput)
      Model.InferenceOps(tfInputIterator, tfInput, tfOutput)
    }
  }
}

private[learn] class SimpleTrainableModel[IT, IO, ID, IS, I, TT, TO, TD, TS, T] private[learn](
    override val input: Input[IT, IO, ID, IS],
    override val layer: Layer[IO, I],
    val trainInput: Input[TT, TO, TD, TS],<commit_msg>Minor addition to the learn API.<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.learn

import org.platanios.tensorflow.api.core.Graph
import org.platanios.tensorflow.api.learn.layers.{Input, Layer}
import org.platanios.tensorflow.api.ops.{Math, Op, Output}
import org.platanios.tensorflow.api.ops.training.optimizers.Optimizer
import org.platanios.tensorflow.api.ops.io.Iterator
import org.platanios.tensorflow.api.ops.metrics.Metric
import org.platanios.tensorflow.api.types.FLOAT32

/**
  * @author <NAME>
  */
trait Model

trait InferenceModel[IT, IO, ID, IS, I] extends Model {
  def buildInferenceOps(graph: Graph = Op.currentGraph): Model.InferenceOps[IT, IO, ID, IS, I]
}

trait TrainableModel[IT, IO, ID, IS, I, TT, TO, TD, TS, T] extends InferenceModel[IT, IO, ID, IS, I] {
  def buildTrainOps(graph: Graph = Op.currentGraph): Model.SupervisedTrainOps[IT, IO, ID, IS, I, TT, TO, TD, TS, T]
  def buildEvaluationOps(
      graph: Graph = Op.currentGraph, metrics: Seq[Metric[(I, T), Output]]
  ): Model.EvaluationOps[(IT, TT), (IO, TO), (ID, TD), (IS, TS), I]
}

trait UnsupervisedTrainableModel[IT, IO, ID, IS, I] extends InferenceModel[IT, IO, ID, IS, I] {
  def buildTrainOps(graph: Graph = Op.currentGraph): Model.UnsupervisedTrainOps[IT, IO, ID, IS, I]
  def buildEvaluationOps(
      graph: Graph = Op.currentGraph, metrics: Seq[Metric[I, Output]]
  ): Model.EvaluationOps[IT, IO, ID, IS, I]
}

object Model {
  case class InferenceOps[IT, IO, ID, IS, I](inputIterator: Iterator[IT, IO, ID, IS], input: IO, output: I)

  case class UnsupervisedTrainOps[IT, IO, ID, IS, I](
      inputIterator: Iterator[IT, IO, ID, IS],
      input: IO,
      output: I,
      loss: Output,
      trainOp: Op)

  case class SupervisedTrainOps[IT, IO, ID, IS, I, TT, TO, TD, TS, T](
      inputIterator: Iterator[(IT, TT), (IO, TO), (ID, TD), (IS, TS)],
      input: (IO, TO),
      output: I,
      trainOutput: T,
      loss: Output,
      trainOp: Op)

  object SupervisedTrainOps {
    def apply[IT, IO, ID, IS, I](
        inputIterator: Iterator[(IT, IT), (IO, IO), (ID, ID), (IS, IS)],
        input: (IO, IO),
        output: I,
        loss: Output,
        trainOp: Op): SupervisedTrainOps[IT, IO, ID, IS, I, IT, IO, ID, IS, I] = {
      SupervisedTrainOps(inputIterator, input, output, output, loss, trainOp)
    }
  }

  case class EvaluationOps[IT, IO, ID, IS, I](
      inputIterator: Iterator[IT, IO, ID, IS],
      input: IO,
      output: I,
      metricValues: Seq[Output],
      metricUpdates: Seq[Output],
      metricResets: Seq[Op])

  trait API {
    def Model[IT, IO, ID, IS, I, TT, TO, TD, TS, T](
        input: Input[IT, IO, ID, IS],
        layer: Layer[IO, I],
        trainInput: Input[TT, TO, TD, TS],
        trainInputLayer: Layer[TO, T],
        loss: Layer[(I, T), Output],
        optimizer: Optimizer): TrainableModel[IT, IO, ID, IS, I, TT, TO, TD, TS, T] = {
      new SimpleTrainableModel(input, layer, trainInput, trainInputLayer, loss, optimizer)
    }

    def Model[IT, IO, ID, IS, I, TT, TO, TD, TS](
        input: Input[IT, IO, ID, IS],
        layer: Layer[IO, I],
        trainInput: Input[TT, TO, TD, TS],
        loss: Layer[(I, TO), Output],
        optimizer: Optimizer): TrainableModel[IT, IO, ID, IS, I, TT, TO, TD, TS, TO] = {
      new SimpleTrainableModel(input, layer, trainInput, Layer.identity[TO]("TrainInputLayer"), loss, optimizer)
    }
  }

  object API extends API
}

private[learn] class SimpleInferenceModel[IT, IO, ID, IS, I] private[learn](
    val input: Input[IT, IO, ID, IS],
    val layer: Layer[IO, I]
) extends InferenceModel[IT, IO, ID, IS, I] {
  def buildInferenceOps(graph: Graph = Op.currentGraph): Model.InferenceOps[IT, IO, ID, IS, I] = {
    Op.createWith(graph) {
      val tfInputIterator = input()
      val tfInput = tfInputIterator.next()
      val tfOutput = layer(tfInput)
      Model.InferenceOps(tfInputIterator, tfInput, tfOutput)
    }
  }
}

private[learn] class SimpleTrainableModel[IT, IO, ID, IS, I, TT, TO, TD, TS, T] private[learn](
    override val input: Input[IT, IO, ID, IS],
    override val layer: Layer[IO, I],
    val trainInput: Input[TT, TO, TD, TS],
{'fraction_non_alphanumeric': 0.13847502191060473, 'fraction_numerical': 0.0021910604732690623, 'mean_word_length': 3.505923000987167, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 15, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '138156', 'n_tokens_mistral': 3204, 'n_tokens_neox': 3088, 'n_words': 998}