<commit_before># coding=utf-8
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
                        unicode_literals, with_statement)

import os
import re

import pytest

from pants.base.build_environment import get_buildroot
from pants.util.contextutil import temporary_dir
from pants.util.dirutil import safe_rmtree
from pants_test.pants_run_integration_test import PantsRunIntegrationTest
from pants_test.tasks.task_test_base import is_exe

def shared_artifacts(version, extra_jar=None):
  published_file_list = ['ivy-{0}.xml'.format(version),
                         'hello-greet-{0}.jar'.format(version),
                         'hello-greet-{0}.pom'.format(version),
                         'hello-greet-{0}-sources.jar'.format(version)]
  if extra_jar:
    published_file_list.append(extra_jar)
  return {'org/pantsbuild/testproject/publish/hello-greet/{0}'.format(version): published_file_list}

# TODO: Right now some options are set via config and some via cmd-line flags. Normalize this?
def publish_extra_config(unique_config):
  return {
          'publish.jar': {
            'publish_extras': {
              'extra_test_jar_example': unique_config,
              },
            },
          'backends': {
            'packages': [
              'example.pants_publish_plugin',
              'internal_backend.repositories',
              ],
            },
          }

class JarPublishIntegrationTest(PantsRunIntegrationTest):
  SCALADOC = is_exe('scaladoc')
  JAVADOC = is_exe('javadoc')
  GOLDEN_DATA_DIR = 'tests/python/pants_test/tasks/jar_publish_resources/'

  # This is where all pushdb properties files will end up.
  @property
  def pushdb_root(self):
    return os.path.join(get_buildroot(), 'testprojects', 'ivy', 'pushdb')

  def setUp(self):
    # This attribute is required to see the full diff between ivy and pom files.
    self.maxDiff  = None
    safe_rmtree(self.pushdb_root)

  def tearDown(self):
    safe_rmtree(self.pushdb_root)

  @pytest.mark.skipif('not JarPublishIntegrationTest.SCALADOC',
                      reason='No scaladoc binary on the PATH.')
  def test_scala_publish(self):
    unique_artifacts = {'org/pantsbuild/testproject/publish/jvm-example-lib/0.0.1-SNAPSHOT':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'jvm-example-lib-0.0.1-SNAPSHOT.jar',
                         'jvm-example-lib-0.0.1-SNAPSHOT.pom',
                         'jvm-example-lib-0.0.1-SNAPSHOT-sources.jar'],
                        'org/pantsbuild/testproject/publish/hello/welcome/0.0.1-SNAPSHOT':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'welcome-0.0.1-SNAPSHOT.jar',
                         'welcome-0.0.1-SNAPSHOT.pom',
                         'welcome-0.0.1-SNAPSHOT-sources.jar'],}
    self.publish_test('testprojects/src/scala/org/pantsbuild/testproject/publish:jvm-run-example-lib',
                      dict(unique_artifacts.items() + shared_artifacts('0.0.1-SNAPSHOT').items()),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties',
                       'org.pantsbuild.testproject.publish/jvm-example-lib/publish.properties',
                       'org.pantsbuild.testproject.publish.hello/welcome/publish.properties'],
                      extra_options=['--doc-scaladoc-skip'],
                      expected_primary_artifact_count=3,
                      assert_publish_config_contents=True)

  @pytest.mark.skipif('not JarPublishIntegrationTest.JAVADOC',
                      reason='No javadoc binary on the PATH.')
  def test_java_publish(self):
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts('0.0.1-SNAPSHOT'),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],)

  def test_protobuf_publish(self):
    unique_artifacts = {'org/pantsbuild/testproject/publish/protobuf/protobuf-java/0.0.1-SNAPSHOT':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'protobuf-java-0.0.1-SNAPSHOT.jar',
                         'protobuf-java-0.0.1-SNAPSHOT.pom',
                         'protobuf-java-0.0.1-SNAPSHOT-sources.jar'],
                        'org/pantsbuild/testproject/protobuf/distance/0.0.1-SNAPSHOT/':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'distance-0.0.1-SNAPSHOT.jar',
                         'distance-0.0.1-SNAPSHOT.pom',
                         'distance-0.0.1-SNAPSHOT-sources.jar'],}
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/protobuf:protobuf-java',
                      unique_artifacts,
                      ['org.pantsbuild.testproject.publish.protobuf/protobuf-java/publish.properties',
                       'org.pantsbuild.testproject.protobuf/distance/publish.properties'],
                      extra_options=['--doc-javadoc-skip'],
                      expected_primary_artifact_count=2)

  def test_named_snapshot(self):
    name = "abcdef0123456789"
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts(name),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],
                      extra_options=['--named-snapshot={}'.format(name)])

  def test_publish_override_flag_succeeds(self):
    override = "com.twitter.foo#baz=0.1.0"
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts('0.0.1-SNAPSHOT'),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],
                      extra_options=['--override={}'.format(override)])

  # Collect all the common factors for running a publish_extras test, and execute the test.
  def publish_extras_runner(self, extra_config=None, artifact_name=None, success_expected=True):
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts('0.0.1-SNAPSHOT', artifact_name),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],
                      extra_options=['--doc-javadoc-skip'],
                      extra_config=extra_config,
                      extra_env={'WRAPPER_SRCPATH': 'examples/src/python'},
                      success_expected=success_expected)

  #
  # Run through all the permutations of the config parameters for publish_extras.
  #
  def test_publish_extras_name_classifier(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'override_name': '{target_provides_name}-extra_example',
                                'classifier': 'classy',
                                }),
                               artifact_name='hello-greet-extra_example-0.0.1-SNAPSHOT-classy.jar')

  def test_publish_extras_name(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'override_name': '{target_provides_name}-extra_example',
                                }),
                               artifact_name='hello-greet-extra_example-0.0.1-SNAPSHOT.jar')

  def test_publish_extras_name_extension(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'override_name': '{target_provides_name}-extra_example',
                                'extension': 'zip'
                                }),
                               artifact_name='hello-greet-extra_example-0.0.1-SNAPSHOT.zip')

  def test_publish_extras_extension(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'extension': 'zip'
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT.zip')

  def test_publish_extras_extension_classifier(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'classifier': 'classy',
                                'extension': 'zip'
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT-classy.zip')

  def test_publish_extras_classifier(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'classifier': 'classy',
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT-classy.jar')

  # This test doesn't specify a proper set of parameters that uniquely name the extra artifact, and
  # should fail with an error from pants.
  def test_publish_extras_invalid_args(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'extension': 'jar',
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT.jar',
                               success_expected=False)

  @pytest.mark.skipif('not JarPublishIntegrationTest.SCALADOC',
                      reason='No scaladoc binary on the PATH.')
  def test_scala_publish_classifiers(self):
    self.publish_test('testprojects/src/scala/org/pantsbuild/testproject/publish/classifiers',
                      dict({
                        'org/pantsbuild/testproject/publish/classifiers/0.0.1-SNAPSHOT': [
                          'classifiers-0.0.1-SNAPSHOT.pom',
                          'ivy-0.0.1-SNAPSHOT.xml',
                        ]}),
                      [],
                      assert_publish_config_contents=True)

  def publish_test(self, target, artifacts, pushdb_files, extra_options=None, extra_config=None,
                   extra_env=None, expected_primary_artifact_count=1, success_expected=True,
                   assert_publish_config_contents=False):
    """Tests that publishing the given target results in the expected output.

    :param target: Target to test.
    :param artifacts: A map from directories to a list of expected filenames.
    :param pushdb_files: list of pushdb files that would be created if this weren't a local publish
    :param extra_options: Extra command-line options to the pants run.
    :param extra_config: Extra pants.ini configuration for the pants run.
    :param expected_primary_artifact_count: Number of artifacts we expect to be published.
    :param extra_env: Extra environment variables for the pants run.
    :param assert_publish_config_contents: Test the contents of the generated ivy and pom file.
           If set to True, compares the generated ivy.xml and pom files in
           tests/python/pants_test/tasks/jar_publish_resources/<package_name>/<artifact_name>/
    """

    with temporary_dir() as publish_dir:
      options = ['--local={}'.format(publish_dir),
                 '--no-dryrun',
                 '--force']
      if extra_options:
        options.extend(extra_options)

      yes = 'y' * expected_primary_artifact_count
      pants_run = self.run_pants(['publish.jar'] + options + [target], config=extra_config,
                                 stdin_data=yes, extra_env=extra_env)
      if success_expected:
        self.assert_success(pants_run, "'pants goal publish' expected success, but failed instead.")
      else:
        self.assert_failure(pants_run,
                            "'pants goal publish' expected failure, but succeeded instead.")
        return

      # New pushdb directory should be created for all artifacts.
      for pushdb_file in pushdb_files:
        pushdb_dir = os.path.dirname(os.path.join(self.pushdb_root, pushdb_file))
        self.assertTrue(os.path.exists(pushdb_dir))

      # But because we are doing local publishes, no pushdb files are created
      for pushdb_file in pushdb_files:
        self.assertFalse(os.path.exists(os.path.join(self.pushdb_root, pushdb_file)))

      for directory, artifact_list in artifacts.items():
        for artifact in artifact_list:
          artifact_path = os.path.join(publish_dir, directory, artifact)
          self.assertTrue(os.path.exists(artifact_path))
          if assert_publish_config_contents:
            if artifact.endswith('xml') or artifact.endswith('pom'):
              self.compare_file_contents(artifact_path, directory)

  def compare_file_contents(self, artifact_path, directory):
    """
    Tests the ivy.xml and pom
    :param artifact_path: Path of the artifact
    :param directory: Directory where the artifact resides.
    :return:
    """
    # Strip away the version number
    [package_dir, artifact_name, version] = directory.rsplit(os.path.sep, 2)
    file_name = os.path.basename(artifact_path)
    golden_file_nm = os.path.join(JarPublishIntegrationTest.GOLDEN_DATA_DIR,
                                  package_dir.replace(os.path.sep, '.'), artifact_name, file_name)
    with open(artifact_path, 'r') as test_file:
      generated_file = test_file.read()
      with open(golden_file_nm, 'r') as golden_file:
        golden_file_contents = golden_file.read()
        # Remove the publication sha attribute from ivy.xml
        if artifact_path.endswith('.xml'):
          generated_file = re.sub(r'publication=.*', '/>', generated_file)
      return self.assertMultiLineEqual(generated_file, golden_file_contents)
<commit_msg>Remove the pytest skip tag for scala publish integration test as it uses --doc-scaladoc-skip<commit_after># coding=utf-8
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
                        unicode_literals, with_statement)

import os
import re

import pytest

from pants.base.build_environment import get_buildroot
from pants.util.contextutil import temporary_dir
from pants.util.dirutil import safe_rmtree
from pants_test.pants_run_integration_test import PantsRunIntegrationTest
from pants_test.tasks.task_test_base import is_exe

def shared_artifacts(version, extra_jar=None):
  published_file_list = ['ivy-{0}.xml'.format(version),
                         'hello-greet-{0}.jar'.format(version),
                         'hello-greet-{0}.pom'.format(version),
                         'hello-greet-{0}-sources.jar'.format(version)]
  if extra_jar:
    published_file_list.append(extra_jar)
  return {'org/pantsbuild/testproject/publish/hello-greet/{0}'.format(version): published_file_list}

# TODO: Right now some options are set via config and some via cmd-line flags. Normalize this?
def publish_extra_config(unique_config):
  return {
          'publish.jar': {
            'publish_extras': {
              'extra_test_jar_example': unique_config,
              },
            },
          'backends': {
            'packages': [
              'example.pants_publish_plugin',
              'internal_backend.repositories',
              ],
            },
          }

class JarPublishIntegrationTest(PantsRunIntegrationTest):
  SCALADOC = is_exe('scaladoc')
  JAVADOC = is_exe('javadoc')
  GOLDEN_DATA_DIR = 'tests/python/pants_test/tasks/jar_publish_resources/'

  # This is where all pushdb properties files will end up.
  @property
  def pushdb_root(self):
    return os.path.join(get_buildroot(), 'testprojects', 'ivy', 'pushdb')

  def setUp(self):
    # This attribute is required to see the full diff between ivy and pom files.
    self.maxDiff  = None
    safe_rmtree(self.pushdb_root)

  def tearDown(self):
    safe_rmtree(self.pushdb_root)

  def test_scala_publish(self):
    unique_artifacts = {'org/pantsbuild/testproject/publish/jvm-example-lib/0.0.1-SNAPSHOT':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'jvm-example-lib-0.0.1-SNAPSHOT.jar',
                         'jvm-example-lib-0.0.1-SNAPSHOT.pom',
                         'jvm-example-lib-0.0.1-SNAPSHOT-sources.jar'],
                        'org/pantsbuild/testproject/publish/hello/welcome/0.0.1-SNAPSHOT':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'welcome-0.0.1-SNAPSHOT.jar',
                         'welcome-0.0.1-SNAPSHOT.pom',
                         'welcome-0.0.1-SNAPSHOT-sources.jar'],}
    self.publish_test('testprojects/src/scala/org/pantsbuild/testproject/publish:jvm-run-example-lib',
                      dict(unique_artifacts.items() + shared_artifacts('0.0.1-SNAPSHOT').items()),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties',
                       'org.pantsbuild.testproject.publish/jvm-example-lib/publish.properties',
                       'org.pantsbuild.testproject.publish.hello/welcome/publish.properties'],
                      extra_options=['--doc-scaladoc-skip'],
                      expected_primary_artifact_count=3,
                      assert_publish_config_contents=True)

  @pytest.mark.skipif('not JarPublishIntegrationTest.JAVADOC',
                      reason='No javadoc binary on the PATH.')
  def test_java_publish(self):
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts('0.0.1-SNAPSHOT'),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],)

  def test_protobuf_publish(self):
    unique_artifacts = {'org/pantsbuild/testproject/publish/protobuf/protobuf-java/0.0.1-SNAPSHOT':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'protobuf-java-0.0.1-SNAPSHOT.jar',
                         'protobuf-java-0.0.1-SNAPSHOT.pom',
                         'protobuf-java-0.0.1-SNAPSHOT-sources.jar'],
                        'org/pantsbuild/testproject/protobuf/distance/0.0.1-SNAPSHOT/':
                        ['ivy-0.0.1-SNAPSHOT.xml',
                         'distance-0.0.1-SNAPSHOT.jar',
                         'distance-0.0.1-SNAPSHOT.pom',
                         'distance-0.0.1-SNAPSHOT-sources.jar'],}
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/protobuf:protobuf-java',
                      unique_artifacts,
                      ['org.pantsbuild.testproject.publish.protobuf/protobuf-java/publish.properties',
                       'org.pantsbuild.testproject.protobuf/distance/publish.properties'],
                      extra_options=['--doc-javadoc-skip'],
                      expected_primary_artifact_count=2)

  def test_named_snapshot(self):
    name = "abcdef0123456789"
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts(name),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],
                      extra_options=['--named-snapshot={}'.format(name)])

  def test_publish_override_flag_succeeds(self):
    override = "com.twitter.foo#baz=0.1.0"
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts('0.0.1-SNAPSHOT'),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],
                      extra_options=['--override={}'.format(override)])

  # Collect all the common factors for running a publish_extras test, and execute the test.
  def publish_extras_runner(self, extra_config=None, artifact_name=None, success_expected=True):
    self.publish_test('testprojects/src/java/org/pantsbuild/testproject/publish/hello/greet',
                      shared_artifacts('0.0.1-SNAPSHOT', artifact_name),
                      ['org.pantsbuild.testproject.publish/hello-greet/publish.properties'],
                      extra_options=['--doc-javadoc-skip'],
                      extra_config=extra_config,
                      extra_env={'WRAPPER_SRCPATH': 'examples/src/python'},
                      success_expected=success_expected)

  #
  # Run through all the permutations of the config parameters for publish_extras.
  #
  def test_publish_extras_name_classifier(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'override_name': '{target_provides_name}-extra_example',
                                'classifier': 'classy',
                                }),
                               artifact_name='hello-greet-extra_example-0.0.1-SNAPSHOT-classy.jar')

  def test_publish_extras_name(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'override_name': '{target_provides_name}-extra_example',
                                }),
                               artifact_name='hello-greet-extra_example-0.0.1-SNAPSHOT.jar')

  def test_publish_extras_name_extension(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'override_name': '{target_provides_name}-extra_example',
                                'extension': 'zip'
                                }),
                               artifact_name='hello-greet-extra_example-0.0.1-SNAPSHOT.zip')

  def test_publish_extras_extension(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'extension': 'zip'
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT.zip')

  def test_publish_extras_extension_classifier(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'classifier': 'classy',
                                'extension': 'zip'
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT-classy.zip')

  def test_publish_extras_classifier(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'classifier': 'classy',
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT-classy.jar')

  # This test doesn't specify a proper set of parameters that uniquely name the extra artifact, and
  # should fail with an error from pants.
  def test_publish_extras_invalid_args(self):
    self.publish_extras_runner(extra_config=publish_extra_config({
                                'extension': 'jar',
                                }),
                               artifact_name='hello-greet-0.0.1-SNAPSHOT.jar',
                               success_expected=False)

  def test_scala_publish_classifiers(self):
    self.publish_test('testprojects/src/scala/org/pantsbuild/testproject/publish/classifiers',
                      dict({
                        'org/pantsbuild/testproject/publish/classifiers/0.0.1-SNAPSHOT': [
                          'classifiers-0.0.1-SNAPSHOT.pom',
                          'ivy-0.0.1-SNAPSHOT.xml',
                        ]}),
                      [],
                      extra_options=['--doc-scaladoc-skip'],
                      assert_publish_config_contents=True)

  def publish_test(self, target, artifacts, pushdb_files, extra_options=None, extra_config=None,
                   extra_env=None, expected_primary_artifact_count=1, success_expected=True,
                   assert_publish_config_contents=False):
    """Tests that publishing the given target results in the expected output.

    :param target: Target to test.
    :param artifacts: A map from directories to a list of expected filenames.
    :param pushdb_files: list of pushdb files that would be created if this weren't a local publish
    :param extra_options: Extra command-line options to the pants run.
    :param extra_config: Extra pants.ini configuration for the pants run.
    :param expected_primary_artifact_count: Number of artifacts we expect to be published.
    :param extra_env: Extra environment variables for the pants run.
    :param assert_publish_config_contents: Test the contents of the generated ivy and pom file.
           If set to True, compares the generated ivy.xml and pom files in
           tests/python/pants_test/tasks/jar_publish_resources/<package_name>/<artifact_name>/
    """

    with temporary_dir() as publish_dir:
      options = ['--local={}'.format(publish_dir),
                 '--no-dryrun',
                 '--force']
      if extra_options:
        options.extend(extra_options)

      yes = 'y' * expected_primary_artifact_count
      pants_run = self.run_pants(['publish.jar'] + options + [target], config=extra_config,
                                 stdin_data=yes, extra_env=extra_env)
      if success_expected:
        self.assert_success(pants_run, "'pants goal publish' expected success, but failed instead.")
      else:
        self.assert_failure(pants_run,
                            "'pants goal publish' expected failure, but succeeded instead.")
        return

      # New pushdb directory should be created for all artifacts.
      for pushdb_file in pushdb_files:
        pushdb_dir = os.path.dirname(os.path.join(self.pushdb_root, pushdb_file))
        self.assertTrue(os.path.exists(pushdb_dir))

      # But because we are doing local publishes, no pushdb files are created
      for pushdb_file in pushdb_files:
        self.assertFalse(os.path.exists(os.path.join(self.pushdb_root, pushdb_file)))

      for directory, artifact_list in artifacts.items():
        for artifact in artifact_list:
          artifact_path = os.path.join(publish_dir, directory, artifact)
          self.assertTrue(os.path.exists(artifact_path))
          if assert_publish_config_contents:
            if artifact.endswith('xml') or artifact.endswith('pom'):
              self.compare_file_contents(artifact_path, directory)

  def compare_file_contents(self, artifact_path, directory):
    """
    Tests the ivy.xml and pom
    :param artifact_path: Path of the artifact
    :param directory: Directory where the artifact resides.
    :return:
    """
    # Strip away the version number
    [package_dir, artifact_name, version] = directory.rsplit(os.path.sep, 2)
    file_name = os.path.basename(artifact_path)
    golden_file_nm = os.path.join(JarPublishIntegrationTest.GOLDEN_DATA_DIR,
                                  package_dir.replace(os.path.sep, '.'), artifact_name, file_name)
    with open(artifact_path, 'r') as test_file:
      generated_file = test_file.read()
      with open(golden_file_nm, 'r') as golden_file:
        golden_file_contents = golden_file.read()
        # Remove the publication sha attribute from ivy.xml
        if artifact_path.endswith('.xml'):
          generated_file = re.sub(r'publication=.*', '/>', generated_file)
      return self.assertMultiLineEqual(generated_file, golden_file_contents)
<|endoftext|>


<commit_before>import numpy as np

def symsqrtm(a):
    """symmetric square-root of a symmetric positive definite matrix"""
    evals, eigs = np.linalg.eigh(a)
    sqrtevals = np.sqrt(evals)
    symsqrt = np.dot(np.dot(eigs,np.diag(sqrtevals)),eigs.T)
    symsqrtinv = np.dot(np.dot(eigs,np.diag(1./sqrtevals)),eigs.T)
    return symsqrt, symsqrtinv

def serial_ensrf(xmean,xprime,h,obs,oberrvar,covlocal,obcovlocal):
    """serial potter method"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    #hxmean = np.dot(h,xmean)
    #import matplotlib.pyplot as plt
    #plt.plot(np.arange(ndim),xmean)
    #plt.plot(np.arange(ndim),hxmean)
    #plt.show()
    #raise SystemExit
    for nob,ob in zip(np.arange(nobs),obs):
        # forward operator.
        hxprime = np.dot(xprime,h[nob])
        hxmean = np.dot(h[nob],xmean)
        # state space update
        hxens = hxprime.reshape((nanals, 1))
        hpbht = (hxens**2).sum()/(nanals-1)
        gainfact = ((hpbht+oberrvar)/hpbht*\
                   (1.-np.sqrt(oberrvar/(hpbht+oberrvar))))
        pbht = (xprime.T*hxens[:,0]).sum(axis=1)/float(nanals-1)
        kfgain = covlocal[nob,:]*pbht/(hpbht+oberrvar)
        xmean = xmean + kfgain*(ob-hxmean)
        xprime = xprime - gainfact*kfgain*hxens
    return xmean, xprime

def serial_ensrf_modens(xmean,xprime,h,obs,oberrvar,covlocal,z):
    """serial potter method"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]

    # if True, use gain from modulated ensemble to
    # update perts.  if False, use gain from original ensemble.
    update_xprime = True
    if z is None:
        # set ensemble to square root of localized Pb
        Pb = covlocal*np.dot(xprime.T,xprime)/(nanals-1)
        evals, eigs = np.linalg.eigh(Pb)
        print evals.sum()
        evals = np.where(evals > 1.e-10, evals, 1.e-10)
        nanals2 = eigs.shape[0]
        xprime2 = np.sqrt(nanals2-1)*(eigs*np.sqrt(evals)).T
    else:
        # modulation ensemble
        neig = z.shape[0]; nanals2 = neig*nanals; nanal2 = 0
        xprime2 = np.zeros((nanals2,ndim),xprime.dtype)
        for j in range(neig):
            for nanal in range(nanals):
                #print j,nanal,z[neig-j-1,:].min(), z[neig-j-1,:].max()
                xprime2[nanal2,:] = xprime[nanal,:]*z[neig-j-1,:]
                nanal2 += 1
        xprime2 = np.sqrt(float(nanals2-1)/float(nanals-1))*xprime2
    #print xprime2.shape
    #print ((xprime**2).sum(axis=0)/(nanals-1)).sum()
    #print ((xprime2**2).sum(axis=0)/(nanals2-1)).sum()
    #raise SystemExit

    # update xmean using full xprime2
    # update original xprime using gain from full xprime2
    for nob,ob in zip(np.arange(nobs),obs):
        # forward operator.
        hxprime = np.dot(xprime2,h[nob])
        hxprime_orig = np.dot(xprime,h[nob])
        hxmean = np.dot(h[nob],xmean)
        # state space update
        hxens = hxprime.reshape((nanals2, 1))
        hxens_orig = hxprime_orig.reshape((nanals, 1))
        hpbht = (hxens**2).sum()/(nanals2-1)
        gainfact = ((hpbht+oberrvar)/hpbht*\
                   (1.-np.sqrt(oberrvar/(hpbht+oberrvar))))
        pbht = (xprime2.T*hxens[:,0]).sum(axis=1)/float(nanals2-1)
        kfgain = pbht/(hpbht+oberrvar)
        xmean = xmean + kfgain*(ob-hxmean)
        xprime2 = xprime2 - gainfact*kfgain*hxens
        if not update_xprime:
            hpbht = (hxens_orig**2).sum()/(nanals-1)
            gainfact = ((hpbht+oberrvar)/hpbht*\
                       (1.-np.sqrt(oberrvar/(hpbht+oberrvar))))
            pbht = (xprime.T*hxens_orig[:,0]).sum(axis=1)/float(nanals-1)
            kfgain = covlocal[nob,:]*pbht/(hpbht+oberrvar)
        xprime  = xprime  - gainfact*kfgain*hxens_orig
    #print ((xprime2**2).sum(axis=0)/(nanals2-1)).mean()
    #print ((xprime**2).sum(axis=0)/(nanals-1)).mean()
    #raise SystemExit
    return xmean, xprime

def bulk_ensrf(xmean,xprime,h,obs,oberrvar,covlocal):
    """bulk potter method"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    R = oberrvar*np.eye(nobs)
    Rsqrt = np.sqrt(oberrvar)*np.eye(nobs)
    Pb = np.dot(np.transpose(xprime),xprime)/(nanals-1)
    Pb = covlocal*Pb
    C = np.dot(np.dot(h,Pb),h.T)+R
    Cinv = np.linalg.inv(C)
    Csqrt, Csqrtinv =  symsqrtm(C)
    kfgain = np.dot(np.dot(Pb,h.T),Cinv)
    reducedgain = np.dot(np.dot(np.dot(Pb,h.T),Csqrtinv.T),np.linalg.inv(Csqrt + Rsqrt))
    xmean = xmean + np.dot(kfgain, obs-np.dot(h,xmean))
    hxprime = np.empty((nanals, nobs), xprime.dtype)
    for nanal in range(nanals):
        hxprime[nanal] = np.dot(h,xprime[nanal])
    hxprime_tmp = hxprime.reshape((nanals, ndim, 1))
    xprime = xprime - np.dot(reducedgain, hxprime_tmp).T.squeeze()
    return xmean, xprime

def etkf(xmean,xprime,h,obs,oberrvar):
    """ETKF (use only with full rank ensemble, no localization)"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    # forward operator.
    hxprime = np.empty((nanals, nobs), xprime.dtype)
    for nanal in range(nanals):
        hxprime[nanal] = np.dot(h,xprime[nanal])
    hxmean = np.dot(h,xmean)
    Rinv = (1./oberrvar)*np.eye(nobs)
    YbRinv = np.dot(hxprime,Rinv)
    pa = (nanals-1)*np.eye(nanals)+np.dot(YbRinv,hxprime.T)
    evals, eigs = np.linalg.eigh(pa)
    # make square root symmetric.
    painv = np.dot(np.dot(eigs,np.diag(np.sqrt(1./evals))),eigs.T)
    kfgain = np.dot(xprime.T,np.dot(np.dot(painv,painv.T),YbRinv))
    enswts = np.sqrt(nanals-1)*painv
    xmean = xmean + np.dot(kfgain, obs-hxmean)
    xprime = np.dot(enswts.T,xprime)
    return xmean, xprime

def etkf_modens(xmean,xprime,h,obs,oberrvar,covlocal,z):
    """ETKF (use only with full rank ensemble, no localization)"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    if z is None:
        raise ValueError('z not specified')
    # modulation ensemble
    neig = z.shape[0]; nanals2 = neig*nanals; nanal2 = 0
    xprime2 = np.zeros((nanals2,ndim),xprime.dtype)
    for j in range(neig):
        for nanal in range(nanals):
            xprime2[nanal2,:] = xprime[nanal,:]*z[neig-j-1,:]
            nanal2 += 1
    xprime2 = np.sqrt(float(nanals2-1)/float(nanals-1))*xprime2
    # forward operator.
    hxprime = np.empty((nanals2, nobs), xprime2.dtype)
    for nanal in range(nanals2):
        hxprime[nanal] = np.dot(h,xprime2[nanal])
    hxmean = np.dot(h,xmean)
    Rinv = (1./oberrvar)*np.eye(nobs)
    YbRinv = np.dot(hxprime,Rinv)
    pa = (nanals2-1)*np.eye(nanals2)+np.dot(YbRinv,hxprime.T)
    evals, eigs = np.linalg.eigh(pa)
    # make square root symmetric.
    painv = np.dot(np.dot(eigs,np.diag(np.sqrt(1./evals))),eigs.T)
    kfgain = np.dot(xprime2.T,np.dot(np.dot(painv,painv.T),YbRinv))
    enswts = np.sqrt(nanals2-1)*painv
    xmean = xmean + np.dot(kfgain, obs-hxmean)
    # random sample of posterior modulated ensemble to update ens perts.
    xprime2 = np.dot(enswts.T,xprime2)
    #print ((xprime2**2).sum(axis=0)/(nanals2-1)).mean()
    # subsample xprime2 in eigenspace
    #Pa = np.dot(xprime2.T,xprime2)/(nanals2-1)
    #evals, eigs = np.linalg.eigh(Pa)
    #evalsum = evals.sum(); frac = evals[ndim-nanals:ndim].sum()/evalsum
    #evals = np.where(evals > 1.e-10, evals, 1.e-10)
    #xprime2 = np.sqrt(nanals2-1)*(eigs*np.sqrt(evals/frac)).T
    #xprime = np.sqrt(float(nanals-1)/float(nanals2-1))*xprime2[ndim-nanals:ndim,:]
    #print ((xprime**2).sum(axis=0)/(nanals-1)).mean()
    #raise SystemExit
    # subsample xprime2 randomly.
    #nanals_ran = np.random.choice(np.arange(nanals2),nanals)
    #xprime = xprime2[nanals_ran]
    #xprime = xprime - xprime.mean(axis=0) # ensure zero mean
    ##print ((xprime**2).sum(axis=0)/(nanals-1)).mean()
    #raise SystemExit
    #return xmean, xprime
    # update perts with serial ensrf.
    for nob,ob in zip(np.arange(nobs),obs):
        # forward operator.
        hxprime = np.dot(xprime,h[nob])
        # state space update
        hxens = hxprime.reshape((nanals, 1))
        hpbht = (hxens**2).sum()/(nanals-1)
        gainfact = ((hpbht+oberrvar)/hpbht*\
                   (1.-np.sqrt(oberrvar/(hpbht+oberrvar))))
        pbht = (xprime.T*hxens[:,0]).sum(axis=1)/float(nanals-1)
        kfgain = covlocal[nob,:]*pbht/(hpbht+oberrvar)
        xprime = xprime - gainfact*kfgain*hxens
    return xmean, xprime

def letkf(xmean,xprime,h,obs,oberrvar,obcovlocal):
    """LETKF (with observation localization)"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    # forward operator.
    hxprime = np.empty((nanals, nobs), xprime.dtype)
    for nanal in range(nanals):
        hxprime[nanal] = np.dot(h,xprime[nanal])
    hxmean = np.dot(h,xmean)
    obcovlocal = np.where(obcovlocal < 1.e-13,1.e-13,obcovlocal)
    xprime_prior = xprime.copy(); xmean_prior = xmean.copy()
    # brute force application of ETKF for each state element - very slow!
    # assumes all state variables observed.
    ominusf = obs - np.dot(h,xmean_prior)
    for n in range(ndim):
        Rinv = np.diag(obcovlocal[n,:]/oberrvar)
        YbRinv = np.dot(hxprime,Rinv)
        pa = (nanals-1)*np.eye(nanals)+np.dot(YbRinv,hxprime.T)
        evals, eigs = np.linalg.eigh(pa)
        painv = np.dot(np.dot(eigs,np.diag(np.sqrt(1./evals))),eigs.T)
        kfgain = np.dot(xprime_prior[:,n].T,np.dot(np.dot(painv,painv.T),YbRinv))
        enswts = np.sqrt(nanals-1)*painv
        xmean[n] = xmean[n] + np.dot(kfgain, ominusf)
        xprime[:,n] = np.dot(enswts.T,xprime_prior[:,n])
    return xmean, xprime
<commit_msg>update<commit_after>import numpy as np

def symsqrtm(a):
    """symmetric square-root of a symmetric positive definite matrix"""
    evals, eigs = np.linalg.eigh(a)
    sqrtevals = np.sqrt(evals)
    symsqrt = np.dot(np.dot(eigs,np.diag(sqrtevals)),eigs.T)
    symsqrtinv = np.dot(np.dot(eigs,np.diag(1./sqrtevals)),eigs.T)
    return symsqrt, symsqrtinv

def serial_ensrf(xmean,xprime,h,obs,oberrvar,covlocal,obcovlocal):
    """serial potter method"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    #hxmean = np.dot(h,xmean)
    #import matplotlib.pyplot as plt
    #plt.plot(np.arange(ndim),xmean)
    #plt.plot(np.arange(ndim),hxmean)
    #plt.show()
    #raise SystemExit
    for nob,ob in zip(np.arange(nobs),obs):
        # forward operator.
        hxprime = np.dot(xprime,h[nob])
        hxmean = np.dot(h[nob],xmean)
        # state space update
        hxens = hxprime.reshape((nanals, 1))
        hpbht = (hxens**2).sum()/(nanals-1)
        gainfact = ((hpbht+oberrvar)/hpbht*\
                   (1.-np.sqrt(oberrvar/(hpbht+oberrvar))))
        pbht = (xprime.T*hxens[:,0]).sum(axis=1)/float(nanals-1)
        kfgain = covlocal[nob,:]*pbht/(hpbht+oberrvar)
        xmean = xmean + kfgain*(ob-hxmean)
        xprime = xprime - gainfact*kfgain*hxens
    return xmean, xprime

def serial_ensrf_modens(xmean,xprime,h,obs,oberrvar,covlocal,z):
    """serial potter method"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]

    # if True, use gain from modulated ensemble to
    # update perts.  if False, use gain from original ensemble.
    update_xprime = True
    if z is None:
        # set ensemble to square root of localized Pb
        Pb = covlocal*np.dot(xprime.T,xprime)/(nanals-1)
        evals, eigs = np.linalg.eigh(Pb)
        print evals.sum()
        evals = np.where(evals > 1.e-10, evals, 1.e-10)
        nanals2 = eigs.shape[0]
        xprime2 = np.sqrt(nanals2-1)*(eigs*np.sqrt(evals)).T
    else:
        # modulation ensemble
        neig = z.shape[0]; nanals2 = neig*nanals; nanal2 = 0
        xprime2 = np.zeros((nanals2,ndim),xprime.dtype)
        for j in range(neig):
            for nanal in range(nanals):
                #print j,nanal,z[neig-j-1,:].min(), z[neig-j-1,:].max()
                xprime2[nanal2,:] = xprime[nanal,:]*z[neig-j-1,:]
                # unmodulated member is j=1, scaled by z[-1] (a constant)
                nanal2 += 1
        xprime2 = np.sqrt(float(nanals2-1)/float(nanals-1))*xprime2
    #print xprime2.shape
    #print ((xprime**2).sum(axis=0)/(nanals-1)).sum()
    #print ((xprime2**2).sum(axis=0)/(nanals2-1)).sum()
    #raise SystemExit

    # update xmean using full xprime2
    # update original xprime using gain from full xprime2
    for nob,ob in zip(np.arange(nobs),obs):
        # forward operator.
        hxprime = np.dot(xprime2,h[nob])
        hxprime_orig = np.dot(xprime,h[nob])
        hxmean = np.dot(h[nob],xmean)
        # state space update
        hxens = hxprime.reshape((nanals2, 1))
        hxens_orig = hxprime_orig.reshape((nanals, 1))
        hpbht = (hxens**2).sum()/(nanals2-1)
        gainfact = ((hpbht+oberrvar)/hpbht*\
                   (1.-np.sqrt(oberrvar/(hpbht+oberrvar))))
        pbht = (xprime2.T*hxens[:,0]).sum(axis=1)/float(nanals2-1)
        kfgain = pbht/(hpbht+oberrvar)
        xmean = xmean + kfgain*(ob-hxmean)
        xprime2 = xprime2 - gainfact*kfgain*hxens
        if not update_xprime:
            hpbht = (hxens_orig**2).sum()/(nanals-1)
            gainfact = ((hpbht+oberrvar)/hpbht*\
                       (1.-np.sqrt(oberrvar/(hpbht+oberrvar))))
            pbht = (xprime.T*hxens_orig[:,0]).sum(axis=1)/float(nanals-1)
            kfgain = covlocal[nob,:]*pbht/(hpbht+oberrvar)
        xprime  = xprime  - gainfact*kfgain*hxens_orig
    #print ((xprime2**2).sum(axis=0)/(nanals2-1)).mean()
    #print ((xprime**2).sum(axis=0)/(nanals-1)).mean()
    #raise SystemExit
    return xmean, xprime

def bulk_ensrf(xmean,xprime,h,obs,oberrvar,covlocal):
    """bulk potter method"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    R = oberrvar*np.eye(nobs)
    Rsqrt = np.sqrt(oberrvar)*np.eye(nobs)
    Pb = np.dot(np.transpose(xprime),xprime)/(nanals-1)
    Pb = covlocal*Pb
    C = np.dot(np.dot(h,Pb),h.T)+R
    Cinv = np.linalg.inv(C)
    Csqrt, Csqrtinv =  symsqrtm(C)
    kfgain = np.dot(np.dot(Pb,h.T),Cinv)
    reducedgain = np.dot(np.dot(np.dot(Pb,h.T),Csqrtinv.T),np.linalg.inv(Csqrt + Rsqrt))
    xmean = xmean + np.dot(kfgain, obs-np.dot(h,xmean))
    hxprime = np.empty((nanals, nobs), xprime.dtype)
    for nanal in range(nanals):
        hxprime[nanal] = np.dot(h,xprime[nanal])
    hxprime_tmp = hxprime.reshape((nanals, ndim, 1))
    xprime = xprime - np.dot(reducedgain, hxprime_tmp).T.squeeze()
    return xmean, xprime

def etkf(xmean,xprime,h,obs,oberrvar):
    """ETKF (use only with full rank ensemble, no localization)"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    # forward operator.
    hxprime = np.empty((nanals, nobs), xprime.dtype)
    for nanal in range(nanals):
        hxprime[nanal] = np.dot(h,xprime[nanal])
    hxmean = np.dot(h,xmean)
    Rinv = (1./oberrvar)*np.eye(nobs)
    YbRinv = np.dot(hxprime,Rinv)
    pa = (nanals-1)*np.eye(nanals)+np.dot(YbRinv,hxprime.T)
    evals, eigs = np.linalg.eigh(pa)
    # make square root symmetric.
    painv = np.dot(np.dot(eigs,np.diag(np.sqrt(1./evals))),eigs.T)
    kfgain = np.dot(xprime.T,np.dot(np.dot(painv,painv.T),YbRinv))
    enswts = np.sqrt(nanals-1)*painv
    xmean = xmean + np.dot(kfgain, obs-hxmean)
    xprime = np.dot(enswts.T,xprime)
    return xmean, xprime

def etkf_modens(xmean,xprime,h,obs,oberrvar,covlocal,z):
    """ETKF (use only with full rank ensemble, no localization)"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    if z is None:
        raise ValueError('z not specified')
    # modulation ensemble
    print 'here'
    neig = z.shape[0]; nanals2 = neig*nanals; nanal2 = 0
    xprime2 = np.zeros((nanals2,ndim),xprime.dtype)
    for j in range(neig):
        for nanal in range(nanals):
            xprime2[nanal2,:] = xprime[nanal,:]*z[neig-j-1,:]
            nanal2 += 1
    print 'here 2'
    xprime2 = np.sqrt(float(nanals2-1)/float(nanals-1))*xprime2
    # forward operator.
    hxprime = np.empty((nanals2, nobs), xprime2.dtype)
    for nanal in range(nanals2):
        hxprime[nanal] = np.dot(h,xprime2[nanal])
    hxmean = np.dot(h,xmean)
    Rinv = (1./oberrvar)*np.eye(nobs)
    YbRinv = np.dot(hxprime,Rinv)
    pa = (nanals2-1)*np.eye(nanals2)+np.dot(YbRinv,hxprime.T)
    evals, eigs = np.linalg.eigh(pa)
    # make square root symmetric.
    painv = np.dot(np.dot(eigs,np.diag(np.sqrt(1./evals))),eigs.T)
    kfgain = np.dot(xprime2.T,np.dot(np.dot(painv,painv.T),YbRinv))
    enswts = np.sqrt(nanals2-1)*painv
    #       tmp = np.dot(np.dot(np.dot(painv, painv.T), YbRinv), ominusf)
    #       return np.sqrt(nanals-1)*painv + tmp[:,np.newaxis]
    #            wts = calcwts(hx[:,mask],Rinv,omf[mask])
    #            xens[:,k,n] = xmean[k,n] + np.dot(wts.T, xprime[:,k,n])
    xmean = xmean + np.dot(kfgain, obs-hxmean)
    # project weights on un-modulated ensemble.
    #hxprime = np.empty((nanals, nobs), xprime.dtype)
    #for nanal in range(nanals):
    #    hxprime[nanal] = np.dot(h,xprime[nanal])
    #hxprime_tmp = hxprime.reshape((nanals, ndim, 1))
    #xprime = xprime - np.dot(0.5*kfgain, hxprime_tmp).T.squeeze()
    enswts = np.sqrt(nanals-1)*painv
    xprime = np.dot(enswts.T[:,0:nanals],xprime)
    #xprime = np.dot(enswts.T[:,0:nanals],xprime2[0:nanals])
    #print xprime.min(), xprime.max()
    #raise SystemExit
    #xprime = np.dot(enswts.T,xprime2)[0:nanals]
    #print xprime.min(), xprime.max()
    #raise SystemExit
    #print (enswts.T).shape,xprime2.shape,xprime.shape
    #raise SystemExit
    #xprime = np.dot(enswts.T[:,0:nanals],xprime2[0:nanals])
    return xmean, xprime

def letkf(xmean,xprime,h,obs,oberrvar,obcovlocal):
    """LETKF (with observation localization)"""
    nanals, ndim = xprime.shape; nobs = obs.shape[-1]
    # forward operator.
    hxprime = np.empty((nanals, nobs), xprime.dtype)
    for nanal in range(nanals):
        hxprime[nanal] = np.dot(h,xprime[nanal])
    hxmean = np.dot(h,xmean)
    obcovlocal = np.where(obcovlocal < 1.e-13,1.e-13,obcovlocal)
    xprime_prior = xprime.copy(); xmean_prior = xmean.copy()
    # brute force application of ETKF for each state element - very slow!
    # assumes all state variables observed.
    ominusf = obs - np.dot(h,xmean_prior)
    for n in range(ndim):
        Rinv = np.diag(obcovlocal[n,:]/oberrvar)
        YbRinv = np.dot(hxprime,Rinv)
        pa = (nanals-1)*np.eye(nanals)+np.dot(YbRinv,hxprime.T)
        evals, eigs = np.linalg.eigh(pa)
        painv = np.dot(np.dot(eigs,np.diag(np.sqrt(1./evals))),eigs.T)
        kfgain = np.dot(xprime_prior[:,n].T,np.dot(np.dot(painv,painv.T),YbRinv))
        enswts = np.sqrt(nanals-1)*painv
        xmean[n] = xmean[n] + np.dot(kfgain, ominusf)
        xprime[:,n] = np.dot(enswts.T,xprime_prior[:,n])
    return xmean, xprime
<|endoftext|>


<commit_before># Copyright 2016 Google Inc. 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.
"""Binary for evaluating Tensorflow models on the YouTube-8M dataset."""

import glob
import json
import os
import time

from absl import logging
import eval_util
import frame_level_models
import losses
import readers
import tensorflow as tf
from tensorflow import app
from tensorflow import flags
from tensorflow import gfile
# from tensorflow import logging
from tensorflow.python.lib.io import file_io
import utils
import video_level_models

FLAGS = flags.FLAGS

if __name__ == "__main__":
  # Dataset flags.
  flags.DEFINE_string(
      "train_dir", "/tmp/yt8m_model/",
      "The directory to load the model files from. "
      "The tensorboard metrics files are also saved to this "
      "directory.")
  flags.DEFINE_string(
      "eval_data_pattern", "",
      "File glob defining the evaluation dataset in tensorflow.SequenceExample "
      "format. The SequenceExamples are expected to have an 'rgb' byte array "
      "sequence feature as well as a 'labels' int64 context feature.")
  flags.DEFINE_bool(
      "segment_labels", False,
      "If set, then --train_data_pattern must be frame-level features (but with"
      " segment_labels). Otherwise, --train_data_pattern must be aggregated "
      "video-level features. The model must also be set appropriately (i.e. to "
      "read 3D batches VS 4D batches.")

  # Other flags.
  flags.DEFINE_integer("batch_size", 1024,
                       "How many examples to process per batch.")
  flags.DEFINE_integer("num_readers", 8,
                       "How many threads to use for reading input files.")
  flags.DEFINE_boolean("run_once", False, "Whether to run eval only once.")
  flags.DEFINE_integer("top_k", 20, "How many predictions to output per video.")

def find_class_by_name(name, modules):
  """Searches the provided modules for the named class and returns it."""
  modules = [getattr(module, name, None) for module in modules]
  return next(a for a in modules if a)

def get_input_evaluation_tensors(reader,
                                 data_pattern,
                                 batch_size=1024,
                                 num_readers=1):
  """Creates the section of the graph which reads the evaluation data.

  Args:
    reader: A class which parses the training data.
    data_pattern: A 'glob' style path to the data files.
    batch_size: How many examples to process at a time.
    num_readers: How many I/O threads to use.

  Returns:
    A tuple containing the features tensor, labels tensor, and optionally a
    tensor containing the number of frames per video. The exact dimensions
    depend on the reader being used.

  Raises:
    IOError: If no files matching the given pattern were found.
  """
  logging.info("Using batch size of %d for evaluation.", batch_size)
  with tf.name_scope("eval_input"):
    files = gfile.Glob(data_pattern)
    if not files:
      raise IOError("Unable to find the evaluation files.")
    logging.info("number of evaluation files: %d", len(files))
    filename_queue = tf.train.string_input_producer(
        files, shuffle=False, num_epochs=1)
    eval_data = [
        reader.prepare_reader(filename_queue) for _ in range(num_readers)
    ]
    return tf.train.batch_join(
        eval_data,
        batch_size=batch_size,
        capacity=3 * batch_size,
        allow_smaller_final_batch=True,
        enqueue_many=True)

def build_graph(reader,
                model,
                eval_data_pattern,
                label_loss_fn,
                batch_size=1024,
                num_readers=1):
  """Creates the Tensorflow graph for evaluation.

  Args:
    reader: The data file reader. It should inherit from BaseReader.
    model: The core model (e.g. logistic or neural net). It should inherit from
      BaseModel.
    eval_data_pattern: glob path to the evaluation data files.
    label_loss_fn: What kind of loss to apply to the model. It should inherit
      from BaseLoss.
    batch_size: How many examples to process at a time.
    num_readers: How many threads to use for I/O operations.
  """

  global_step = tf.Variable(0, trainable=False, name="global_step")
  input_data_dict = get_input_evaluation_tensors(
      reader, eval_data_pattern, batch_size=batch_size, num_readers=num_readers)
  video_id_batch = input_data_dict["video_ids"]
  model_input_raw = input_data_dict["video_matrix"]
  labels_batch = input_data_dict["labels"]
  num_frames = input_data_dict["num_frames"]
  tf.summary.histogram("model_input_raw", model_input_raw)

  feature_dim = len(model_input_raw.get_shape()) - 1

  # Normalize input features.
  model_input = tf.nn.l2_normalize(model_input_raw, feature_dim)

  with tf.variable_scope("tower"):
    result = model.create_model(
        model_input,
        num_frames=num_frames,
        vocab_size=reader.num_classes,
        labels=labels_batch,
        is_training=False)
    predictions = result["predictions"]
    tf.summary.histogram("model_activations", predictions)
    if "loss" in result.keys():
      label_loss = result["loss"]
    else:
      label_loss = label_loss_fn.calculate_loss(predictions, labels_batch)

  tf.add_to_collection("global_step", global_step)
  tf.add_to_collection("loss", label_loss)
  tf.add_to_collection("predictions", predictions)
  tf.add_to_collection("input_batch", model_input)
  tf.add_to_collection("input_batch_raw", model_input_raw)
  tf.add_to_collection("video_id_batch", video_id_batch)
  tf.add_to_collection("num_frames", num_frames)
  tf.add_to_collection("labels", tf.cast(labels_batch, tf.float32))
  tf.add_to_collection("summary_op", tf.summary.merge_all())

def evaluation_loop(video_id_batch, prediction_batch, label_batch, loss,
                    summary_op, saver, summary_writer, evl_metrics,
                    last_global_step_val):
  """Run the evaluation loop once.

  Args:
    video_id_batch: a tensor of video ids mini-batch.
    prediction_batch: a tensor of predictions mini-batch.
    label_batch: a tensor of label_batch mini-batch.
    loss: a tensor of loss for the examples in the mini-batch.
    summary_op: a tensor which runs the tensorboard summary operations.
    saver: a tensorflow saver to restore the model.
    summary_writer: a tensorflow summary_writer
    evl_metrics: an EvaluationMetrics object.
    last_global_step_val: the global step used in the previous evaluation.

  Returns:
    The global_step used in the latest model.
  """

  global_step_val = -1
  with tf.Session() as sess:
    latest_checkpoint = tf.train.latest_checkpoint(FLAGS.train_dir)
    if latest_checkpoint:
      logging.info("Loading checkpoint for eval: %s", latest_checkpoint)
      # Restores from checkpoint
      saver.restore(sess, latest_checkpoint)
      # Assuming model_checkpoint_path looks something like:
      # /my-favorite-path/yt8m_train/model.ckpt-0, extract global_step from it.
      global_step_val = os.path.basename(latest_checkpoint).split("-")[-1]

      # Save model
      saver.save(
          sess,
          os.path.join(FLAGS.train_dir, "inference_model", "inference_model"))
    else:
      logging.info("No checkpoint file found.")
      return global_step_val

    if global_step_val == last_global_step_val:
      logging.info(
          "skip this checkpoint global_step_val=%s "
          "(same as the previous one).", global_step_val)
      return global_step_val

    sess.run([tf.local_variables_initializer()])

    # Start the queue runners.
    fetches = [video_id_batch, prediction_batch, label_batch, loss, summary_op]
    coord = tf.train.Coordinator()
    try:
      threads = []
      for qr in tf.get_collection(tf.GraphKeys.QUEUE_RUNNERS):
        threads.extend(
            qr.create_threads(sess, coord=coord, daemon=True, start=True))
      logging.info("enter eval_once loop global_step_val = %s. ",
                   global_step_val)

      evl_metrics.clear()

      examples_processed = 0
      while not coord.should_stop():
        logging.info("Running eval step...")
        batch_start_time = time.time()
        _, predictions_val, labels_val, loss_val, summary_val = sess.run(
            fetches)
        seconds_per_batch = time.time() - batch_start_time
        logging.info("calculating metrics...")
        example_per_second = labels_val.shape[0] / seconds_per_batch
        examples_processed += labels_val.shape[0]

        iteration_info_dict = evl_metrics.accumulate(predictions_val,
                                                     labels_val, loss_val)
        iteration_info_dict["examples_per_second"] = example_per_second

        iterinfo = utils.AddGlobalStepSummary(
            summary_writer,
            global_step_val,
            iteration_info_dict,
            summary_scope="Eval")
        logging.info("examples_processed: %d | %s", examples_processed,
                     iterinfo)

    except tf.errors.OutOfRangeError as e:
      logging.info(
          "Done with batched inference. Now calculating global performance "
          "metrics.")
      # calculate the metrics for the entire epoch
      epoch_info_dict = evl_metrics.get()
      epoch_info_dict["epoch_id"] = global_step_val

      summary_writer.add_summary(summary_val, global_step_val)
      epochinfo = utils.AddEpochSummary(
          summary_writer,
          global_step_val,
          epoch_info_dict,
          summary_scope="Eval")
      logging.info(epochinfo)
      evl_metrics.clear()
    except Exception as e:  # pylint: disable=broad-except
      logging.info("Unexpected exception: %s", str(e))
      coord.request_stop(e)

    coord.request_stop()
    coord.join(threads, stop_grace_period_secs=10)

    return global_step_val

def evaluate():
  """Starts main evaluation loop."""
  tf.set_random_seed(0)  # for reproducibility

  # Write json of flags
  model_flags_path = os.path.join(FLAGS.train_dir, "model_flags.json")
  if not file_io.file_exists(model_flags_path):
    raise IOError(("Cannot find file %s. Did you run train.py on the same "
                   "--train_dir?") % model_flags_path)
  flags_dict = json.loads(file_io.FileIO(model_flags_path, mode="r").read())

  with tf.Graph().as_default():
    # convert feature_names and feature_sizes to lists of values
    feature_names, feature_sizes = utils.GetListOfFeatureNamesAndSizes(
        flags_dict["feature_names"], flags_dict["feature_sizes"])

    if flags_dict["frame_features"]:
      reader = readers.YT8MFrameFeatureReader(
          feature_names=feature_names,
          feature_sizes=feature_sizes,
          segment_labels=FLAGS.segment_labels)
    else:
      reader = readers.YT8MAggregatedFeatureReader(
          feature_names=feature_names, feature_sizes=feature_sizes)

    model = find_class_by_name(flags_dict["model"],
                               [frame_level_models, video_level_models])()
    label_loss_fn = find_class_by_name(flags_dict["label_loss"], [losses])()

    if not FLAGS.eval_data_pattern:
      raise IOError("'eval_data_pattern' was not specified. Nothing to "
                    "evaluate.")

    build_graph(
        reader=reader,
        model=model,
        eval_data_pattern=FLAGS.eval_data_pattern,
        label_loss_fn=label_loss_fn,
        num_readers=FLAGS.num_readers,
        batch_size=FLAGS.batch_size)
    logging.info("built evaluation graph")
    video_id_batch = tf.get_collection("video_id_batch")[0]
    prediction_batch = tf.get_collection("predictions")[0]
    label_batch = tf.get_collection("labels")[0]
    loss = tf.get_collection("loss")[0]
    summary_op = tf.get_collection("summary_op")[0]

    saver = tf.train.Saver(tf.global_variables())
    summary_writer = tf.summary.FileWriter(
        os.path.join(FLAGS.train_dir, "eval"), graph=tf.get_default_graph())

    evl_metrics = eval_util.EvaluationMetrics(reader.num_classes, FLAGS.top_k)

    last_global_step_val = -1
    while True:
      last_global_step_val = evaluation_loop(video_id_batch, prediction_batch,
                                             label_batch, loss, summary_op,
                                             saver, summary_writer, evl_metrics,
                                             last_global_step_val)
      if FLAGS.run_once:
        break

def main(unused_argv):
  logging.set_verbosity(tf.logging.INFO)
  logging.info("tensorflow version: %s", tf.__version__)
  evaluate()

if __name__ == "__main__":
  app.run()
<commit_msg>Remove some unnecessary comment.<commit_after># Copyright 2016 Google Inc. 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.
"""Binary for evaluating Tensorflow models on the YouTube-8M dataset."""

import glob
import json
import os
import time

from absl import logging
import eval_util
import frame_level_models
import losses
import readers
import tensorflow as tf
from tensorflow import app
from tensorflow import flags
from tensorflow import gfile
from tensorflow.python.lib.io import file_io
import utils
import video_level_models

FLAGS = flags.FLAGS

if __name__ == "__main__":
  # Dataset flags.
  flags.DEFINE_string(
      "train_dir", "/tmp/yt8m_model/",
      "The directory to load the model files from. "
      "The tensorboard metrics files are also saved to this "
      "directory.")
  flags.DEFINE_string(
      "eval_data_pattern", "",
      "File glob defining the evaluation dataset in tensorflow.SequenceExample "
      "format. The SequenceExamples are expected to have an 'rgb' byte array "
      "sequence feature as well as a 'labels' int64 context feature.")
  flags.DEFINE_bool(
      "segment_labels", False,
      "If set, then --train_data_pattern must be frame-level features (but with"
      " segment_labels). Otherwise, --train_data_pattern must be aggregated "
      "video-level features. The model must also be set appropriately (i.e. to "
      "read 3D batches VS 4D batches.")

  # Other flags.
  flags.DEFINE_integer("batch_size", 1024,
                       "How many examples to process per batch.")
  flags.DEFINE_integer("num_readers", 8,
                       "How many threads to use for reading input files.")
  flags.DEFINE_boolean("run_once", False, "Whether to run eval only once.")
  flags.DEFINE_integer("top_k", 20, "How many predictions to output per video.")

def find_class_by_name(name, modules):
  """Searches the provided modules for the named class and returns it."""
  modules = [getattr(module, name, None) for module in modules]
  return next(a for a in modules if a)

def get_input_evaluation_tensors(reader,
                                 data_pattern,
                                 batch_size=1024,
                                 num_readers=1):
  """Creates the section of the graph which reads the evaluation data.

  Args:
    reader: A class which parses the training data.
    data_pattern: A 'glob' style path to the data files.
    batch_size: How many examples to process at a time.
    num_readers: How many I/O threads to use.

  Returns:
    A tuple containing the features tensor, labels tensor, and optionally a
    tensor containing the number of frames per video. The exact dimensions
    depend on the reader being used.

  Raises:
    IOError: If no files matching the given pattern were found.
  """
  logging.info("Using batch size of %d for evaluation.", batch_size)
  with tf.name_scope("eval_input"):
    files = gfile.Glob(data_pattern)
    if not files:
      raise IOError("Unable to find the evaluation files.")
    logging.info("number of evaluation files: %d", len(files))
    filename_queue = tf.train.string_input_producer(
        files, shuffle=False, num_epochs=1)
    eval_data = [
        reader.prepare_reader(filename_queue) for _ in range(num_readers)
    ]
    return tf.train.batch_join(
        eval_data,
        batch_size=batch_size,
        capacity=3 * batch_size,
        allow_smaller_final_batch=True,
        enqueue_many=True)

def build_graph(reader,
                model,
                eval_data_pattern,
                label_loss_fn,
                batch_size=1024,
                num_readers=1):
  """Creates the Tensorflow graph for evaluation.

  Args:
    reader: The data file reader. It should inherit from BaseReader.
    model: The core model (e.g. logistic or neural net). It should inherit from
      BaseModel.
    eval_data_pattern: glob path to the evaluation data files.
    label_loss_fn: What kind of loss to apply to the model. It should inherit
      from BaseLoss.
    batch_size: How many examples to process at a time.
    num_readers: How many threads to use for I/O operations.
  """

  global_step = tf.Variable(0, trainable=False, name="global_step")
  input_data_dict = get_input_evaluation_tensors(
      reader, eval_data_pattern, batch_size=batch_size, num_readers=num_readers)
  video_id_batch = input_data_dict["video_ids"]
  model_input_raw = input_data_dict["video_matrix"]
  labels_batch = input_data_dict["labels"]
  num_frames = input_data_dict["num_frames"]
  tf.summary.histogram("model_input_raw", model_input_raw)

  feature_dim = len(model_input_raw.get_shape()) - 1

  # Normalize input features.
  model_input = tf.nn.l2_normalize(model_input_raw, feature_dim)

  with tf.variable_scope("tower"):
    result = model.create_model(
        model_input,
        num_frames=num_frames,
        vocab_size=reader.num_classes,
        labels=labels_batch,
        is_training=False)
    predictions = result["predictions"]
    tf.summary.histogram("model_activations", predictions)
    if "loss" in result.keys():
      label_loss = result["loss"]
    else:
      label_loss = label_loss_fn.calculate_loss(predictions, labels_batch)

  tf.add_to_collection("global_step", global_step)
  tf.add_to_collection("loss", label_loss)
  tf.add_to_collection("predictions", predictions)
  tf.add_to_collection("input_batch", model_input)
  tf.add_to_collection("input_batch_raw", model_input_raw)
  tf.add_to_collection("video_id_batch", video_id_batch)
  tf.add_to_collection("num_frames", num_frames)
  tf.add_to_collection("labels", tf.cast(labels_batch, tf.float32))
  tf.add_to_collection("summary_op", tf.summary.merge_all())

def evaluation_loop(video_id_batch, prediction_batch, label_batch, loss,
                    summary_op, saver, summary_writer, evl_metrics,
                    last_global_step_val):
  """Run the evaluation loop once.

  Args:
    video_id_batch: a tensor of video ids mini-batch.
    prediction_batch: a tensor of predictions mini-batch.
    label_batch: a tensor of label_batch mini-batch.
    loss: a tensor of loss for the examples in the mini-batch.
    summary_op: a tensor which runs the tensorboard summary operations.
    saver: a tensorflow saver to restore the model.
    summary_writer: a tensorflow summary_writer
    evl_metrics: an EvaluationMetrics object.
    last_global_step_val: the global step used in the previous evaluation.

  Returns:
    The global_step used in the latest model.
  """

  global_step_val = -1
  with tf.Session() as sess:
    latest_checkpoint = tf.train.latest_checkpoint(FLAGS.train_dir)
    if latest_checkpoint:
      logging.info("Loading checkpoint for eval: %s", latest_checkpoint)
      # Restores from checkpoint
      saver.restore(sess, latest_checkpoint)
      # Assuming model_checkpoint_path looks something like:
      # /my-favorite-path/yt8m_train/model.ckpt-0, extract global_step from it.
      global_step_val = os.path.basename(latest_checkpoint).split("-")[-1]

      # Save model
      saver.save(
          sess,
          os.path.join(FLAGS.train_dir, "inference_model", "inference_model"))
    else:
      logging.info("No checkpoint file found.")
      return global_step_val

    if global_step_val == last_global_step_val:
      logging.info(
          "skip this checkpoint global_step_val=%s "
          "(same as the previous one).", global_step_val)
      return global_step_val

    sess.run([tf.local_variables_initializer()])

    # Start the queue runners.
    fetches = [video_id_batch, prediction_batch, label_batch, loss, summary_op]
    coord = tf.train.Coordinator()
    try:
      threads = []
      for qr in tf.get_collection(tf.GraphKeys.QUEUE_RUNNERS):
        threads.extend(
            qr.create_threads(sess, coord=coord, daemon=True, start=True))
      logging.info("enter eval_once loop global_step_val = %s. ",
                   global_step_val)

      evl_metrics.clear()

      examples_processed = 0
      while not coord.should_stop():
        batch_start_time = time.time()
        _, predictions_val, labels_val, loss_val, summary_val = sess.run(
            fetches)
        seconds_per_batch = time.time() - batch_start_time
        example_per_second = labels_val.shape[0] / seconds_per_batch
        examples_processed += labels_val.shape[0]

        iteration_info_dict = evl_metrics.accumulate(predictions_val,
                                                     labels_val, loss_val)
        iteration_info_dict["examples_per_second"] = example_per_second

        iterinfo = utils.AddGlobalStepSummary(
            summary_writer,
            global_step_val,
            iteration_info_dict,
            summary_scope="Eval")
        logging.info("examples_processed: %d | %s", examples_processed,
                     iterinfo)

    except tf.errors.OutOfRangeError as e:
      logging.info(
          "Done with batched inference. Now calculating global performance "
          "metrics.")
      # calculate the metrics for the entire epoch
      epoch_info_dict = evl_metrics.get()
      epoch_info_dict["epoch_id"] = global_step_val

      summary_writer.add_summary(summary_val, global_step_val)
      epochinfo = utils.AddEpochSummary(
          summary_writer,
          global_step_val,
          epoch_info_dict,
          summary_scope="Eval")
      logging.info(epochinfo)
      evl_metrics.clear()
    except Exception as e:  # pylint: disable=broad-except
      logging.info("Unexpected exception: %s", str(e))
      coord.request_stop(e)

    coord.request_stop()
    coord.join(threads, stop_grace_period_secs=10)

    return global_step_val

def evaluate():
  """Starts main evaluation loop."""
  tf.set_random_seed(0)  # for reproducibility

  # Write json of flags
  model_flags_path = os.path.join(FLAGS.train_dir, "model_flags.json")
  if not file_io.file_exists(model_flags_path):
    raise IOError(("Cannot find file %s. Did you run train.py on the same "
                   "--train_dir?") % model_flags_path)
  flags_dict = json.loads(file_io.FileIO(model_flags_path, mode="r").read())

  with tf.Graph().as_default():
    # convert feature_names and feature_sizes to lists of values
    feature_names, feature_sizes = utils.GetListOfFeatureNamesAndSizes(
        flags_dict["feature_names"], flags_dict["feature_sizes"])

    if flags_dict["frame_features"]:
      reader = readers.YT8MFrameFeatureReader(
          feature_names=feature_names,
          feature_sizes=feature_sizes,
          segment_labels=FLAGS.segment_labels)
    else:
      reader = readers.YT8MAggregatedFeatureReader(
          feature_names=feature_names, feature_sizes=feature_sizes)

    model = find_class_by_name(flags_dict["model"],
                               [frame_level_models, video_level_models])()
    label_loss_fn = find_class_by_name(flags_dict["label_loss"], [losses])()

    if not FLAGS.eval_data_pattern:
      raise IOError("'eval_data_pattern' was not specified. Nothing to "
                    "evaluate.")

    build_graph(
        reader=reader,
        model=model,
        eval_data_pattern=FLAGS.eval_data_pattern,
        label_loss_fn=label_loss_fn,
        num_readers=FLAGS.num_readers,
        batch_size=FLAGS.batch_size)
    logging.info("built evaluation graph")
    video_id_batch = tf.get_collection("video_id_batch")[0]
    prediction_batch = tf.get_collection("predictions")[0]
    label_batch = tf.get_collection("labels")[0]
    loss = tf.get_collection("loss")[0]
    summary_op = tf.get_collection("summary_op")[0]

    saver = tf.train.Saver(tf.global_variables())
    summary_writer = tf.summary.FileWriter(
        os.path.join(FLAGS.train_dir, "eval"), graph=tf.get_default_graph())

    evl_metrics = eval_util.EvaluationMetrics(reader.num_classes, FLAGS.top_k)

    last_global_step_val = -1
    while True:
      last_global_step_val = evaluation_loop(video_id_batch, prediction_batch,
                                             label_batch, loss, summary_op,
                                             saver, summary_writer, evl_metrics,
                                             last_global_step_val)
      if FLAGS.run_once:
        break

def main(unused_argv):
  logging.set_verbosity(tf.logging.INFO)
  logging.info("tensorflow version: %s", tf.__version__)
  evaluate()

if __name__ == "__main__":
  app.run()
<|endoftext|>


<commit_before>#coding:utf-8

#第一个函数
def break_words(stuff):
    """This function will break up words for us."""
    words = stuff.split(' ')        #截取字符串一空格为基准，截取为列表
    return words                    #返回words
#第二个函数
def sort_words(words):
    """Sorts the words."""          #注释，帮助文档引用
    return sorted(words)            #按从小到大的顺序排序，然后返回

def print_firsr_work(words):
    """Prints the first word after popping if off."""
    word = words.pop(0)             #把列表的元组移出给对象，默认为最后一个
    print word

def print_last_word(words):
    """Prints the last word after popping  it off."""
    word = words.pop(-1)            #pop是提取某个元素给对象，默认为最后一个
    print word

def sort_sentence(sentence):
    """Takes in a full sentence and returns the eorted words."""
    words = break_woeds(sentence)
    return sort_woeds(words)

def print_first_and_last(sentence):
    """Prinds the first and last words of the sentence."""
    words = break_woeds(sentence)
    print_firsr_work(woeds)
    print_last_word(words)

def print_first_and_last_sorted(sentence):
    """Sortd the words then prints the first and last one."""
    words = sort_sentence(sentence)
    print_first_word(words)
    print_last_word(words)
<commit_msg>函数更改之后的<commit_after>#coding:utf-8

#第一个函数
def break_words(stuff):
    """This function will break up words for us."""
    words = stuff.split(' ')        #截取字符串一空格为基准，截取为列表
    return words                    #返回words
#第二个函数
def sort_words(words):
    """Sorts the words."""          #注释，帮助文档引用
    return sorted(words)            #按从小到大的顺序排序，然后返回

def print_firsr_work(words):
    """Prints the first word after popping if off."""
    word = words.pop(0)             #把列表的元组移出给对象，默认为最后一个
    print word

def print_last_word(words):
    """Prints the last word after popping  it off."""
    word = words.pop(-1)            #pop是提取某个元素给对象，默认为最后一个
    print word

def sort_sentence(sentence):
    """Takes in a full sentence and returns the eorted words."""
    words = break_words(sentence)
    return sort_words(words)

def print_first_and_last(sentence):
    """Prinds the first and last words of the sentence."""
    words = break_words(sentence)
    print_firsr_work(words)
    print_last_word(words)

def print_first_and_last_sorted(sentence):
    """Sortd the words then prints the first and last one."""
    words = sort_sentence(sentence)
    print_first_word(words)
    print_last_word(words)
<|endoftext|>