diff --git a/.gitignore b/.gitignore index a9f548a..1224cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,9 @@ pip-wheel-metadata # VS Code .vscode +# Emacs - projectile +TAGS + # default pytest cache directory */.pytest_cache .pytest_cache/ diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..0f83864 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/einsteinpy.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/einsteinpy.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/einsteinpy" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/einsteinpy" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/src/riccipy/__init__.py b/src/riccipy/__init__.py index 589f1e6..19b1913 100644 --- a/src/riccipy/__init__.py +++ b/src/riccipy/__init__.py @@ -1,5 +1,4 @@ """ -======= RicciPy ======= diff --git a/src/riccipy/metric.py b/src/riccipy/metric.py index 904bae6..6899f1e 100644 --- a/src/riccipy/metric.py +++ b/src/riccipy/metric.py @@ -4,7 +4,7 @@ from sympy.tensor.tensor import TensorIndexType from .partial import PartialDerivative -from .tensor import AbstractTensor, ReplacementManager, Tensor, expand_tensor, indices +from .tensor import AbstractTensor, ReplacementManager, Tensor, expand_array, indices class Metric(AbstractTensor, TensorIndexType): @@ -41,13 +41,13 @@ def __new__(cls, symbol, coords, matrix, **kwargs): Examples -------- >>> from sympy import diag, symbols - >>> from einsteinpy.symbolic.tensor import indices, expand_tensor + >>> from einsteinpy.symbolic.tensor import indices, expand_array >>> from einsteinpy.symbolic.metric import Metric >>> t, x, y, z = symbols('t x y z') >>> eta = Metric('eta', [t, x, y, z], diag(1, -1, -1, -1)) >>> mu, nu = indices('mu nu', eta) >>> expr = eta(mu, nu) * eta(-mu, -nu) - >>> expand_tensor(expr) + >>> expand_array(expr) 4 """ @@ -106,7 +106,7 @@ def christoffel(self): * g(si, rh) * (d(-mu) * g(-nu, -rh) + d(-nu) * g(-rh, -mu) - d(-rh) * g(-mu, -nu)) ) - syms = expand_tensor(gamma, [si, -mu, -nu]) + syms = expand_array(gamma, [si, -mu, -nu]) self._christoffel = Tensor("Gamma", syms, self, covar=(1, -1, -1)) return self._christoffel @@ -130,7 +130,7 @@ def riemann(self): + gamma(rh, -mu, -la) * gamma(la, -nu, -si) - gamma(rh, -nu, -la) * gamma(la, -mu, -si) ) - res = expand_tensor(R, [rh, -si, -mu, -nu]) + res = expand_array(R, [rh, -si, -mu, -nu]) self._riemann = Tensor( "R", res, self, symmetry=[[2, 2]], covar=(1, -1, -1, -1) ) @@ -146,7 +146,7 @@ def ricci_tensor(self): if self._ricci_tensor is None: mu, nu, si = indices("mu nu sigma", self) R = self.riemann - res = expand_tensor(R(si, -mu, -si, -nu), [-mu, -nu]) + res = expand_array(R(si, -mu, -si, -nu), [-mu, -nu]) self._ricci_tensor = Tensor("R", res, self, covar=(-1, -1)) return self._ricci_tensor @@ -160,7 +160,7 @@ def ricci_scalar(self): if self._ricci_scalar is None: mu, nu = indices("mu nu", self) RR = self.ricci_tensor - res = expand_tensor(RR(mu, -mu)) + res = expand_array(RR(mu, -mu)) self._ricci_scalar = res return self._ricci_scalar @@ -205,7 +205,7 @@ def weyl(self): ) + c2 * (g(rh, -mu) * g(-nu, -si) - g(rh, -nu) * g(-mu, -si)) * RRR ) - res = expand_tensor(C, [rh, -si, -mu, -nu]) + res = expand_array(C, [rh, -si, -mu, -nu]) self._weyl = Tensor( "C", res, self, symmetry=[[2, 2]], covar=(1, -1, -1, -1) ) @@ -223,7 +223,7 @@ def einstein(self): g = self.metric R = self.ricci_tensor RR = self.ricci_scalar - res = expand_tensor(R(-mu, -nu) - Rational(1, 2) * RR * g(-mu, -nu)) + res = expand_array(R(-mu, -nu) - Rational(1, 2) * RR * g(-mu, -nu)) self._einstein = Tensor("G", res, self, covar=(-1, -1)) return self._einstein diff --git a/src/riccipy/tensor.py b/src/riccipy/tensor.py index 53a4473..4f9cf7d 100644 --- a/src/riccipy/tensor.py +++ b/src/riccipy/tensor.py @@ -168,7 +168,7 @@ def __new__(cls, symbol, matrix, metric, **kwargs): Examples -------- >>> from sympy import diag, symbols - >>> from einsteinpy.symbolic.tensor import Tensor, indices, expand_tensor + >>> from einsteinpy.symbolic.tensor import Tensor, indices, expand_array >>> from einsteinpy.symbolic.metric import Metric >>> E1, E2, E3, B1, B2, B3 = symbols('E1:4 B1:4') >>> em = [[0, -E1, -E2, -E3], @@ -180,10 +180,10 @@ def __new__(cls, symbol, matrix, metric, **kwargs): >>> F = Tensor('F', em, eta, symmetry=[[2]]) >>> mu, nu = indices('mu nu', eta) >>> expr = F(mu, nu) + F(nu, mu) - >>> expand_tensor(expr) + >>> expand_array(expr) 0 >>> expr = F(mu, nu) * F(-mu, -nu) - >>> expand_tensor(expr) + >>> expand_array(expr) 2*B_1**2 + 2*B_2**2 + 2*B_3**2 - 2*E_1**2 - 2*E_2**2 - 2*E_3**2 """ @@ -292,9 +292,9 @@ def __neg__(self): return Index(self.name, self.tensor_index_type, (not self.is_up)) -def expand_tensor(expr, idxs=None): +def expand_array(expr, idxs=None): """ - Evaluate a tensor expression and return the resulting array. + Evaluate a tensor expression and return the result as an array. Parameters ---------- @@ -309,6 +309,31 @@ def expand_tensor(expr, idxs=None): return expr.replace_with_arrays(ReplacementManager, idxs) +def expand_tensor(symbol, expr, metric, idxs=None, **kwargs): + """ + Evaluate a tensor expression and return the result as a tensor. + + Parameters + ---------- + symbol : str + Name of the tensor and the symbol to denote it by when printed. + expr : TensExpr + Symbolic expression of tensors. + metric : Metric + Classify the tensor as being defined in terms of a metric. + idxs : TensorIndex + Indices that encode the covariance and contravariance of the result. + + """ + result = expand_array(expr, idxs) + if not isinstance(result, Array): + return result + if idxs is None: + idxs = TensMul(expr).get_free_indices() + covar = [1 if idx.is_up else -1 for idx in idxs] + return Tensor(symbol, result, metric, covar=covar, **kwargs) + + def indices(s, metric, is_up=True): """ Create indices using a method similar to ~sympy.symbols. diff --git a/src/riccipy/tests/test_metric.py b/src/riccipy/tests/test_metric.py index 0e243bd..6b84349 100644 --- a/src/riccipy/tests/test_metric.py +++ b/src/riccipy/tests/test_metric.py @@ -1,8 +1,7 @@ -from sympy import Expr, diag, eye, sin, symbols, tensorproduct, zeros - from riccipy.metric import * from riccipy.partial import * from riccipy.tensor import * +from sympy import Expr, diag, eye, sin, symbols, tensorproduct, zeros def _generate_schwarzschild(): @@ -67,13 +66,13 @@ def is_zero(arr): yield comp.equals(0) expr = R(-rh, -si, -mu, -nu) + R(-si, -rh, -mu, -nu) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) expr = R(-rh, -si, -mu, -nu) + R(-rh, -si, -nu, -mu) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) expr = R(-rh, -si, -mu, -nu) - R(-mu, -nu, -rh, -si) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) expr = R(-rh, -si, -mu, -nu) + R(-rh, -mu, -nu, -si) + R(-rh, -nu, -si, -mu) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) def test_Metric_ricci_tensor(): @@ -110,10 +109,10 @@ def is_zero(arr): yield comp.equals(0) expr = C(-rh, -si, -mu, -nu) + C(-si, -rh, -mu, -nu) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) expr = C(-rh, -si, -mu, -nu) + C(-rh, -si, -nu, -mu) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) expr = C(-rh, -si, -mu, -nu) - C(-mu, -nu, -rh, -si) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) expr = C(-rh, -si, -mu, -nu) + C(-rh, -mu, -nu, -si) + C(-rh, -nu, -si, -mu) - assert all(is_zero(expand_tensor(expr))) + assert all(is_zero(expand_array(expr))) diff --git a/src/riccipy/tests/test_partial.py b/src/riccipy/tests/test_partial.py index 6b1402b..31b2149 100644 --- a/src/riccipy/tests/test_partial.py +++ b/src/riccipy/tests/test_partial.py @@ -1,8 +1,7 @@ -from sympy import diag, sin, symbols - from riccipy.metric import * from riccipy.partial import * from riccipy.tensor import * +from sympy import diag, sin, symbols def _generate_schwarzschild(): diff --git a/src/riccipy/tests/test_tensor.py b/src/riccipy/tests/test_tensor.py index ab68c7e..080bd9a 100644 --- a/src/riccipy/tests/test_tensor.py +++ b/src/riccipy/tests/test_tensor.py @@ -1,8 +1,7 @@ -from sympy import Array, diag, eye, simplify, sin, symbols -from sympy.tensor.tensor import TensExpr, TensMul - from riccipy.metric import * from riccipy.tensor import * +from sympy import Array, diag, eye, simplify, sin, symbols +from sympy.tensor.tensor import TensExpr, TensMul def _generate_simple(): @@ -107,15 +106,15 @@ def test_ReplacementManager(): pass -def test_expand_tensor(): +def test_expand_array(): (coords, t, r, th, ph, mink, eta, mu, nu) = _generate_minkowski() E1, E2, E3, B1, B2, B3 = symbols("E_1:4 B_1:4", real=True) matrix = [[0, -E1, -E2, -E3], [E1, 0, -B3, B2], [E2, B3, 0, -B1], [E3, -B2, B1, 0]] F = Tensor("F", matrix, eta, symmetry=[[2]]) - assert expand_tensor(eta(mu, nu) * eta(-mu, -nu)) == 4 - assert expand_tensor(F(mu, -mu)) == 0 + assert expand_array(eta(mu, nu) * eta(-mu, -nu)) == 4 + assert expand_array(F(mu, -mu)) == 0 assert ( - expand_tensor(F(mu, nu) * F(-mu, -nu)) + expand_array(F(mu, nu) * F(-mu, -nu)) == 2 * B1 ** 2 + 2 * B2 ** 2 + 2 * B3 ** 2 @@ -125,21 +124,21 @@ def test_expand_tensor(): ) (coords, t, r, th, ph, schw, g, mu, nu) = _generate_schwarzschild() x = Tensor("x", [t, r, th, ph], g) - res = expand_tensor(g(mu, nu)) + res = expand_array(g(mu, nu)) assert schw.inv().equals(res) - res1 = expand_tensor(g(mu, nu) * g(-mu, -nu)) - res2 = expand_tensor(g(-mu, -nu) * g(mu, nu)) + res1 = expand_array(g(mu, nu) * g(-mu, -nu)) + res2 = expand_array(g(-mu, -nu) * g(mu, nu)) assert res1 == res2 assert simplify(res1) == 4 - res1 = expand_tensor(g(-mu, -nu) * x(nu)) - res2 = expand_tensor(x(-mu)) + res1 = expand_array(g(-mu, -nu) * x(nu)) + res2 = expand_array(x(-mu)) res3 = x.covariance_transform(-mu) assert res1 == res2 assert res2 == res3 - res1 = expand_tensor(g(mu, nu) * x(-nu)) - res2 = expand_tensor(x(mu)) + res1 = expand_array(g(mu, nu) * x(-nu)) + res2 = expand_array(x(mu)) assert simplify(res1) == res2 - res = expand_tensor(x(mu) * x(-mu)) + res = expand_array(x(mu) * x(-mu)) assert ( res == t ** 2 * (1 - 1 / r) @@ -147,3 +146,12 @@ def test_expand_tensor(): - th ** 2 * r ** 2 - ph ** 2 * r ** 2 * sin(th) ** 2 ) + + +def test_expand_tensor(): + (coords, t, r, th, ph, schw, g, mu, nu) = _generate_schwarzschild() + res = expand_tensor("t", g(-mu, -nu) * g(mu, nu), g) + assert not isinstance(res, TensExpr) + res = expand_tensor("T", g(mu, nu), g) + assert isinstance(res, Tensor) + assert schw.inv().equals(res.as_array()) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..43fc3f0 --- /dev/null +++ b/tox.ini @@ -0,0 +1,73 @@ +[tox] +description = list of environments againts tox runs the tests +envlist = + clean, + check, + docs, + py35, + py36 + py37 + pypy, + pypy3 + +[testenv] +basepython = + pypy: {env:PYTHON:pypy} + pypy3: {env:PYTHON:pypy3} + py35: {env:PYTHON:python3.5} + {py36,docs}: {env:PYTHON:python3.6} + py37: {env:PYTHON:python3.7} + {clean,check,reformat}: {env:PYTHON:python3} +setenv = + PYTHONPATH={toxinidir}/tests + PYTHONUNBUFFERED=yes +passenv = + * +usedevelop = false +deps = + pytest-cov + ipywidgets +skip_install = false +commands = + {posargs:pytest --cov --cov-report=term-missing -vv src/einsteinpy/tests} + + +[testenv:check] +description = this environments checks for flake8, black, isort and einsteinpy code style +deps = + black + docutils + isort + flake8 + mypy + pygments +skip_install = true +commands = + python setup.py check --strict --metadata --restructuredtext + flake8 src setup.py + isort --check-only --diff --recursive --project einsteinpy --section-default THIRDPARTY src setup.py + black --check src setup.py + mypy --ignore-missing-imports --check-untyped-defs --no-strict-optional src + + +[testenv:reformat] +description = reformats the code using black and isort +deps = + black + isort +skip_install = true +commands = + isort --recursive --project einsteinpy --section-default THIRDPARTY src setup.py + black src setup.py + + +[testenv:docs] +description = invoke sphinx-build to build the HTML docs +extras = docs +whitelist_externals = sphinx-build +commands = sphinx-build -d "{toxworkdir}/docs_doctree" docs/source "{toxworkdir}/docs_out" --color -W -bhtml + +[testenv:clean] +commands = coverage erase +skip_install = true +deps = coverage