diff --git a/.travis.yml b/.travis.yml
index cb967eb1..aada26e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,6 +13,7 @@ stages:
   - Test
   - Docs
   - Deploy
+  - Nightly
 
 before_install: &before_install
   - sudo apt-get update
@@ -83,7 +84,7 @@ jobs:
     # GitHub Pages Deployment: https://docs.travis-ci.com/user/deployment/pages/
     - stage: Docs
       python: "3.5"
-
+      if: branch != nightly
       # Use previously defined before_install
       before_install: *before_install
 
@@ -161,3 +162,54 @@ jobs:
 
         on:
           tags: true
+
+    - stage: Nightly
+      python: "3.5"
+      env:
+        - PYTORCH_PACKAGE=pytorch-nightly-cpu
+      if: branch = nightly
+      # Use previously defined before_install
+      before_install: *before_install
+      install:
+        # Merge master into nightly
+        - git fetch origin master
+        - git merge FETCH_HEAD --no-edit
+        # Copy "nightly" files
+        - cp nightly/setup_nightly.py setup.py
+        - cp -R nightly/conda.recipe .
+        # Push to nightly branch
+        - git remote rm origin && git remote add origin https://$GITHUB_TOKEN@github.com/${TRAVIS_REPO_SLUG}.git
+        - git push origin nightly
+      script: true
+      after_success: # Nothing to do
+      before_deploy:
+        # Conda deploy if on tag
+        # ANACONDA_TOKEN should be provided by Travis
+        # How to generate ANACONDA_TOKEN: https://docs.anaconda.com/anaconda-cloud/user-guide/tasks/work-with-accounts#creating-access-tokens
+        # https://conda.io/docs/user-guide/tasks/build-packages/install-conda-build.html
+        - conda install -y conda-build conda-verify anaconda-client
+        - conda config --set anaconda_upload no
+        - conda build --quiet --no-test --output-folder conda_build conda.recipe -c pytorch
+        # Convert to other platforms: OSX, WIN
+        - conda convert --platform win-64 conda_build/linux-64/*.tar.bz2 -o conda_build/
+        - conda convert --platform osx-64 conda_build/linux-64/*.tar.bz2 -o conda_build/
+        # Upload to Anaconda
+        # We could use --all but too much platforms to uploaded
+# Uncomment when a package is available
+#        - ls conda_build/*/*.tar.bz2 | xargs -I {} anaconda -v -t $ANACONDA_TOKEN upload -u pytorch {}
+        - ls conda_build/*/*.tar.bz2 | xargs -I {} anaconda -v -t $ANACONDA_TOKEN upload {}
+      # PyPI Deployment: https://docs.travis-ci.com/user/deployment/pypi/
+      deploy:
+        provider: pypi
+        user: $PYPI_USER
+        # If password contains non alphanumeric characters
+        # https://github.com/travis-ci/dpl/issues/377
+        # pass it as secured variable
+        password: $PYPI_TOKEN
+        # otherwise, follow "How to encrypt the password": https://docs.travis-ci.com/user/encryption-keys/
+        # `travis encrypt deploy.password="password"`
+        #  secure: "secured_password"
+        skip_cleanup: true
+        distributions: "sdist bdist_wheel"
+        on:
+          branch: nightly
diff --git a/docs/source/metrics.rst b/docs/source/metrics.rst
index b1af9c64..4d8defa7 100644
--- a/docs/source/metrics.rst
+++ b/docs/source/metrics.rst
@@ -37,6 +37,21 @@ use the `output_transform` argument to transform it:
         metric = Accuracy(output_transform=output_transform)
         metric.attach(engine, "accuracy")
 
+Metrics could be combined together to form a new metric through arithmetics,
+for example:
+
+    .. code-block:: python
+
+        precision = Precision(average=False)
+        recall = Recall(average=False)
+        F1 = precision * recall * 2 / (precision + recall)
+
+    .. note::  This example computes F1 for each class separately, rather than
+        the mean of F1 across class. To combine precision and recall to get
+        F1 or other F metrics, we have to be careful that `average=False`, i.e.
+        to use the unaveraged precision and recall, otherwise we will not be
+        computing F metrics.
+
 
 .. currentmodule:: ignite.metrics
 
diff --git a/ignite/handlers/checkpoint.py b/ignite/handlers/checkpoint.py
index 4e68a4e1..57ea8bd0 100644
--- a/ignite/handlers/checkpoint.py
+++ b/ignite/handlers/checkpoint.py
@@ -83,7 +83,7 @@ class ModelCheckpoint(object):
                  create_dir=True,
                  save_as_state_dict=False):
 
-        self._dirname = dirname
+        self._dirname = os.path.expanduser(dirname)
         self._fname_prefix = filename_prefix
         self._n_saved = n_saved
         self._save_interval = save_interval
diff --git a/ignite/metrics/metric.py b/ignite/metrics/metric.py
index 1f367029..0afc8b08 100644
--- a/ignite/metrics/metric.py
+++ b/ignite/metrics/metric.py
@@ -73,3 +73,35 @@ class Metric(with_metaclass(ABCMeta, object)):
             engine.add_event_handler(Events.EPOCH_STARTED, self.started)
         if not engine.has_event_handler(self.iteration_completed, Events.ITERATION_COMPLETED):
             engine.add_event_handler(Events.ITERATION_COMPLETED, self.iteration_completed)
+
+    def __add__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x + y, self, other)
+
+    def __sub__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x - y, self, other)
+
+    def __mul__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x * y, self, other)
+
+    def __pow__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x ** y, self, other)
+
+    def __mod__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x % y, self, other)
+
+    def __div__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x.__div__(y), self, other)
+
+    def __truediv__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x.__truediv__(y), self, other)
+
+    def __floordiv__(self, other):
+        from ignite.metrics import MetricsLambda
+        return MetricsLambda(lambda x, y: x // y, self, other)

Master branch nightly build depending on torch_nightly
We need a build of ignite to allow people try nightly version of PyTorch together with ignite. Since the PyTorch is nightly built, it might be better to call this package `pytorch-ignite-nightly` which is also a nightly build of master branch, but with the dependencies on `torch` changed to `torch_nightly`.

cc: @vfdev-5 

NB: I'm not sure the dependency should be `torch_nightly` or `torch-nightly`, because the install command has `torch_nightly` but the output of pip says `torch-nightly`:
```
gaoxiang@pc ~ $ sudo pip install torch_nightly -f https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html
Looking in links: https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html
Collecting torch_nightly
  Downloading https://download.pytorch.org/whl/nightly/cpu/torch_nightly-1.0.0.dev20181029-cp37-cp37m-linux_x86_64.whl (85.9MB)
    100% |████████████████████████████████| 85.9MB 698kB/s 
Installing collected packages: torch-nightly
Successfully installed torch-nightly-1.0.0.dev20181029
```
@soumith Do you think we should change these two names to make them consistent?
diff --git a/tests/ignite/metrics/test_metric.py b/tests/ignite/metrics/test_metric.py
index 371f2581..3fe3b80a 100644
--- a/tests/ignite/metrics/test_metric.py
+++ b/tests/ignite/metrics/test_metric.py
@@ -1,8 +1,12 @@
-from ignite.metrics import Metric
+import sys
+from ignite.metrics import Metric, Precision, Recall
 from ignite.engine import Engine, State
 import torch
 from mock import MagicMock
-from pytest import raises
+
+from pytest import approx, raises
+import numpy as np
+from sklearn.metrics import precision_score, recall_score, f1_score
 
 
 def test_no_transform():
@@ -72,6 +76,133 @@ def test_no_grad():
     metric.iteration_completed(engine)
 
 
+def test_arithmetics():
+    class ListGatherMetric(Metric):
+
+        def __init__(self, index):
+            self.index = index
+            super(ListGatherMetric, self).__init__()
+
+        def reset(self):
+            self.list_ = []
+
+        def update(self, output):
+            self.list_ = output
+
+        def compute(self):
+            print(self.index)
+            return self.list_[self.index]
+
+    m0 = ListGatherMetric(0)
+    m1 = ListGatherMetric(1)
+    m2 = ListGatherMetric(2)
+
+    # __add__
+    m0_plus_m1 = m0 + m1
+    m0.update([1, 10, 100])
+    m1.update([1, 10, 100])
+    assert m0_plus_m1.compute() == 11
+    m0.update([2, 20, 200])
+    m1.update([2, 20, 200])
+    assert m0_plus_m1.compute() == 22
+
+    m2_plus_2 = m2 + 2
+    m2.update([1, 10, 100])
+    assert m2_plus_2.compute() == 102
+
+    # __sub__
+    m0_minus_m1 = m0 - m1
+    m0.update([1, 10, 100])
+    m1.update([1, 10, 100])
+    assert m0_minus_m1.compute() == -9
+    m0.update([2, 20, 200])
+    m1.update([2, 20, 200])
+    assert m0_minus_m1.compute() == -18
+
+    m2_minus_2 = m2 - 2
+    m2.update([1, 10, 100])
+    assert m2_minus_2.compute() == 98
+
+    # __mul__
+    m0_times_m1 = m0 * m1
+    m0.update([1, 10, 100])
+    m1.update([1, 10, 100])
+    assert m0_times_m1.compute() == 10
+    m0.update([2, 20, 200])
+    m1.update([2, 20, 200])
+    assert m0_times_m1.compute() == 40
+
+    m2_times_2 = m2 * 2
+    m2.update([1, 10, 100])
+    assert m2_times_2.compute() == 200
+
+    # __pow__
+    m0_pow_m1 = m0 ** m1
+    m0.update([1, 10, 100])
+    m1.update([1, 10, 100])
+    assert m0_pow_m1.compute() == 1
+    m0.update([2, 20, 200])
+    m1.update([2, 20, 200])
+    assert m0_pow_m1.compute() == 2 ** 20
+
+    m2_pow_2 = m2 ** 2
+    m2.update([1, 10, 100])
+    assert m2_pow_2.compute() == 10000
+
+    # __mod__
+    m0_mod_m1 = m0 % m1
+    m0.update([1, 10, 100])
+    m1.update([1, 10, 100])
+    assert m0_mod_m1.compute() == 1
+    m0.update([2, 20, 200])
+    m1.update([2, 20, 200])
+    assert m0_mod_m1.compute() == 2
+
+    m2_mod_2 = m2 % 2
+    m2.update([1, 10, 100])
+    assert m2_mod_2.compute() == 0
+
+    # __div__, only applicable to python2
+    if sys.version_info[0] < 3:
+        m0_div_m1 = m0.__div__(m1)
+        m0.update([1, 10, 100])
+        m1.update([1, 10, 100])
+        assert m0_div_m1.compute() == 0
+        m0.update([2, 20, 200])
+        m1.update([2, 20, 200])
+        assert m0_div_m1.compute() == 0
+
+        m2_div_2 = m2.__div__(2)
+        m2.update([1, 10, 100])
+        assert m2_div_2.compute() == 50
+
+    # __truediv__
+    m0_truediv_m1 = m0.__truediv__(m1)
+    m0.update([1, 10, 100])
+    m1.update([1, 10, 100])
+    assert m0_truediv_m1.compute() == approx(0.1)
+    m0.update([2, 20, 200])
+    m1.update([2, 20, 200])
+    assert m0_truediv_m1.compute() == approx(0.1)
+
+    m2_truediv_2 = m2.__truediv__(2)
+    m2.update([1, 10, 100])
+    assert m2_truediv_2.compute() == approx(50.0)
+
+    # __floordiv__
+    m0_floordiv_m1 = m0 // m1
+    m0.update([1, 10, 100])
+    m1.update([1, 10, 100])
+    assert m0_floordiv_m1.compute() == 0
+    m0.update([2, 20, 200])
+    m1.update([2, 20, 200])
+    assert m0_floordiv_m1.compute() == 0
+
+    m2_floordiv_2 = m2 // 2
+    m2.update([1, 10, 100])
+    assert m2_floordiv_2.compute() == 50
+
+
 def test_attach():
     class CountMetric(Metric):
         def __init__(self, value):
@@ -116,6 +247,56 @@ def test_attach():
     assert m2.update_count == 50
 
 
+def test_integration():
+    np.random.seed(1)
+
+    n_iters = 10
+    batch_size = 10
+    n_classes = 10
+
+    y_true = np.arange(0, n_iters * batch_size) % n_classes
+    y_pred = 0.2 * np.random.rand(n_iters * batch_size, n_classes)
+    for i in range(n_iters * batch_size):
+        if np.random.rand() > 0.4:
+            y_pred[i, y_true[i]] = 1.0
+        else:
+            j = np.random.randint(0, n_classes)
+            y_pred[i, j] = 0.7
+
+    y_true_batch_values = iter(y_true.reshape(n_iters, batch_size))
+    y_pred_batch_values = iter(y_pred.reshape(n_iters, batch_size, n_classes))
+
+    def update_fn(engine, batch):
+        y_true_batch = next(y_true_batch_values)
+        y_pred_batch = next(y_pred_batch_values)
+        return torch.from_numpy(y_pred_batch), torch.from_numpy(y_true_batch)
+
+    evaluator = Engine(update_fn)
+
+    precision = Precision(average=False)
+    recall = Recall(average=False)
+    F1 = precision * recall * 2 / (precision + recall)
+
+    precision.attach(evaluator, "precision")
+    recall.attach(evaluator, "recall")
+    F1.attach(evaluator, "f1")
+
+    data = list(range(n_iters))
+    state = evaluator.run(data, max_epochs=1)
+
+    precision_true = precision_score(y_true, np.argmax(y_pred, axis=-1), average=None)
+    recall_true = recall_score(y_true, np.argmax(y_pred, axis=-1), average=None)
+    f1_true = f1_score(y_true, np.argmax(y_pred, axis=-1), average=None)
+
+    precision = state.metrics['precision'].numpy()
+    recall = state.metrics['recall'].numpy()
+    f1 = state.metrics['f1'].numpy()
+
+    assert precision_true == approx(precision), "{} vs {}".format(precision_true, precision)
+    assert recall_true == approx(recall), "{} vs {}".format(recall_true, recall)
+    assert f1_true == approx(f1), "{} vs {}".format(f1_true, f1)
+
+
 def test_abstract_class():
     with raises(TypeError):
         Metric()

pip install -e .
parse_log_pytest
pytest
numpy mock pytest codecov pytest-cov tqdm scikit-learn visdom torchvision tensorboardX gym
apt-get update apt-get install -y gcc
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
charset-normalizer==2.0.12
cloudpickle==2.2.1
codecov==2.1.13
coverage==6.2
dataclasses==0.8
decorator==4.4.2
gym==0.26.2
gym-notices==0.0.8
idna==3.10
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
importlib-resources==5.4.0
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
joblib==1.1.1
jsonpatch==1.32
jsonpointer==2.3
mock==5.2.0
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
networkx==2.5.1
numpy==1.19.5
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
Pillow==8.4.0
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
protobuf==4.21.0
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
pytest-cov==4.0.0
-e git+https://github.com/pytorch/ignite.git@11928a3b02eacaed1f312c225434195adf9e5082#egg=pytorch_ignite
requests==2.27.1
scikit-learn==0.24.2
scipy==1.5.4
six==1.17.0
tensorboardX==2.6.2.2
threadpoolctl==3.1.0
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
tomli==1.2.3
torch==1.10.1
torchvision==0.11.2
tornado==6.1
tqdm==4.64.1
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
urllib3==1.26.20
visdom==0.2.4
websocket-client==1.3.1
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: ignite
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - charset-normalizer==2.0.12
      - cloudpickle==2.2.1
      - codecov==2.1.13
      - coverage==6.2
      - dataclasses==0.8
      - decorator==4.4.2
      - gym==0.26.2
      - gym-notices==0.0.8
      - idna==3.10
      - importlib-resources==5.4.0
      - joblib==1.1.1
      - jsonpatch==1.32
      - jsonpointer==2.3
      - mock==5.2.0
      - networkx==2.5.1
      - numpy==1.19.5
      - pillow==8.4.0
      - protobuf==4.21.0
      - pytest-cov==4.0.0
      - requests==2.27.1
      - scikit-learn==0.24.2
      - scipy==1.5.4
      - six==1.17.0
      - tensorboardx==2.6.2.2
      - threadpoolctl==3.1.0
      - tomli==1.2.3
      - torch==1.10.1
      - torchvision==0.11.2
      - tornado==6.1
      - tqdm==4.64.1
      - urllib3==1.26.20
      - visdom==0.2.4
      - websocket-client==1.3.1
prefix: /opt/conda/envs/ignite

tests/ignite/metrics/test_metric.py::test_arithmetics tests/ignite/metrics/test_metric.py::test_integration
tests/ignite/metrics/test_metric.py::test_no_transform tests/ignite/metrics/test_metric.py::test_transform tests/ignite/metrics/test_metric.py::test_no_grad tests/ignite/metrics/test_metric.py::test_attach tests/ignite/metrics/test_metric.py::test_abstract_class
docs/source/metrics.rst .travis.yml ignite/handlers/checkpoint.py ignite/metrics/metric.py
docs/source/metrics.rst .travis.yml ignite/handlers/checkpoint.py ignite/metrics/metric.py